diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_dvr_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_dvr_neutron_agent.py index ff29a4656d9..503cc5a0f4a 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_dvr_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_dvr_neutron_agent.py @@ -130,10 +130,9 @@ class OVSDVRNeutronAgent(object): self.enable_tunneling = enable_tunneling self.enable_distributed_routing = enable_distributed_routing self.bridge_mappings = bridge_mappings - self.phys_brs = phys_brs self.int_ofports = int_ofports self.phys_ofports = phys_ofports - self.reset_ovs_parameters(integ_br, tun_br, + self.reset_ovs_parameters(integ_br, tun_br, phys_brs, patch_int_ofport, patch_tun_ofport) self.reset_dvr_parameters() self.dvr_mac_address = None @@ -145,17 +144,19 @@ class OVSDVRNeutronAgent(object): def set_firewall(self, firewall=None): self.firewall = firewall - def setup_dvr_flows(self): + def setup_dvr_flows(self, bridge_mappings=None): + bridge_mappings = bridge_mappings or self.bridge_mappings self.setup_dvr_flows_on_integ_br() self.setup_dvr_flows_on_tun_br() - self.setup_dvr_flows_on_phys_br() + self.setup_dvr_flows_on_phys_br(bridge_mappings) self.setup_dvr_mac_flows_on_all_brs() - def reset_ovs_parameters(self, integ_br, tun_br, + def reset_ovs_parameters(self, integ_br, tun_br, phys_brs, patch_int_ofport, patch_tun_ofport): '''Reset the openvswitch parameters''' self.int_br = integ_br self.tun_br = tun_br + self.phys_brs = phys_brs self.patch_int_ofport = patch_int_ofport self.patch_tun_ofport = patch_tun_ofport @@ -166,6 +167,15 @@ class OVSDVRNeutronAgent(object): self.local_ports = {} self.registered_dvr_macs = set() + def reset_dvr_flows(self, integ_br, tun_br, phys_brs, + patch_int_ofport, patch_tun_ofport, + bridge_mappings=None): + '''Reset the openvswitch and DVR parameters and DVR flows''' + self.reset_ovs_parameters( + integ_br, tun_br, phys_brs, patch_int_ofport, patch_tun_ofport) + self.reset_dvr_parameters() + self.setup_dvr_flows(bridge_mappings) + def get_dvr_mac_address(self): try: self.get_dvr_mac_address_with_retry() @@ -241,10 +251,10 @@ class OVSDVRNeutronAgent(object): self.tun_br.install_goto(table_id=constants.DVR_PROCESS, dest_table_id=constants.PATCH_LV_TO_TUN) - def setup_dvr_flows_on_phys_br(self): + def setup_dvr_flows_on_phys_br(self, bridge_mappings=None): '''Setup up initial dvr flows into br-phys''' - - for physical_network in self.bridge_mappings: + bridge_mappings = bridge_mappings or self.bridge_mappings + for physical_network in bridge_mappings: self.phys_brs[physical_network].install_goto( in_port=self.phys_ofports[physical_network], priority=2, diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index 160ce5cc7ff..aee85394bb2 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -1206,6 +1206,11 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin, if bridge_mappings: sync = True self.setup_physical_bridges(bridge_mappings) + if self.enable_distributed_routing: + self.dvr_agent.reset_dvr_flows( + self.int_br, self.tun_br, self.phys_brs, + self.patch_int_ofport, self.patch_tun_ofport, + bridge_mappings) return sync def _check_bridge_datapath_id(self, bridge, datapath_ids_set): @@ -2236,12 +2241,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin, # with l2pop fdb entries update self._report_state() if self.enable_distributed_routing: - self.dvr_agent.reset_ovs_parameters(self.int_br, - self.tun_br, - self.patch_int_ofport, - self.patch_tun_ofport) - self.dvr_agent.reset_dvr_parameters() - self.dvr_agent.setup_dvr_flows() + self.dvr_agent.reset_dvr_flows( + self.int_br, self.tun_br, self.phys_brs, + self.patch_int_ofport, self.patch_tun_ofport) # notify that OVS has restarted registry.notify( callback_resources.AGENT, diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py index be988ca0bc6..b00b5d46261 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py @@ -3573,6 +3573,64 @@ class TestOvsDvrNeutronAgent(object): self.agent.ancillary_brs = mock.Mock() self._test_scan_ports_failure('scan_ancillary_ports') + def test_ext_br_recreated(self): + self._setup_for_dvr_test() + reset_methods = ( + 'reset_ovs_parameters', 'reset_dvr_parameters', + 'setup_dvr_flows_on_integ_br', 'setup_dvr_flows_on_tun_br', + 'setup_dvr_flows_on_phys_br', 'setup_dvr_mac_flows_on_all_brs') + for method in reset_methods: + mock.patch.object(self.agent.dvr_agent, method).start() + bridge_mappings = {'physnet0': 'br-ex0', + 'physnet1': 'br-ex1'} + ex_br_mocks = [mock.Mock(br_name='br-ex0'), + mock.Mock(br_name='br-ex1')] + phys_bridges = {'physnet0': ex_br_mocks[0], + 'physnet1': ex_br_mocks[1]}, + bm_mock = mock.Mock() + bridges_added = ['br-ex0'] + with mock.patch( + 'neutron.agent.linux.ovsdb_monitor.get_bridges_monitor', + return_value=bm_mock),\ + mock.patch.object( + self.agent, + 'check_ovs_status', + return_value=constants.OVS_NORMAL),\ + mock.patch.object( + self.agent, + '_agent_has_updates', + side_effect=TypeError('loop exit')),\ + mock.patch.dict( + self.agent.bridge_mappings, bridge_mappings, clear=True),\ + mock.patch.dict( + self.agent.phys_brs, phys_bridges, clear=True),\ + mock.patch.object( + self.agent, + 'setup_physical_bridges') as setup_physical_bridges: + bm_mock.bridges_added = bridges_added + try: + self.agent.rpc_loop(polling_manager=mock.Mock(), + bridges_monitor=bm_mock) + except TypeError: + pass + # Setup bridges should be called once even if it will raise Runtime + # Error because TypeError is raised in _agent_has_updates to stop + # agent after first loop iteration + setup_physical_bridges.assert_called_once_with({'physnet0': 'br-ex0'}) + # Ensure dvr_agent methods were called correctly + self.agent.dvr_agent.reset_ovs_parameters.assert_called_once_with( + self.agent.int_br, self.agent.tun_br, self.agent.phys_brs, + self.agent.patch_int_ofport, self.agent.patch_tun_ofport) + self.agent.dvr_agent.reset_dvr_parameters.assert_called_once_with() + (self.agent.dvr_agent.setup_dvr_flows_on_phys_br. + assert_called_once_with({'physnet0': 'br-ex0'})) + (self.agent.dvr_agent.setup_dvr_flows_on_integ_br. + assert_called_once_with()) + (self.agent.dvr_agent.setup_dvr_flows_on_tun_br. + assert_called_once_with()) + (self.agent.dvr_agent.setup_dvr_mac_flows_on_all_brs. + assert_called_once_with()) + class TestOvsDvrNeutronAgentOFCtl(TestOvsDvrNeutronAgent, ovs_test_base.OVSOFCtlTestBase):