VOL-419: Flows not passed to Device Adapter if more than one PON Port
Changed flow to use requested priority per Nokia comment
Change-Id: I1ba954d56dbb65e4773b35a9df4a424458df4263
diff --git a/tests/utests/voltha/core/test_flow_decomposer.py b/tests/utests/voltha/core/test_flow_decomposer.py
index 6d6b5d5..5da4bc7 100644
--- a/tests/utests/voltha/core/test_flow_decomposer.py
+++ b/tests/utests/voltha/core/test_flow_decomposer.py
@@ -66,6 +66,11 @@
4: LogicalPort(id='4', device_id='onu4', device_port_no=2),
}
+ def get_wildcard_input_ports(self, exclude_port=None):
+ logical_ports = self._logical_ports.iterkeys()
+ return [port_no for port_no in logical_ports
+ if port_no != exclude_port]
+
_routes = {
# DOWNSTREAM ROUTES
@@ -193,22 +198,6 @@
}
_default_rules = {
- 'olt': (
- OrderedDict((f.id, f) for f in [
- mk_flow_stat(
- match_fields=[
- in_port(2),
- vlan_vid(ofp.OFPVID_PRESENT | 4000),
- vlan_pcp(0)
- ],
- actions=[
- pop_vlan(),
- output(1)
- ]
- )
- ]),
- OrderedDict()
- ),
'onu1': (
OrderedDict((f.id, f) for f in [
mk_flow_stat(
@@ -315,10 +304,11 @@
output(1)
]
))
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=1000,
match_fields=[
in_port(1),
+ vlan_vid(ofp.OFPVID_PRESENT | 1),
eth_type(0x888e)
],
actions=[
@@ -327,6 +317,19 @@
output(2)
]
))
+ self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ priority=1000,
+ match_fields=[
+ in_port(2),
+ vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0),
+ metadata(1)
+ ],
+ actions=[
+ pop_vlan(),
+ output(1)
+ ]
+ ))
def test_dhcp_reroute_rule_decomposition(self):
flow = mk_flow_stat(
@@ -359,10 +362,11 @@
output(1)
]
))
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=1000,
match_fields=[
in_port(1),
+ vlan_vid(ofp.OFPVID_PRESENT | 1),
eth_type(0x0800),
ipv4_dst(0xffffffff),
ip_proto(17),
@@ -375,6 +379,19 @@
output(2)
]
))
+ self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ priority=1000,
+ match_fields=[
+ in_port(2),
+ vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0),
+ metadata(1)
+ ],
+ actions=[
+ pop_vlan(),
+ output(1)
+ ]
+ ))
def test_igmp_reroute_rule_decomposition(self):
flow = mk_flow_stat(
@@ -404,10 +421,11 @@
output(1)
]
))
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=1000,
match_fields=[
in_port(1),
+ vlan_vid(ofp.OFPVID_PRESENT | 1),
eth_type(0x0800),
ip_proto(2)
],
@@ -417,6 +435,19 @@
output(2)
]
))
+ self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ priority=1000,
+ match_fields=[
+ in_port(2),
+ vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0),
+ metadata(1)
+ ],
+ actions=[
+ pop_vlan(),
+ output(1)
+ ]
+ ))
def test_wildcarded_igmp_reroute_rule_decomposition(self):
flow = mk_flow_stat(
@@ -433,25 +464,23 @@
olt_flows, olt_groups = device_rules['olt']
self.assertEqual(len(onu1_flows), 1)
self.assertEqual(len(onu1_groups), 0)
- self.assertEqual(len(olt_flows), 2)
+ self.assertEqual(len(olt_flows), 8)
self.assertEqual(len(olt_groups), 0)
self.assertFlowsEqual(onu1_flows.values()[0], mk_flow_stat(
match_fields=[
- in_port(2),
- vlan_vid(ofp.OFPVID_PRESENT | 0),
+ in_port(2), vlan_vid(ofp.OFPVID_PRESENT | 0)
],
actions=[
set_field(vlan_vid(ofp.OFPVID_PRESENT | 101)),
output(1)
]
))
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=2000,
cookie=140,
match_fields=[
- in_port(1),
- eth_type(0x0800),
- ip_proto(2)
+ in_port(1), vlan_vid(ofp.OFPVID_PRESENT | 0),
+ eth_type(0x0800), ip_proto(2)
],
actions=[
push_vlan(0x8100),
@@ -459,6 +488,85 @@
output(2)
]
))
+ self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ priority=2000,
+ match_fields=[
+ in_port(2), vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0), metadata(0)
+ ],
+ actions=[
+ pop_vlan(), output(1)
+ ]
+ ))
+ self.assertFlowsEqual(olt_flows.values()[2], mk_flow_stat(
+ priority=2000,
+ cookie=140,
+ match_fields=[
+ in_port(1), vlan_vid(ofp.OFPVID_PRESENT | 1),
+ eth_type(0x0800), ip_proto(2)
+ ],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(ofp.OFPVID_PRESENT | 4000)),
+ output(2)
+ ]
+ ))
+ self.assertFlowsEqual(olt_flows.values()[3], mk_flow_stat(
+ priority=2000,
+ match_fields=[
+ in_port(2), vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0), metadata(1)
+ ],
+ actions=[
+ pop_vlan(), output(1)
+ ]
+ ))
+ self.assertFlowsEqual(olt_flows.values()[4], mk_flow_stat(
+ priority=2000,
+ cookie=140,
+ match_fields=[
+ in_port(1), vlan_vid(ofp.OFPVID_PRESENT | 3),
+ eth_type(0x0800), ip_proto(2)
+ ],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(ofp.OFPVID_PRESENT | 4000)),
+ output(2)
+ ]
+ ))
+ self.assertFlowsEqual(olt_flows.values()[5], mk_flow_stat(
+ priority=2000,
+ match_fields=[
+ in_port(2), vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0), metadata(3)
+ ],
+ actions=[
+ pop_vlan(), output(1)
+ ]
+ ))
+ self.assertFlowsEqual(olt_flows.values()[6], mk_flow_stat(
+ priority=2000,
+ cookie=140,
+ match_fields=[
+ in_port(1), vlan_vid(ofp.OFPVID_PRESENT | 4),
+ eth_type(0x0800), ip_proto(2)
+ ],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(ofp.OFPVID_PRESENT | 4000)),
+ output(2)
+ ]
+ ))
+ self.assertFlowsEqual(olt_flows.values()[7], mk_flow_stat(
+ priority=2000,
+ match_fields=[
+ in_port(2), vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0), metadata(4)
+ ],
+ actions=[
+ pop_vlan(), output(1)
+ ]
+ ))
def test_unicast_upstream_rule_decomposition(self):
flow1 = mk_flow_stat(
@@ -492,7 +600,7 @@
olt_flows, olt_groups = device_rules['olt']
self.assertEqual(len(onu1_flows), 2)
self.assertEqual(len(onu1_groups), 0)
- self.assertEqual(len(olt_flows), 2)
+ self.assertEqual(len(olt_flows), 1)
self.assertEqual(len(olt_groups), 0)
self.assertFlowsEqual(onu1_flows.values()[1], mk_flow_stat(
priority=500,
@@ -506,7 +614,7 @@
output(1)
]
))
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=500,
match_fields=[
in_port(1),
@@ -551,9 +659,9 @@
olt_flows, olt_groups = device_rules['olt']
self.assertEqual(len(onu1_flows), 2)
self.assertEqual(len(onu1_groups), 0)
- self.assertEqual(len(olt_flows), 2)
+ self.assertEqual(len(olt_flows), 1)
self.assertEqual(len(olt_groups), 0)
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=500,
match_fields=[
in_port(2),
@@ -606,9 +714,9 @@
olt_flows, olt_groups = device_rules['olt']
self.assertEqual(len(onu1_flows), 2)
self.assertEqual(len(onu1_groups), 0)
- self.assertEqual(len(olt_flows), 2)
+ self.assertEqual(len(olt_flows), 1)
self.assertEqual(len(olt_groups), 0)
- self.assertFlowsEqual(olt_flows.values()[1], mk_flow_stat(
+ self.assertFlowsEqual(olt_flows.values()[0], mk_flow_stat(
priority=500,
match_fields=[
in_port(2),
diff --git a/tests/utests/voltha/core/test_logical_device_agent.py b/tests/utests/voltha/core/test_logical_device_agent.py
index 42ced6f..aa374c6 100644
--- a/tests/utests/voltha/core/test_logical_device_agent.py
+++ b/tests/utests/voltha/core/test_logical_device_agent.py
@@ -374,8 +374,8 @@
def test_default_rules(self):
rules = self.lda.get_all_default_rules()
- # we assume one default flow and no default group for each of 3 devs
- self.assertEqual(len(rules['olt'][0]), 1)
+ # no default olt downstream and no default group for each of 3 devs
+ self.assertEqual(len(rules['olt'][0]), 0)
self.assertEqual(len(rules['olt'][1]), 0)
self.assertEqual(len(rules['onu1'][0]), 3)
self.assertEqual(len(rules['onu1'][1]), 0)
@@ -442,16 +442,23 @@
self.assertEqual(len(self.device_groups['onu1'].items), 0)
self.assertEqual(len(self.device_groups['onu2'].items), 0)
- # the only non-default flow (check without the id field)
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), vlan_vid(4096 + 1), eth_type(0x888e)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 4000)),
+ output(0)
+ ]
+ ))
self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
- priority=1000,
- match_fields=[in_port(1), eth_type(0x888e)],
- actions=[
- push_vlan(0x8100),
- set_field(vlan_vid(4096 + 4000)),
- output(0)
- ]
- ))
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(1)],
+ actions=[
+ pop_vlan(),
+ output(1)
+ ]
+ ))
def test_wildcarded_igmp_rule(self):
self.lda.update_flow_table(mk_simple_flow_mod(
@@ -461,23 +468,47 @@
))
self.lda._flow_table_updated(self.flows)
- self.assertEqual(len(self.device_flows['olt'].items), 2)
+ self.assertEqual(len(self.device_flows['olt'].items), 4)
self.assertEqual(len(self.device_flows['onu1'].items), 3)
self.assertEqual(len(self.device_flows['onu2'].items), 3)
self.assertEqual(len(self.device_groups['olt'].items), 0)
self.assertEqual(len(self.device_groups['onu1'].items), 0)
self.assertEqual(len(self.device_groups['onu2'].items), 0)
- # the only non-default flow
- self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
priority=1000,
- match_fields=[in_port(1), eth_type(0x800), ip_proto(2)],
+ match_fields=[in_port(1), vlan_vid(4096 + 1), eth_type(0x800), ip_proto(2)],
actions=[
push_vlan(0x8100),
set_field(vlan_vid(4096 + 4000)),
output(0)
]
))
+ self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(1)],
+ actions=[
+ pop_vlan(),
+ output(1)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[2], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), vlan_vid(4096 + 2), eth_type(0x800), ip_proto(2)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 4000)),
+ output(0)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[3], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(2)],
+ actions=[
+ pop_vlan(),
+ output(1)
+ ]
+ ))
def test_multicast_group_with_one_subscriber(self):
self.lda.update_group_table(mk_multicast_group_mod(
@@ -500,14 +531,14 @@
actions=[group(2)]
))
self.lda._flow_table_updated(self.flows)
- self.assertEqual(len(self.device_flows['olt'].items), 2)
+ self.assertEqual(len(self.device_flows['olt'].items), 1)
self.assertEqual(len(self.device_flows['onu1'].items), 4)
self.assertEqual(len(self.device_flows['onu2'].items), 3)
self.assertEqual(len(self.device_groups['olt'].items), 0)
self.assertEqual(len(self.device_groups['onu1'].items), 0)
self.assertEqual(len(self.device_groups['onu2'].items), 0)
- self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
priority=1000,
match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
ipv4_dst(0xe60a0a0a)],
@@ -549,14 +580,14 @@
actions=[group(2)]
))
self.lda._flow_table_updated(self.flows)
- self.assertEqual(len(self.device_flows['olt'].items), 2)
+ self.assertEqual(len(self.device_flows['olt'].items), 1)
self.assertEqual(len(self.device_flows['onu1'].items), 4)
self.assertEqual(len(self.device_flows['onu2'].items), 4)
self.assertEqual(len(self.device_groups['olt'].items), 0)
self.assertEqual(len(self.device_groups['onu1'].items), 0)
self.assertEqual(len(self.device_groups['onu2'].items), 0)
- self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
priority=1000,
match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
ipv4_dst(0xe60a0a0a)],
@@ -596,17 +627,18 @@
actions=[group(2)]
))
self.lda._flow_table_updated(self.flows)
- self.assertEqual(len(self.device_flows['olt'].items), 2)
+ self.assertEqual(len(self.device_flows['olt'].items), 1)
self.assertEqual(len(self.device_flows['onu1'].items), 3)
self.assertEqual(len(self.device_flows['onu2'].items), 3)
+ self.assertEqual(len(self.device_flows['onu2'].items), 3)
self.assertEqual(len(self.device_groups['olt'].items), 0)
self.assertEqual(len(self.device_groups['onu1'].items), 0)
self.assertEqual(len(self.device_groups['onu2'].items), 0)
- self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
priority=1000,
- match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
- ipv4_dst(0xe60a0a0a)],
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe60a0a0a)],
actions=[
pop_vlan(),
output(1)
@@ -724,7 +756,7 @@
self.lda._flow_table_updated(self.flows)
# now check device level flows
- self.assertEqual(len(self.device_flows['olt'].items), 12)
+ self.assertEqual(len(self.device_flows['olt'].items), 16)
self.assertEqual(len(self.device_flows['onu1'].items), 5)
self.assertEqual(len(self.device_flows['onu2'].items), 5)
self.assertEqual(len(self.device_groups['olt'].items), 0)
@@ -734,65 +766,93 @@
# Flows installed on the OLT
self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
priority=2000,
- match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0)],
- actions=[pop_vlan(), output(1)]
- ))
- self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
- priority=2000,
- match_fields=[in_port(1), eth_type(0x888e)],
+ match_fields=[in_port(1), vlan_vid(4096 + 1), eth_type(0x888e)],
actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
output(0)]
))
+ self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ priority=2000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(1)],
+ actions=[pop_vlan(), output(1)]
+ ))
self.assertFlowsEqual(self.device_flows['olt'].items[2], mk_flow_stat(
priority=1000,
- match_fields=[in_port(1), eth_type(0x800), ip_proto(2)],
+ match_fields=[in_port(1), vlan_vid(4096 + 1), eth_type(0x800), ip_proto(2)],
actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
output(0)]
))
self.assertFlowsEqual(self.device_flows['olt'].items[3], mk_flow_stat(
priority=1000,
- match_fields=[in_port(1), eth_type(0x800), ip_proto(17),
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(1)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[4], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), vlan_vid(4096 + 1), eth_type(0x800), ip_proto(17),
udp_src(68), udp_dst(67)],
actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
output(0)]
))
- self.assertFlowsEqual(self.device_flows['olt'].items[4], mk_flow_stat(
- priority=1000,
- match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140), ipv4_dst(0xe4010101)],
- actions=[pop_vlan(), output(1)]
- ))
self.assertFlowsEqual(self.device_flows['olt'].items[5], mk_flow_stat(
- priority=1000,
- match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140), ipv4_dst(0xe4010102)],
- actions=[pop_vlan(), output(1)]
+ priority=2000,
+ match_fields=[in_port(1), vlan_vid(4096 + 2), eth_type(0x888e)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
))
self.assertFlowsEqual(self.device_flows['olt'].items[6], mk_flow_stat(
- priority=1000,
- match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140), ipv4_dst(0xe4010103)],
+ priority=2000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(2)],
actions=[pop_vlan(), output(1)]
))
self.assertFlowsEqual(self.device_flows['olt'].items[7], mk_flow_stat(
priority=1000,
- match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140), ipv4_dst(0xe4010104)],
- actions=[pop_vlan(), output(1)]
+ match_fields=[in_port(1), vlan_vid(4096 + 2), eth_type(0x800), ip_proto(2)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
))
self.assertFlowsEqual(self.device_flows['olt'].items[8], mk_flow_stat(
- priority=500,
- match_fields=[in_port(0), vlan_vid(4096 + 1000), metadata(101)],
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(2)],
actions=[pop_vlan(), output(1)]
))
self.assertFlowsEqual(self.device_flows['olt'].items[9], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), vlan_vid(4096 + 2), eth_type(0x800), ip_proto(17),
+ udp_src(68), udp_dst(67)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[10], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010101)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[11], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010102)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[12], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010103)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[13], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010104)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[14], mk_flow_stat(
priority=500,
match_fields=[in_port(1), vlan_vid(4096 + 101)],
actions=[
push_vlan(0x8100), set_field(vlan_vid(4096 + 1000)), output(0)]
))
- self.assertFlowsEqual(self.device_flows['olt'].items[10], mk_flow_stat(
- priority=500,
- match_fields=[in_port(0), vlan_vid(4096 + 1000), metadata(102)],
- actions=[pop_vlan(), output(1)]
- ))
- self.assertFlowsEqual(self.device_flows['olt'].items[11], mk_flow_stat(
+ self.assertFlowsEqual(self.device_flows['olt'].items[15], mk_flow_stat(
priority=500,
match_fields=[in_port(1), vlan_vid(4096 + 102)],
actions=[
diff --git a/tests/utests/voltha/core/test_multipon_lda.py b/tests/utests/voltha/core/test_multipon_lda.py
new file mode 100644
index 0000000..0561dec
--- /dev/null
+++ b/tests/utests/voltha/core/test_multipon_lda.py
@@ -0,0 +1,652 @@
+
+from unittest import main
+
+from mock import Mock
+
+from tests.utests.voltha.core.flow_helpers import FlowHelpers
+from voltha.core import logical_device_agent
+from voltha.core.flow_decomposer import *
+from voltha.core.logical_device_agent import LogicalDeviceAgent
+from voltha.protos.device_pb2 import Device, Port
+from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
+from voltha.protos.openflow_13_pb2 import Flows, FlowGroups
+
+
+class test_multipon_logical_device_agent(FlowHelpers):
+
+ def setup_mock_registry(self):
+ registry = Mock()
+ logical_device_agent.registry = registry
+
+ def setUp(self):
+ self.setup_mock_registry()
+
+ self.flows = Flows(items=[])
+ self.groups = FlowGroups(items=[])
+ self.ld_ports = [
+ LogicalPort(
+ id='0',
+ device_id='olt',
+ device_port_no=0,
+ root_port=True,
+ ofp_port=ofp.ofp_port(port_no=0)
+ ),
+ LogicalPort(
+ id='101',
+ device_id='onu1',
+ device_port_no=0,
+ ofp_port=ofp.ofp_port(port_no=101)
+ ),
+ LogicalPort(
+ id='201',
+ device_id='onu2',
+ device_port_no=0,
+ ofp_port=ofp.ofp_port(port_no=201)
+ )
+ ]
+
+ self.devices = {
+ 'olt': Device(
+ id='olt', root=True, parent_id='id'),
+ 'onu1': Device(
+ id='onu1', parent_id='olt', parent_port_no=1, vlan=101),
+ 'onu2': Device(
+ id='onu2', parent_id='olt', parent_port_no=2, vlan=201),
+ }
+
+ self.ports = {
+ 'olt': [
+ Port(port_no=0, type=Port.ETHERNET_NNI, device_id='olt'),
+ Port(port_no=1, type=Port.PON_OLT, device_id='olt',
+ peers=[Port.PeerPort(device_id='onu1', port_no=1)]),
+ Port(port_no=2, type=Port.PON_OLT, device_id='olt',
+ peers=[Port.PeerPort(device_id='onu2', port_no=1)])
+ ],
+ 'onu1': [
+ Port(port_no=0, type=Port.ETHERNET_UNI, device_id='onu1'),
+ Port(port_no=1, type=Port.PON_ONU, device_id='onu1',
+ peers=[Port.PeerPort(device_id='olt', port_no=1)])
+ ],
+ 'onu2': [
+ Port(port_no=0, type=Port.ETHERNET_UNI, device_id='onu2'),
+ Port(port_no=1, type=Port.PON_ONU, device_id='onu2',
+ peers=[Port.PeerPort(device_id='olt', port_no=2)])
+ ],
+ }
+
+ self.device_flows = {
+ 'olt': Flows(),
+ 'onu1': Flows(),
+ 'onu2': Flows()
+ }
+
+ self.device_groups = {
+ 'olt': FlowGroups(),
+ 'onu1': FlowGroups(),
+ 'onu2': FlowGroups()
+ }
+
+ self.ld = LogicalDevice(id='id', root_device_id='olt')
+
+ self.root_proxy = Mock()
+ def get_devices(path):
+ if path == '':
+ return self.devices.values()
+ if path.endswith('/ports'):
+ return self.ports[path[:-len('/ports')]]
+ elif path.find('/') == -1:
+ return self.devices[path]
+ else:
+ raise Exception(
+ 'Nothing to yield for path /devices/{}'.format(path))
+ def update_devices(path, data):
+ if path.endswith('/flows'):
+ self.device_flows[path[:-len('/flows')]] = data
+ elif path.endswith('/flow_groups'):
+ self.device_groups[path[:-len('/flow_groups')]] = data
+ else:
+ raise NotImplementedError(
+ 'not handling path /devices/{}'.format(path))
+
+ self.root_proxy.get = lambda p: \
+ get_devices(p[len('/devices/'):]) if p.startswith('/devices') \
+ else None
+ self.root_proxy.update = lambda p, d: \
+ update_devices(p[len('/devices/'):], d) \
+ if p.startswith('/devices') \
+ else None
+ self.ld_proxy = Mock()
+ self.ld_proxy.get = lambda p: \
+ self.ld_ports if p == '/ports' else (
+ self.ld if p == '/' else None
+ )
+
+ self.flows_proxy = Mock()
+ self.flows_proxy.get = lambda _: self.flows # always '/' path
+ def update_flows(_, flows): # always '/' path
+ self.flows = flows
+ self.flows_proxy.update = update_flows
+
+ self.groups_proxy = Mock()
+ self.groups_proxy.get = lambda _: self.groups # always '/' path
+ def update_groups(_, groups): # always '/' path
+ self.groups = groups
+ self.groups_proxy.update = update_groups
+
+ self.core = Mock()
+ self.core.get_proxy = lambda path: \
+ self.root_proxy if path == '/' else (
+ self.ld_proxy if path.endswith('id') else (
+ self.flows_proxy if path.endswith('flows') else
+ self.groups_proxy
+ )
+ )
+
+ self.lda = LogicalDeviceAgent(self.core, self.ld)
+
+ def test_init(self):
+ pass # really just tests the setUp method
+
+ # ~~~~~~~~~~~~~~~~~~~~ DEFAULT RULES AND ROUTES ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ def test_default_rules(self):
+ rules = self.lda.get_all_default_rules()
+ # no default olt downstream and no default group for each of 3 devs
+ self.assertEqual(len(rules['olt'][0]), 0)
+ self.assertEqual(len(rules['olt'][1]), 0)
+ self.assertEqual(len(rules['onu1'][0]), 3)
+ self.assertEqual(len(rules['onu1'][1]), 0)
+ self.assertEqual(len(rules['onu2'][0]), 3)
+ self.assertEqual(len(rules['onu2'][1]), 0)
+
+ def test_routes(self):
+ self.lda.get_all_default_rules() # this will prepare the _routes
+ routes = self.lda._routes
+ self.assertEqual(len(routes), 4)
+ self.assertEqual(set(routes.keys()),
+ set([(0, 101), (0, 201), (101, 0), (201, 0)]))
+
+ # verify all routes
+ route = routes[(0, 101)]
+ self.assertEqual(len(route), 2)
+ self.assertEqual(route[0].device, self.devices['olt'])
+ self.assertEqual(route[0].ingress_port, self.ports['olt'][0])
+ self.assertEqual(route[0].egress_port, self.ports['olt'][1])
+ self.assertEqual(route[1].device, self.devices['onu1'])
+ self.assertEqual(route[1].ingress_port, self.ports['onu1'][1])
+ self.assertEqual(route[1].egress_port, self.ports['onu1'][0])
+
+ route = routes[(0, 201)]
+ self.assertEqual(len(route), 2)
+ self.assertEqual(route[0].device, self.devices['olt'])
+ self.assertEqual(route[0].ingress_port, self.ports['olt'][0])
+ self.assertEqual(route[0].egress_port, self.ports['olt'][2])
+ self.assertEqual(route[1].device, self.devices['onu2'])
+ self.assertEqual(route[1].ingress_port, self.ports['onu2'][1])
+ self.assertEqual(route[1].egress_port, self.ports['onu2'][0])
+
+ route = routes[(101, 0)]
+ self.assertEqual(len(route), 2)
+ self.assertEqual(route[0].device, self.devices['onu1'])
+ self.assertEqual(route[0].ingress_port, self.ports['onu1'][0])
+ self.assertEqual(route[0].egress_port, self.ports['onu1'][1])
+ self.assertEqual(route[1].device, self.devices['olt'])
+ self.assertEqual(route[1].ingress_port, self.ports['olt'][1])
+ self.assertEqual(route[1].egress_port, self.ports['olt'][0])
+
+ route = routes[(201, 0)]
+ self.assertEqual(len(route), 2)
+ self.assertEqual(route[0].device, self.devices['onu2'])
+ self.assertEqual(route[0].ingress_port, self.ports['onu2'][0])
+ self.assertEqual(route[0].egress_port, self.ports['onu2'][1])
+ self.assertEqual(route[1].device, self.devices['olt'])
+ self.assertEqual(route[1].ingress_port, self.ports['olt'][2])
+ self.assertEqual(route[1].egress_port, self.ports['olt'][0])
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOW DECOMP TESTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ def test_eapol_flow_decomp_case(self):
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[in_port(201), eth_type(0x888e)],
+ actions=[output(ofp.OFPP_CONTROLLER)]
+ ))
+ self.lda._flow_table_updated(self.flows)
+ self.assertEqual(len(self.device_flows['olt'].items), 2)
+ self.assertEqual(len(self.device_flows['onu1'].items), 3)
+ self.assertEqual(len(self.device_flows['onu2'].items), 3)
+ self.assertEqual(len(self.device_groups['olt'].items), 0)
+ self.assertEqual(len(self.device_groups['onu1'].items), 0)
+ self.assertEqual(len(self.device_groups['onu2'].items), 0)
+
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(2), vlan_vid(4096 + 201), eth_type(0x888e)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 4000)),
+ output(0)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(201)],
+ actions=[
+ pop_vlan(),
+ output(2)
+ ]
+ ))
+
+ def test_wildcarded_igmp_rule(self):
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[eth_type(0x800), ip_proto(2)],
+ actions=[output(ofp.OFPP_CONTROLLER)]
+ ))
+
+ self.lda._flow_table_updated(self.flows)
+ self.assertEqual(len(self.device_flows['olt'].items), 4)
+ self.assertEqual(len(self.device_flows['onu1'].items), 3)
+ self.assertEqual(len(self.device_flows['onu2'].items), 3)
+ self.assertEqual(len(self.device_groups['olt'].items), 0)
+ self.assertEqual(len(self.device_groups['onu1'].items), 0)
+ self.assertEqual(len(self.device_groups['onu2'].items), 0)
+
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(2), vlan_vid(4096 + 101), eth_type(0x800), ip_proto(2)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 4000)),
+ output(0)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(101)],
+ actions=[
+ pop_vlan(),
+ output(2)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[2], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(2), vlan_vid(4096 + 201), eth_type(0x800), ip_proto(2)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 4000)),
+ output(0)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[3], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(201)],
+ actions=[
+ pop_vlan(),
+ output(2)
+ ]
+ ))
+
+ def test_multicast_group_with_one_subscriber(self):
+ self.lda.update_group_table(mk_multicast_group_mod(
+ group_id=2,
+ buckets=[
+ ofp.ofp_bucket(actions=[
+ pop_vlan(),
+ output(201)
+ ]),
+ ]
+ ))
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[
+ in_port(0),
+ eth_type(0x800),
+ vlan_vid(4096 + 140),
+ ipv4_dst(0xe60a0a0a)
+ ],
+ actions=[group(2)]
+ ))
+ self.lda._flow_table_updated(self.flows)
+ self.assertEqual(len(self.device_flows['olt'].items), 1)
+ self.assertEqual(len(self.device_flows['onu1'].items), 3)
+ self.assertEqual(len(self.device_flows['onu2'].items), 4)
+ self.assertEqual(len(self.device_groups['olt'].items), 0)
+ self.assertEqual(len(self.device_groups['onu1'].items), 0)
+ self.assertEqual(len(self.device_groups['onu2'].items), 0)
+
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe60a0a0a)],
+ actions=[
+ pop_vlan(),
+ output(2)
+ ]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[3], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), eth_type(0x800), ipv4_dst(0xe60a0a0a)],
+ actions=[
+ output(0)
+ ]
+ ))
+
+ def test_multicast_group_with_no_subscribers(self):
+ self.lda.update_group_table(mk_multicast_group_mod(
+ group_id=2,
+ buckets=[] # No subscribers
+ ))
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[
+ in_port(0),
+ eth_type(0x800),
+ vlan_vid(4096 + 140),
+ ipv4_dst(0xe60a0a0a)
+ ],
+ actions=[group(2)]
+ ))
+ self.lda._flow_table_updated(self.flows)
+ self.assertEqual(len(self.device_flows['olt'].items), 1)
+ self.assertEqual(len(self.device_flows['onu1'].items), 3)
+ self.assertEqual(len(self.device_flows['onu2'].items), 3)
+ self.assertEqual(len(self.device_flows['onu2'].items), 3)
+ self.assertEqual(len(self.device_groups['olt'].items), 0)
+ self.assertEqual(len(self.device_groups['onu1'].items), 0)
+ self.assertEqual(len(self.device_groups['onu2'].items), 0)
+
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe60a0a0a)],
+ actions=[
+ pop_vlan(),
+ output(2)
+ ]
+ ))
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ COMPLEX TESTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ def test_complex_flow_table_decomposition(self):
+
+ # Various controller-bound rules
+ for _in_port in (101, 201):
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=2000,
+ match_fields=[in_port(_in_port), eth_type(0x888e)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 4000)),
+ output(ofp.OFPP_CONTROLLER)
+ ]
+ ))
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[in_port(_in_port), eth_type(0x800), ip_proto(2)],
+ actions=[output(ofp.OFPP_CONTROLLER)]
+ ))
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[in_port(_in_port), eth_type(0x800), ip_proto(17),
+ udp_src(68), udp_dst(67)],
+ actions=[output(ofp.OFPP_CONTROLLER)]
+ ))
+
+ # Multicast channels
+ mcast_setup = (
+ (1, 0xe4010101, ()),
+ (2, 0xe4010102, (101,)),
+ (3, 0xe4010103, (201,)),
+ (4, 0xe4010104, (101, 201)),
+ )
+ for group_id, mcast_addr, ports in mcast_setup:
+ self.lda.update_group_table(mk_multicast_group_mod(
+ group_id=group_id,
+ buckets=[
+ ofp.ofp_bucket(actions=[
+ pop_vlan(),
+ output(port)
+ ]) for port in ports
+ ]))
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[
+ in_port(0),
+ eth_type(0x800),
+ vlan_vid(4096 + 140),
+ ipv4_dst(mcast_addr)
+ ],
+ actions=[
+ group(group_id)
+ ]
+ ))
+
+ # Unicast channels for each subscriber
+ for port, c_vid in ((101, 101), (201, 201)):
+
+ # Downstream flow 1 for nni to pon
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=500,
+ match_fields=[
+ in_port(0),
+ vlan_vid(4096 + 1000),
+ metadata(c_vid)
+ ],
+ actions=[pop_vlan()],
+ next_table_id=1
+ ))
+
+ # Downstream flow 2
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + c_vid)],
+ actions=[set_field(vlan_vid(4096 + 0)), output(port)]
+ ))
+
+ # upstream flow 1 for the 0-tagged case
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=500,
+ match_fields=[in_port(port), vlan_vid(4096 + 0)],
+ actions=[set_field(vlan_vid(4096 + c_vid))],
+ next_table_id=1
+ ))
+ # ... and for the untagged case
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=500,
+ match_fields=[in_port(port), vlan_vid(0)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + c_vid))],
+ next_table_id=1
+ ))
+
+ # Upstream flow 2 for s-tag
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=500,
+ match_fields=[in_port(port), vlan_vid(4096 + c_vid)],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(4096 + 1000)),
+ output(0)
+ ]
+ ))
+
+ self.assertEqual(len(self.flows.items), 20)
+ self.assertEqual(len(self.groups.items), 4)
+
+ # trigger flow table decomposition
+ self.lda._flow_table_updated(self.flows)
+
+ # now check device level flows
+ self.assertEqual(len(self.device_flows['olt'].items), 18)
+ self.assertEqual(len(self.device_flows['onu1'].items), 5)
+ self.assertEqual(len(self.device_flows['onu2'].items), 5)
+ self.assertEqual(len(self.device_groups['olt'].items), 0)
+ self.assertEqual(len(self.device_groups['onu1'].items), 0)
+ self.assertEqual(len(self.device_groups['onu2'].items), 0)
+
+ # Flows installed on the OLT
+ self.assertFlowsEqual(self.device_flows['olt'].items[1], mk_flow_stat(
+ priority=2000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(101)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[0], mk_flow_stat(
+ priority=2000,
+ match_fields=[in_port(1), vlan_vid(4096 + 101), eth_type(0x888e)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[2], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), vlan_vid(4096 + 101), eth_type(0x800), ip_proto(2)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[3], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(101)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[4], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), vlan_vid(4096 + 101), eth_type(0x800), ip_proto(17),
+ udp_src(68), udp_dst(67)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[5], mk_flow_stat(
+ priority=2000,
+ match_fields=[in_port(2), vlan_vid(4096 + 201), eth_type(0x888e)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[6], mk_flow_stat(
+ priority=2000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(201)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[7], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(2), vlan_vid(4096 + 201), eth_type(0x800), ip_proto(2)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[8], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 4000), vlan_pcp(0), metadata(201)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[9], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(2), vlan_vid(4096 + 201), eth_type(0x800), ip_proto(17),
+ udp_src(68), udp_dst(67)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+ output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[10], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010101)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[11], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010102)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[12], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010103)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[13], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(0), eth_type(0x800), vlan_vid(4096 + 140),
+ ipv4_dst(0xe4010104)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[14], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + 1000), metadata(101)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[15], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(1), vlan_vid(4096 + 101)],
+ actions=[
+ push_vlan(0x8100), set_field(vlan_vid(4096 + 1000)), output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[16], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + 1000), metadata(201)],
+ actions=[pop_vlan(), output(2)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[17], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(2), vlan_vid(4096 + 201)],
+ actions=[
+ push_vlan(0x8100), set_field(vlan_vid(4096 + 1000)), output(0)]
+ ))
+
+ # Flows installed on the ONU1
+ self.assertFlowsEqual(self.device_flows['onu1'].items[0], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + 0)],
+ actions=[
+ set_field(vlan_vid(4096 + 101)), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu1'].items[3], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), eth_type(0x800), ipv4_dst(0xe4010102)],
+ actions=[output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu1'].items[4], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), eth_type(0x800), ipv4_dst(0xe4010104)],
+ actions=[output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu1'].items[2], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(1), vlan_vid(4096 + 101)],
+ actions=[set_field(vlan_vid(4096 + 0)), output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu1'].items[1], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(0)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 101)),
+ output(1)]
+ ))
+
+ # Flows installed on the ONU2
+ self.assertFlowsEqual(self.device_flows['onu2'].items[0], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + 0)],
+ actions=[
+ set_field(vlan_vid(4096 + 201)), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[3], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), eth_type(0x800), ipv4_dst(0xe4010103)],
+ actions=[output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[4], mk_flow_stat(
+ priority=1000,
+ match_fields=[in_port(1), eth_type(0x800), ipv4_dst(0xe4010104)],
+ actions=[output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[2], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(1), vlan_vid(4096 + 201)],
+ actions=[set_field(vlan_vid(4096 + 0)), output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[1], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(0)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 201)),
+ output(1)]
+ ))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/voltha/core/flow_decomposer.py b/voltha/core/flow_decomposer.py
index cfc4940..d123743 100644
--- a/voltha/core/flow_decomposer.py
+++ b/voltha/core/flow_decomposer.py
@@ -315,6 +315,11 @@
return instruction.goto_table.table_id
return None
+def get_metadata(flow):
+ for field in get_ofb_fields(flow):
+ if field.type == METADATA:
+ return field.table_metadata
+ return None
# test and extract next table and group information
@@ -533,21 +538,43 @@
# TODO make the 4000 configurable
fl_lst, _ = device_rules.setdefault(
egress_hop.device.id, ([], []))
- fl_lst.append(mk_flow_stat(
- priority=flow.priority,
- cookie=flow.cookie,
- match_fields=[
- in_port(egress_hop.ingress_port.port_no)
- ] + [
- field for field in get_ofb_fields(flow)
- if field.type not in (IN_PORT, VLAN_VID)
- ],
- actions=[
- push_vlan(0x8100),
- set_field(vlan_vid(ofp.OFPVID_PRESENT | 4000)),
- output(egress_hop.egress_port.port_no)]
- ))
+ # in_port_no is None for wildcard input case, do not include
+ # upstream port for 4000 flow in input
+ if in_port_no is None:
+ in_ports = self.get_wildcard_input_ports(exclude_port=
+ egress_hop.egress_port.port_no)
+ else:
+ in_ports = [in_port_no]
+
+ for input_port in in_ports:
+ fl_lst.append(mk_flow_stat( # Upstream flow
+ priority=flow.priority,
+ cookie=flow.cookie,
+ match_fields=[
+ in_port(egress_hop.ingress_port.port_no),
+ vlan_vid(ofp.OFPVID_PRESENT | input_port)
+ ] + [
+ field for field in get_ofb_fields(flow)
+ if field.type not in (IN_PORT, VLAN_VID)
+ ],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(ofp.OFPVID_PRESENT | 4000)),
+ output(egress_hop.egress_port.port_no)]
+ ))
+ fl_lst.append(mk_flow_stat( # Downstream flow
+ priority=flow.priority,
+ match_fields=[
+ in_port(egress_hop.egress_port.port_no),
+ vlan_vid(ofp.OFPVID_PRESENT | 4000),
+ vlan_pcp(0),
+ metadata(input_port)
+ ],
+ actions=[
+ pop_vlan(),
+ output(egress_hop.ingress_port.port_no)]
+ ))
else:
# NOT A CONTROLLER-BOUND FLOW
if is_upstream():
@@ -601,6 +628,20 @@
else: # downstream
if has_next_table(flow):
assert out_port_no is None
+
+ # For downstream flows with dual-tags, recalculate route with
+ # inner-tag as logical output port. Otherwise PON-0 is always
+ # selected.
+ inner_tag = get_metadata(flow)
+ if inner_tag is not None:
+ route = self.get_route(in_port_no, inner_tag)
+ if route is None:
+ log.error('no-route-double-tag', in_port_no=in_port_no,
+ out_port_no=inner_tag, comment='ignoring flow')
+ return device_rules
+ assert len(route) == 2
+ ingress_hop, egress_hop = route
+
fl_lst, _ = device_rules.setdefault(
ingress_hop.device.id, ([], []))
fl_lst.append(mk_flow_stat(
@@ -688,7 +729,7 @@
assert len(route2) == 2
ingress_hop2, egress_hop = route2
- assert ingress_hop == ingress_hop2
+ assert ingress_hop.ingress_port == ingress_hop2.ingress_port
fl_lst, _ = device_rules.setdefault(
egress_hop.device.id, ([], []))
@@ -719,4 +760,5 @@
def get_route(self, ingress_port_no, egress_port_no):
raise NotImplementedError('derived class must provide')
-
+ def get_wildcard_input_ports(self, exclude_port=None):
+ raise NotImplementedError('derived class must provide')
diff --git a/voltha/core/logical_device_agent.py b/voltha/core/logical_device_agent.py
index 1d8fe4b..c6bd3e8 100644
--- a/voltha/core/logical_device_agent.py
+++ b/voltha/core/logical_device_agent.py
@@ -614,41 +614,14 @@
self.root_proxy, logical_ports)
self._default_rules = self._generate_default_rules(graph)
root_ports = [p for p in logical_ports if p.root_port]
- assert len(root_ports) == 1
+ assert len(root_ports) == 1, 'Only one root port supported at this time'
self._nni_logical_port_no = root_ports[0].ofp_port.port_no
def _generate_default_rules(self, graph):
def root_device_default_rules(device):
- ports = self.root_proxy.get('/devices/{}/ports'.format(device.id))
- upstream_ports = [
- port for port in ports if port.type == Port.ETHERNET_NNI
- ]
- assert len(upstream_ports) == 1
- downstream_ports = [
- port for port in ports if port.type == Port.PON_OLT \
- or port.type == Port.VENET_OLT
- ]
- _is_any_venet_port = any(_port.type == Port.VENET_OLT for _port in
- downstream_ports)
- if _is_any_venet_port != True:
- assert len(downstream_ports) == 1, \
- 'Initially, we only handle one PON port'
- flows = OrderedDict((f.id, f) for f in [
- mk_flow_stat(
- priority=2000,
- match_fields=[
- in_port(upstream_ports[0].port_no),
- vlan_vid(ofp.OFPVID_PRESENT | 4000),
- vlan_pcp(0)
- ],
- actions=[
- pop_vlan(),
- output(downstream_ports[0].port_no)
- ]
- )
- ])
+ flows = OrderedDict()
groups = OrderedDict()
return flows, groups
@@ -755,3 +728,8 @@
def get_all_default_rules(self):
self._assure_cached_tables_up_to_date()
return self._default_rules
+
+ def get_wildcard_input_ports(self, exclude_port=None):
+ logical_ports = self.self_proxy.get('/ports')
+ return [port.ofp_port.port_no for port in logical_ports
+ if port.ofp_port.port_no != exclude_port]