diff --git a/neutron/plugins/ml2/drivers/agent/_agent_manager_base.py b/neutron/plugins/ml2/drivers/agent/_agent_manager_base.py index b7baabf2ae7..7f8727ef70e 100644 --- a/neutron/plugins/ml2/drivers/agent/_agent_manager_base.py +++ b/neutron/plugins/ml2/drivers/agent/_agent_manager_base.py @@ -21,10 +21,12 @@ import six class NetworkSegment(object): """Represents a Neutron network segment""" - def __init__(self, network_type, physical_network, segmentation_id): + def __init__(self, network_type, physical_network, segmentation_id, + mtu=None): self.network_type = network_type self.physical_network = physical_network self.segmentation_id = segmentation_id + self.mtu = mtu @six.add_metaclass(abc.ABCMeta) diff --git a/neutron/plugins/ml2/drivers/agent/_common_agent.py b/neutron/plugins/ml2/drivers/agent/_common_agent.py index a31134cd59d..6a17ff1823a 100644 --- a/neutron/plugins/ml2/drivers/agent/_common_agent.py +++ b/neutron/plugins/ml2/drivers/agent/_common_agent.py @@ -245,7 +245,8 @@ class CommonAgentLoop(service.Service): segment = amb.NetworkSegment( device_details.get('network_type'), device_details['physical_network'], - device_details.get('segmentation_id') + device_details.get('segmentation_id'), + device_details.get('mtu') ) network_id = device_details['network_id'] self.rpc_callbacks.add_network(network_id, segment) diff --git a/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py b/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py index d44354c79d9..f4906e2c945 100644 --- a/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py @@ -445,12 +445,12 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase): network_id: network_id}) def add_tap_interface(self, network_id, network_type, physical_network, - segmentation_id, tap_device_name, device_owner): + segmentation_id, tap_device_name, device_owner, mtu): """Add tap interface and handle interface missing exceptions.""" try: return self._add_tap_interface(network_id, network_type, physical_network, segmentation_id, - tap_device_name, device_owner) + tap_device_name, device_owner, mtu) except Exception: with excutils.save_and_reraise_exception() as ctx: if not ip_lib.device_exists(tap_device_name): @@ -461,7 +461,7 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase): return False def _add_tap_interface(self, network_id, network_type, physical_network, - segmentation_id, tap_device_name, device_owner): + segmentation_id, tap_device_name, device_owner, mtu): """Add tap interface. If a VIF has been plugged into a network, this function will @@ -483,6 +483,12 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase): physical_network, segmentation_id): return False + if mtu: # <-None with device_details from older neutron servers. + # we ensure the MTU here because libvirt does not set the + # MTU of a bridge it creates and the tap device it creates will + # inherit from the bridge its plugged into, which will be 1500 + # at the time. See bug/1684326 for details. + self._set_tap_mtu(tap_device_name, mtu) # Avoid messing with plugging devices into a bridge that the agent # does not own if not device_owner.startswith(constants.DEVICE_OWNER_COMPUTE_PREFIX): @@ -504,12 +510,16 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase): "thus added elsewhere.", data) return True + def _set_tap_mtu(self, tap_device_name, mtu): + ip_lib.IPDevice(tap_device_name).link.set_mtu(mtu) + def plug_interface(self, network_id, network_segment, tap_name, device_owner): return self.add_tap_interface(network_id, network_segment.network_type, network_segment.physical_network, network_segment.segmentation_id, - tap_name, device_owner) + tap_name, device_owner, + network_segment.mtu) def delete_bridge(self, bridge_name): bridge_device = bridge_lib.BridgeDevice(bridge_name) diff --git a/neutron/plugins/ml2/rpc.py b/neutron/plugins/ml2/rpc.py index ddceb4f9a91..845d5c45ad2 100644 --- a/neutron/plugins/ml2/rpc.py +++ b/neutron/plugins/ml2/rpc.py @@ -120,6 +120,7 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin): 'network_type': segment[api.NETWORK_TYPE], 'segmentation_id': segment[api.SEGMENTATION_ID], 'physical_network': segment[api.PHYSICAL_NETWORK], + 'mtu': port_context.network._network.get('mtu'), 'fixed_ips': port['fixed_ips'], 'device_owner': port['device_owner'], 'allowed_address_pairs': port['allowed_address_pairs'], diff --git a/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py index 0c4219b9c7a..cfc257ee36b 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py @@ -478,7 +478,7 @@ class TestLinuxBridgeManager(base.BaseTestCase): self.assertFalse(self.lbm.add_tap_interface("123", p_const.TYPE_VLAN, "physnet1", None, - "tap1", "foo")) + "tap1", "foo", None)) @mock.patch.object(ip_lib, "device_exists", return_value=True) def test_add_tap_interface_with_other_error(self, exists): @@ -486,7 +486,7 @@ class TestLinuxBridgeManager(base.BaseTestCase): side_effect=RuntimeError("No more fuel")): self.assertRaises(RuntimeError, self.lbm.add_tap_interface, "123", p_const.TYPE_VLAN, "physnet1", None, "tap1", - "foo") + "foo", None) def test_add_tap_interface_owner_compute(self): with mock.patch.object(ip_lib, "device_exists"): @@ -495,7 +495,7 @@ class TestLinuxBridgeManager(base.BaseTestCase): p_const.TYPE_LOCAL, "physnet1", None, "tap1", - "compute:1")) + "compute:1", None)) def _test_add_tap_interface(self, dev_owner_prefix): with mock.patch.object(ip_lib, "device_exists") as de_fn: @@ -503,13 +503,14 @@ class TestLinuxBridgeManager(base.BaseTestCase): self.assertFalse( self.lbm.add_tap_interface("123", p_const.TYPE_VLAN, "physnet1", "1", "tap1", - dev_owner_prefix)) + dev_owner_prefix, None)) de_fn.return_value = True bridge_device = mock.Mock() with mock.patch.object(self.lbm, "ensure_local_bridge") as en_fn,\ mock.patch.object(bridge_lib, "BridgeDevice", return_value=bridge_device), \ + mock.patch.object(self.lbm, '_set_tap_mtu') as set_tap, \ mock.patch.object(bridge_lib.BridgeDevice, "get_interface_bridge") as get_br: bridge_device.addif.retun_value = False @@ -518,7 +519,8 @@ class TestLinuxBridgeManager(base.BaseTestCase): p_const.TYPE_LOCAL, "physnet1", None, "tap1", - dev_owner_prefix)) + dev_owner_prefix, + None)) en_fn.assert_called_with("123", "brq123") self.lbm.bridge_mappings = {"physnet1": "brq999"} @@ -526,7 +528,9 @@ class TestLinuxBridgeManager(base.BaseTestCase): p_const.TYPE_LOCAL, "physnet1", None, "tap1", - dev_owner_prefix)) + dev_owner_prefix, + 8765)) + set_tap.assert_called_with('tap1', 8765) en_fn.assert_called_with("123", "brq999") get_br.return_value = False @@ -535,7 +539,8 @@ class TestLinuxBridgeManager(base.BaseTestCase): p_const.TYPE_LOCAL, "physnet1", None, "tap1", - dev_owner_prefix)) + dev_owner_prefix, + None)) with mock.patch.object(self.lbm, "ensure_physical_in_bridge") as ens_fn: ens_fn.return_value = False @@ -543,7 +548,8 @@ class TestLinuxBridgeManager(base.BaseTestCase): p_const.TYPE_VLAN, "physnet1", "1", "tap1", - dev_owner_prefix)) + dev_owner_prefix, + None)) def test_add_tap_interface_owner_network(self): self._test_add_tap_interface(constants.DEVICE_OWNER_NETWORK_PREFIX) @@ -552,13 +558,14 @@ class TestLinuxBridgeManager(base.BaseTestCase): self._test_add_tap_interface(constants.DEVICE_OWNER_NEUTRON_PREFIX) def test_plug_interface(self): - segment = amb.NetworkSegment(p_const.TYPE_VLAN, "physnet-1", "1") + segment = amb.NetworkSegment(p_const.TYPE_VLAN, "physnet-1", "1", 1777) with mock.patch.object(self.lbm, "add_tap_interface") as add_tap: self.lbm.plug_interface("123", segment, "tap234", constants.DEVICE_OWNER_NETWORK_PREFIX) add_tap.assert_called_with("123", p_const.TYPE_VLAN, "physnet-1", "1", "tap234", - constants.DEVICE_OWNER_NETWORK_PREFIX) + constants.DEVICE_OWNER_NETWORK_PREFIX, + 1777) def test_delete_bridge(self): with mock.patch.object(ip_lib.IPDevice, "exists") as de_fn,\