From e2676ae8d188286b76f802d605f363e21011841a Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Fri, 25 Mar 2016 12:37:12 -0700 Subject: [PATCH] DVR: rebind port if ofport changes When binding is called in DVR, check to see if the port was previously wired under a different ofport. If it was, first unbind the old port and then bind the new one. Change-Id: I372158c4a6986295e396d849a2c9c5372b271e08 Closes-Bug: #1562467 (cherry picked from commit 4731dbbef1f615b9ce6d18315e8ca9810e8a772d) --- .../agent/ovs_dvr_neutron_agent.py | 6 ++ .../agent/test_ovs_neutron_agent.py | 73 ++++++++++++++----- 2 files changed, 59 insertions(+), 20 deletions(-) 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 8cb65f6527b..d5a62c28522 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 @@ -572,6 +572,12 @@ class OVSDVRNeutronAgent(object): local_vlan_map.network_type)) return + if (port.vif_id in self.local_ports and + self.local_ports[port.vif_id].ofport != port.ofport): + LOG.info(_LI("DVR: Port %(vif)s changed port number to " + "%(ofport)s, rebinding."), + {'vif': port.vif_id, 'ofport': port.ofport}) + self.unbind_port_from_dvr(port, local_vlan_map) if device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: self._bind_distributed_router_interface_port(port, local_vlan_map, 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 d2e1a97b40c..72a020dc9f7 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 @@ -2336,6 +2336,58 @@ class TestOvsDvrNeutronAgent(object): def test_port_bound_for_dvr_with_csnat_ports(self): self._setup_for_dvr_test() + int_br, tun_br = self._port_bound_for_dvr_with_csnat_ports() + lvid = self.agent.local_vlan_map[self._net_uuid].vlan + expected_on_int_br = [ + mock.call.install_dvr_to_src_mac( + network_type='vxlan', + gateway_mac='aa:bb:cc:11:22:33', + dst_mac=self._port.vif_mac, + dst_port=self._port.ofport, + vlan_tag=lvid, + ), + ] + self._expected_port_bound(self._port, lvid, is_dvr=False) + self.assertEqual(expected_on_int_br, int_br.mock_calls) + expected_on_tun_br = [ + mock.call.provision_local_vlan( + network_type='vxlan', + lvid=lvid, + segmentation_id=None, + distributed=True, + ), + ] + self.assertEqual(expected_on_tun_br, tun_br.mock_calls) + + def test_port_bound_for_dvr_with_csnat_ports_ofport_change(self): + self._setup_for_dvr_test() + self._port_bound_for_dvr_with_csnat_ports() + # simulate a replug + self._port.ofport = 12 + int_br, tun_br = self._port_bound_for_dvr_with_csnat_ports() + lvid = self.agent.local_vlan_map[self._net_uuid].vlan + expected_on_int_br = [ + mock.call.delete_dvr_to_src_mac( + network_type='vxlan', + dst_mac=self._port.vif_mac, + vlan_tag=lvid, + ), + mock.call.install_dvr_to_src_mac( + network_type='vxlan', + gateway_mac='aa:bb:cc:11:22:33', + dst_mac=self._port.vif_mac, + dst_port=self._port.ofport, + vlan_tag=lvid, + ), + ] + self._expected_port_bound(self._port, lvid, is_dvr=False) + self.assertEqual(expected_on_int_br, int_br.mock_calls) + # a local vlan was already provisioned so there should be no new + # calls to tunbr + self.assertEqual([], tun_br.mock_calls) + # make sure ofport was updated + self.assertEqual(12, + self.agent.dvr_agent.local_ports[self._port.vif_id].ofport) + + def _port_bound_for_dvr_with_csnat_ports(self): int_br = mock.create_autospec(self.agent.int_br) tun_br = mock.create_autospec(self.agent.tun_br) int_br.set_db_attribute.return_value = True @@ -2361,26 +2413,7 @@ class TestOvsDvrNeutronAgent(object): None, None, self._fixed_ips, n_const.DEVICE_OWNER_ROUTER_SNAT, False) - lvid = self.agent.local_vlan_map[self._net_uuid].vlan - expected_on_int_br = [ - mock.call.install_dvr_to_src_mac( - network_type='vxlan', - gateway_mac='aa:bb:cc:11:22:33', - dst_mac=self._port.vif_mac, - dst_port=self._port.ofport, - vlan_tag=lvid, - ), - ] + self._expected_port_bound(self._port, lvid, is_dvr=False) - self.assertEqual(expected_on_int_br, int_br.mock_calls) - expected_on_tun_br = [ - mock.call.provision_local_vlan( - network_type='vxlan', - lvid=lvid, - segmentation_id=None, - distributed=True, - ), - ] - self.assertEqual(expected_on_tun_br, tun_br.mock_calls) + return int_br, tun_br def test_port_bound_for_dvr_with_csnat_ports_without_subnet(self): self._setup_for_dvr_test()