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 116f5c8d67a..f4ae94b003f 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -1280,15 +1280,13 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin, self.int_ofports[physical_network] = int_ofport self.phys_ofports[physical_network] = phys_ofport - # following drop operations are not necessary for - # dvr agent setup_dvr_flows. So skip it if dvr enabled - # the reason is for br_int it is duplicate - # for br_physical drop_port is dangerous because when dvr - # enabled the highest flow on table=0 is 2 which means - # basically everything will be dropped until setup_dvr_flows - # got executed. + # Drop packets from physical bridges that have not matched a higher + # priority flow to set a local vlan. This prevents these stray + # packets from being forwarded to other physical bridges which + # could cause a network loop in the physical network. + self.int_br.drop_port(in_port=int_ofport) + if not self.enable_distributed_routing: - self.int_br.drop_port(in_port=int_ofport) br.drop_port(in_port=phys_ofport) if self.use_veth_interconnection: 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 69817ec3456..f711a36a6de 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 @@ -1275,7 +1275,9 @@ class TestOvsNeutronAgent(object): self.assertFalse(int_br.set_db_attribute.called) self.assertFalse(int_br.drop_port.called) - def _test_setup_physical_bridges(self, port_exists=False): + def _test_setup_physical_bridges(self, port_exists=False, + dvr_enabled=False): + self.agent.enable_distributed_routing = dvr_enabled with mock.patch.object(ip_lib.IPDevice, "exists") as devex_fn,\ mock.patch.object(sys, "exit"),\ mock.patch.object(self.agent, 'br_phys_cls') as phys_br_cls,\ @@ -1332,8 +1334,13 @@ class TestOvsNeutronAgent(object): 'phy-br-eth', constants.NONEXISTENT_PEER), ] expected_calls += [ - mock.call.int_br.drop_port(in_port='int_ofport'), - mock.call.phys_br.drop_port(in_port='phy_ofport'), + mock.call.int_br.drop_port(in_port='int_ofport') + ] + if not dvr_enabled: + expected_calls += [ + mock.call.phys_br.drop_port(in_port='phy_ofport') + ] + expected_calls += [ mock.call.int_br.set_db_attribute('Interface', 'int-br-eth', 'options', {'peer': 'phy-br-eth'}), @@ -1353,6 +1360,9 @@ class TestOvsNeutronAgent(object): def test_setup_physical_bridges_port_exists(self): self._test_setup_physical_bridges(port_exists=True) + def test_setup_physical_bridges_dvr_enabled(self): + self._test_setup_physical_bridges(dvr_enabled=True) + def test_setup_physical_bridges_using_veth_interconnection(self): self.agent.use_veth_interconnection = True with mock.patch.object(ip_lib.IPDevice, "exists") as devex_fn,\