diff --git a/dragonflow/controller/apps/provider.py b/dragonflow/controller/apps/provider.py index 45ea0b343..a35ff119e 100644 --- a/dragonflow/controller/apps/provider.py +++ b/dragonflow/controller/apps/provider.py @@ -90,14 +90,17 @@ class ProviderApp(df_base_app.DFlowApp): self._update_bridge_mac(switch_port.name, None) def _update_bridge_mac(self, bridge, mac): - if bridge not in self.bridge_macs: + physical_network = self.reverse_bridge_mappings.get(bridge) + if not physical_network: return - old_mac = self.bridge_macs[bridge] + if physical_network not in self.bridge_macs: + return + + old_mac = self.bridge_macs[physical_network] if old_mac == mac: return - physical_network = self.reverse_bridge_mappings[bridge] lswitch = self.db_store.get_one( l2.LogicalSwitch(physical_network=physical_network), index=l2.LogicalSwitch.get_index('physical_network')) @@ -106,7 +109,7 @@ class ProviderApp(df_base_app.DFlowApp): self._remove_egress_placeholder_flow(lswitch.unique_key) if mac is not None: - self._egress_placeholder_flow(lswitch.unique_key) + self._egress_placeholder_flow(lswitch) self.bridge_macs[physical_network] = mac @@ -251,12 +254,12 @@ class ProviderApp(df_base_app.DFlowApp): ) if self.bridge_macs.get(physical_network) is not None: - self._egress_placeholder_flow(lport) + self._egress_placeholder_flow(lport.lswitch) - def _egress_placeholder_flow(self, lport): + def _egress_placeholder_flow(self, lswitch): # If dest MAC is the placeholder, update it to bridge MAC - network_id = lport.lswitch.unique_key - physical_network = lport.lswitch.physical_network + network_id = lswitch.unique_key + physical_network = lswitch.physical_network port_num = self.int_ofports[physical_network] self.mod_flow( diff --git a/dragonflow/tests/unit/test_provider_net_app.py b/dragonflow/tests/unit/test_provider_net_app.py index 1539ca886..e4d652a94 100644 --- a/dragonflow/tests/unit/test_provider_net_app.py +++ b/dragonflow/tests/unit/test_provider_net_app.py @@ -14,9 +14,12 @@ # under the License. import copy +import mock +from dragonflow.common import constants from dragonflow.controller.common import constants as const from dragonflow.db.models import l2 +from dragonflow.db.models import switch from dragonflow.tests.unit import test_app_base @@ -29,7 +32,7 @@ class TestProviderNetsApp(test_app_base.DFAppTestBase): def setUp(self): super(TestProviderNetsApp, self).setUp() - fake_vlan_switch1 = l2.LogicalSwitch( + self.fake_vlan_switch1 = l2.LogicalSwitch( network_type='vlan', id='fake_vlan_switch1', mtu=1454, @@ -43,7 +46,7 @@ class TestProviderNetsApp(test_app_base.DFAppTestBase): test_app_base.fake_lswitch_default_subnets[0]) fake_vlan_subnet.id = 'fake_vlan_subnet1' fake_vlan_subnet.lswitch = 'fake_vlan_switch1' - self.controller.update(fake_vlan_switch1) + self.controller.update(self.fake_vlan_switch1) self.controller.update(fake_vlan_subnet) self.app = self.open_flow_app.dispatcher.apps['provider'] self.app.ofproto.OFPVID_PRESENT = 0x1000 @@ -88,3 +91,43 @@ class TestProviderNetsApp(test_app_base.DFAppTestBase): priority=const.PRIORITY_HIGH, match=match) self.app.mod_flow.reset_mock() + + def test_provider_bridge(self): + self.app.int_ofports['phynet'] = 1 + self.app.bridge_macs['phynet'] = '00:12:23:34:45:56' + self.app.reverse_bridge_mappings['private'] = 'phynet' + + fake_local_vlan_port = make_fake_local_port( + lswitch='fake_vlan_switch1') + self.controller.update(fake_local_vlan_port) + self.app.mod_flow.reset_mock() + + switch_port = switch.SwitchPort( + id='fake_switch_port', lport=fake_local_vlan_port.id, + port_num=1, admin_state='up', name='private', + mac_in_use='00:00:00:00:00:01', + type=constants.SWITCH_COMPUTE_INTERFACE) + self.controller.update(switch_port) + + call_list = [ + mock.call( + command=self.app.ofproto.OFPFC_DELETE, + table_id=const.EGRESS_EXTERNAL_TABLE, + priority=const.PRIORITY_HIGH, + match=self.app.parser.OFPMatch()), + mock.call( + table_id=const.EGRESS_EXTERNAL_TABLE, + priority=const.PRIORITY_HIGH, + match=self.app.parser.OFPMatch(), + inst=[self.app.parser.OFPInstructionActions()] + )] + self.assertEqual(len(call_list), self.app.mod_flow.call_count) + self.app.mod_flow.assert_has_calls(call_list) + + self.app.mod_flow.reset_mock() + self.controller.delete(switch_port) + self.app.mod_flow.assert_called_with( + command=self.app.ofproto.OFPFC_DELETE, + table_id=const.EGRESS_EXTERNAL_TABLE, + priority=const.PRIORITY_HIGH, + match=self.app.parser.OFPMatch())