Comprehensive flow tables splitting test
Change-Id: I255bdb7f984e97ff1820f17921c8c2a018500f32
diff --git a/tests/utests/voltha/core/test_logical_device_agent.py b/tests/utests/voltha/core/test_logical_device_agent.py
index 5e97f6c..87d888d 100644
--- a/tests/utests/voltha/core/test_logical_device_agent.py
+++ b/tests/utests/voltha/core/test_logical_device_agent.py
@@ -52,9 +52,12 @@
]
self.devices = {
- 'olt': Device(id='olt', root=True, parent_id='id'),
- 'onu1': Device(id='onu1', parent_id='olt', parent_port_no=1),
- 'onu2': Device(id='onu2', parent_id='olt', parent_port_no=1),
+ '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=1, vlan=102),
}
self.ports = {
@@ -114,7 +117,7 @@
if path.endswith('/flows'):
self.device_flows[path[:-len('/flows')]] = data
elif path.endswith('/flow_groups'):
- self.device_groups[path[:-len('/flows')]] = data
+ self.device_groups[path[:-len('/flow_groups')]] = data
else:
raise NotImplementedError(
'not handling path /devices/{}'.format(path))
@@ -605,6 +608,233 @@
]
))
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ COMPLEX TESTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ def test_complex_flow_table_decomposition(self):
+
+ # Various controller-bound rules
+ for _in_port in (1, 2):
+ 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=[eth_type(0x800), ip_proto(2)],
+ actions=[output(ofp.OFPP_CONTROLLER)]
+ ))
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=1000,
+ match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
+ actions=[output(ofp.OFPP_CONTROLLER)]
+ ))
+
+ # Multicast channels
+ mcast_setup = (
+ (1, 0xe4010101, ()),
+ (2, 0xe4010102, (1,)),
+ (3, 0xe4010103, (2,)),
+ (4, 0xe4010104, (1, 2)),
+ )
+ 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
+ # Downstream flow 1 for both
+ self.lda.update_flow_table(mk_simple_flow_mod(
+ priority=500,
+ match_fields=[
+ in_port(0),
+ vlan_vid(4096 + 1000)
+ ],
+ actions=[pop_vlan()],
+ next_table_id=1
+ ))
+ # Downstream flow 2 and upsrteam flow 1 for each ONU
+ for port, c_vid in ((1, 101), (2, 102)):
+ 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)]
+ ))
+ # 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
+ ))
+ # 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), 17)
+ 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), 8)
+ self.assertEqual(len(self.device_flows['onu1'].items), 6)
+ self.assertEqual(len(self.device_flows['onu2'].items), 6)
+ 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[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)],
+ 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), 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),
+ 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), vlan_vid(4096 + 140)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[5], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + 1000)],
+ actions=[pop_vlan(), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['olt'].items[6], 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[7], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(1), vlan_vid(4096 + 102)],
+ 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=1000,
+ 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[1], 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[2], 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[3], 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[4], 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[5], 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=1000,
+ match_fields=[in_port(0), vlan_vid(4096 + 0)],
+ actions=[
+ set_field(vlan_vid(4096 + 102)), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[1], 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[2], 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[3], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(1), vlan_vid(4096 + 102)],
+ actions=[set_field(vlan_vid(4096 + 0)), output(0)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[4], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(4096 + 0)],
+ actions=[set_field(vlan_vid(4096 + 102)), output(1)]
+ ))
+ self.assertFlowsEqual(self.device_flows['onu2'].items[5], mk_flow_stat(
+ priority=500,
+ match_fields=[in_port(0), vlan_vid(0)],
+ actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 102)),
+ output(1)]
+ ))
if __name__ == '__main__':
diff --git a/voltha/core/logical_device_agent.py b/voltha/core/logical_device_agent.py
index 42b88d9..11266db 100644
--- a/voltha/core/logical_device_agent.py
+++ b/voltha/core/logical_device_agent.py
@@ -563,6 +563,7 @@
assert len(downstream_ports) == 1
flows = OrderedDict((f.id, f) for f in [
mk_flow_stat(
+ priority=1000,
match_fields=[
in_port(downstream_ports[0].port_no),
vlan_vid(ofp.OFPVID_PRESENT | 0)
@@ -611,10 +612,9 @@
# If egress_port is not specified (None), we can also can return a
# "half" route
- if egress_port_no is None and \
- ingress_port_no == self._nni_logical_port_no:
+ if egress_port_no is None:
for (ingress, egress), route in self._routes.iteritems():
- if ingress == self._nni_logical_port_no:
+ if ingress == ingress_port_no:
return [route[0], None]
raise Exception('not a single downstream route')