Merge "Make agent interface plugging utilize network MTU" into stable/liberty

This commit is contained in:
Jenkins 2016-05-17 12:58:14 +00:00 committed by Gerrit Code Review
commit b5d4f89551
12 changed files with 132 additions and 37 deletions

View File

@ -99,7 +99,8 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter):
sn_port['fixed_ips'],
sn_port['mac_address'],
interface_name,
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
dvr_snat_ns.SNAT_INT_DEV_PREFIX,
mtu=sn_port.get('mtu'))
def _dvr_internal_network_removed(self, port):
super(DvrEdgeRouter, self)._dvr_internal_network_removed(port)
@ -132,7 +133,8 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter):
snat_ns.name, port['network_id'],
port['id'], port['fixed_ips'],
port['mac_address'], interface_name,
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
dvr_snat_ns.SNAT_INT_DEV_PREFIX,
mtu=port.get('mtu'))
self._external_gateway_added(ex_gw_port, gw_interface_name,
snat_ns.name, preserve_ips=[])
self.snat_iptables_manager = iptables_manager.IptablesManager(

View File

@ -105,7 +105,8 @@ class FipNamespace(namespaces.Namespace):
ex_gw_port['mac_address'],
bridge=self.agent_conf.external_network_bridge,
namespace=ns_name,
prefix=FIP_EXT_DEV_PREFIX)
prefix=FIP_EXT_DEV_PREFIX,
mtu=ex_gw_port.get('mtu'))
ip_cidrs = common_utils.fixed_ip_cidrs(ex_gw_port['fixed_ips'])
self.driver.init_l3(interface_name, ip_cidrs, namespace=ns_name,
@ -231,9 +232,11 @@ class FipNamespace(namespaces.Namespace):
self._internal_ns_interface_added(str(fip_2_rtr),
fip_2_rtr_name,
fip_ns_name)
if self.agent_conf.network_device_mtu:
int_dev[0].link.set_mtu(self.agent_conf.network_device_mtu)
int_dev[1].link.set_mtu(self.agent_conf.network_device_mtu)
mtu = (self.agent_conf.network_device_mtu or
ri.get_ex_gw_port().get('mtu'))
if mtu:
int_dev[0].link.set_mtu(mtu)
int_dev[1].link.set_mtu(mtu)
int_dev[0].link.set_up()
int_dev[1].link.set_up()

View File

@ -144,7 +144,8 @@ class HaRouter(router.RouterInfo):
interface_name,
self.ha_port['mac_address'],
namespace=self.ns_name,
prefix=HA_DEV_PREFIX)
prefix=HA_DEV_PREFIX,
mtu=self.ha_port.get('mtu'))
ip_cidrs = common_utils.fixed_ip_cidrs(self.ha_port['fixed_ips'])
self.driver.init_l3(interface_name, ip_cidrs,
namespace=self.ns_name,
@ -263,13 +264,13 @@ class HaRouter(router.RouterInfo):
def internal_network_added(self, port):
port_id = port['id']
interface_name = self.get_internal_device_name(port_id)
self.driver.plug(port['network_id'],
port_id,
interface_name,
port['mac_address'],
namespace=self.ns_name,
prefix=router.INTERNAL_DEV_PREFIX)
prefix=router.INTERNAL_DEV_PREFIX,
mtu=port.get('mtu'))
self._disable_ipv6_addressing_on_interface(interface_name)
for ip_cidr in common_utils.fixed_ip_cidrs(port['fixed_ips']):

View File

@ -291,12 +291,12 @@ class RouterInfo(object):
def _internal_network_added(self, ns_name, network_id, port_id,
fixed_ips, mac_address,
interface_name, prefix):
interface_name, prefix, mtu=None):
LOG.debug("adding internal network: prefix(%s), port(%s)",
prefix, port_id)
self.driver.plug(network_id, port_id, interface_name, mac_address,
namespace=ns_name,
prefix=prefix)
prefix=prefix, mtu=mtu)
ip_cidrs = common_utils.fixed_ip_cidrs(fixed_ips)
self.driver.init_router_port(
@ -321,7 +321,8 @@ class RouterInfo(object):
fixed_ips,
mac_address,
interface_name,
INTERNAL_DEV_PREFIX)
INTERNAL_DEV_PREFIX,
mtu=port.get('mtu'))
def internal_network_removed(self, port):
interface_name = self.get_internal_device_name(port['id'])
@ -470,7 +471,8 @@ class RouterInfo(object):
ex_gw_port['mac_address'],
bridge=self.agent_conf.external_network_bridge,
namespace=ns_name,
prefix=EXTERNAL_DEV_PREFIX)
prefix=EXTERNAL_DEV_PREFIX,
mtu=ex_gw_port.get('mtu'))
def _get_external_gw_ips(self, ex_gw_port):
gateway_ips = []

View File

@ -1221,7 +1221,8 @@ class DeviceManager(object):
port.id,
interface_name,
port.mac_address,
namespace=network.namespace)
namespace=network.namespace,
mtu=network.get('mtu'))
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Unable to plug DHCP port for '

View File

@ -26,7 +26,7 @@ from neutron.agent.linux import utils
from neutron.common import constants as n_const
from neutron.common import exceptions
from neutron.common import ipv6_utils
from neutron.i18n import _LE, _LI
from neutron.i18n import _LE, _LI, _LW
LOG = logging.getLogger(__name__)
@ -242,15 +242,19 @@ class LinuxInterfaceDriver(object):
@abc.abstractmethod
def plug_new(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
bridge=None, namespace=None, prefix=None, mtu=None):
"""Plug in the interface only for new devices that don't exist yet."""
def plug(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
bridge=None, namespace=None, prefix=None, mtu=None):
if not ip_lib.device_exists(device_name,
namespace=namespace):
self.plug_new(network_id, port_id, device_name, mac_address,
bridge, namespace, prefix)
try:
self.plug_new(network_id, port_id, device_name, mac_address,
bridge, namespace, prefix, mtu)
except TypeError:
self.plug_new(network_id, port_id, device_name, mac_address,
bridge, namespace, prefix)
else:
LOG.info(_LI("Device %s already exists"), device_name)
@ -278,7 +282,7 @@ class LinuxInterfaceDriver(object):
class NullDriver(LinuxInterfaceDriver):
def plug_new(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
bridge=None, namespace=None, prefix=None, mtu=None):
pass
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
@ -313,7 +317,7 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
ovs.replace_port(device_name, *attrs)
def plug_new(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
bridge=None, namespace=None, prefix=None, mtu=None):
"""Plug in the interface."""
if not bridge:
bridge = self.conf.ovs_integration_bridge
@ -338,11 +342,13 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
ns_dev.link.set_address(mac_address)
if self.conf.network_device_mtu:
ns_dev.link.set_mtu(self.conf.network_device_mtu)
mtu = self.conf.network_device_mtu or mtu
if mtu:
ns_dev.link.set_mtu(mtu)
if self.conf.ovs_use_veth:
root_dev.link.set_mtu(self.conf.network_device_mtu)
root_dev.link.set_mtu(mtu)
else:
LOG.warning(_LW("No MTU configured for port %s"), port_id)
# Add an interface created by ovs to the namespace.
if not self.conf.ovs_use_veth and namespace:
namespace_obj = ip.ensure_namespace(namespace)
@ -430,7 +436,7 @@ class IVSInterfaceDriver(LinuxInterfaceDriver):
utils.execute(cmd, run_as_root=True)
def plug_new(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
bridge=None, namespace=None, prefix=None, mtu=None):
"""Plug in the interface."""
ip = ip_lib.IPWrapper()
tap_name = self._get_tap_name(device_name, prefix)
@ -443,9 +449,12 @@ class IVSInterfaceDriver(LinuxInterfaceDriver):
ns_dev = ip.device(device_name)
ns_dev.link.set_address(mac_address)
if self.conf.network_device_mtu:
ns_dev.link.set_mtu(self.conf.network_device_mtu)
root_dev.link.set_mtu(self.conf.network_device_mtu)
mtu = self.conf.network_device_mtu or mtu
if mtu:
ns_dev.link.set_mtu(mtu)
root_dev.link.set_mtu(mtu)
else:
LOG.warning(_LW("No MTU configured for port %s"), port_id)
if namespace:
namespace_obj = ip.ensure_namespace(namespace)
@ -474,7 +483,7 @@ class BridgeInterfaceDriver(LinuxInterfaceDriver):
DEV_NAME_PREFIX = 'ns-'
def plug_new(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
bridge=None, namespace=None, prefix=None, mtu=None):
"""Plugin the interface."""
ip = ip_lib.IPWrapper()
@ -487,9 +496,12 @@ class BridgeInterfaceDriver(LinuxInterfaceDriver):
root_veth.disable_ipv6()
ns_veth.link.set_address(mac_address)
if self.conf.network_device_mtu:
root_veth.link.set_mtu(self.conf.network_device_mtu)
ns_veth.link.set_mtu(self.conf.network_device_mtu)
mtu = self.conf.network_device_mtu or mtu
if mtu:
root_veth.link.set_mtu(mtu)
ns_veth.link.set_mtu(mtu)
else:
LOG.warning(_LW("No MTU configured for port %s"), port_id)
root_veth.link.set_up()
ns_veth.link.set_up()

View File

@ -253,6 +253,15 @@ class DHCPAgentOVSTestCase(DHCPAgentOVSTestFramework):
dhcp_enabled=dhcp_enabled)
self.assert_dhcp_resources(network, dhcp_enabled)
def test_agent_mtu_set_on_interface_driver(self):
network = self.network_dict_for_dhcp()
network["mtu"] = 789
self.configure_dhcp_for_network(network=network)
port = network.ports[0]
iface_name = self.get_interface_name(network, port)
dev = ip_lib.IPDevice(iface_name, network.namespace)
self.assertEqual(789, dev.link.mtu)
def test_good_address_allocation(self):
network, port = self._get_network_port_for_allocation_test()
network.ports.append(port)

View File

@ -1079,6 +1079,10 @@ class UnprivilegedUserGroupMetadataL3AgentTestCase(MetadataL3AgentTestCase):
class TestDvrRouter(L3AgentTestFramework):
def test_dvr_router_lifecycle_without_ha_with_snat_with_fips_nmtu(self):
self._dvr_router_lifecycle(enable_ha=False, enable_snat=True,
use_port_mtu=True)
def test_dvr_router_lifecycle_without_ha_without_snat_with_fips(self):
self._dvr_router_lifecycle(enable_ha=False, enable_snat=False)
@ -1130,7 +1134,7 @@ class TestDvrRouter(L3AgentTestFramework):
self._validate_fips_for_external_network(router2, fip2_ns)
def _dvr_router_lifecycle(self, enable_ha=False, enable_snat=False,
custom_mtu=2000):
custom_mtu=2000, use_port_mtu=False):
'''Test dvr router lifecycle
:param enable_ha: sets the ha value for the router.
@ -1142,11 +1146,18 @@ class TestDvrRouter(L3AgentTestFramework):
# Since by definition this is a dvr (distributed = true)
# only dvr and dvr_snat are applicable
self.agent.conf.agent_mode = 'dvr_snat' if enable_snat else 'dvr'
self.agent.conf.network_device_mtu = custom_mtu
# We get the router info particular to a dvr router
router_info = self.generate_dvr_router_info(
enable_ha, enable_snat, extra_routes=True)
if use_port_mtu:
for key in ('_interfaces', '_snat_router_interfaces',
'_floatingip_agent_interfaces'):
for port in router_info[key]:
port['mtu'] = custom_mtu
router_info['gw_port']['mtu'] = custom_mtu
else:
self.agent.conf.network_device_mtu = custom_mtu
# We need to mock the get_agent_gateway_port return value
# because the whole L3PluginApi is mocked and we need the port
@ -1165,6 +1176,11 @@ class TestDvrRouter(L3AgentTestFramework):
# manage the router (create it, create namespaces,
# attach interfaces, etc...)
router = self.manage_router(self.agent, router_info)
if enable_ha:
device = router.router[l3_constants.INTERFACE_KEY][-1]
name = router.get_internal_device_name(device['id'])
self.assertEqual(custom_mtu,
ip_lib.IPDevice(name, router.ns_name).link.mtu)
ext_gateway_port = router_info['gw_port']
self.assertTrue(self._namespace_exists(router.ns_name))

View File

@ -1291,7 +1291,8 @@ class TestDeviceManager(base.BaseTestCase):
port.id,
'tap12345678-12',
'aa:bb:cc:dd:ee:ff',
namespace=net.namespace))
namespace=net.namespace,
mtu=None))
self.mock_driver.assert_has_calls(expected)
dh._set_default_route.assert_called_once_with(net, 'tap12345678-12')

View File

@ -380,7 +380,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
sn_port['fixed_ips'],
sn_port['mac_address'],
ri._get_snat_int_device_name(sn_port['id']),
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
dvr_snat_ns.SNAT_INT_DEV_PREFIX,
mtu=None)
elif action == 'remove':
self.device_exists.return_value = False
ri.get_snat_port_for_internal_port = mock.Mock(

View File

@ -56,6 +56,23 @@ class FakePort(object):
network_id = network.id
class FakeInterfaceDriverNoMtu(interface.LinuxInterfaceDriver):
# NOTE(ihrachys) this method intentially omit mtu= parameter, since that
# was the method signature before Mitaka. We should make sure the old
# signature still works.
def __init__(self, *args, **kwargs):
super(FakeInterfaceDriverNoMtu, self).__init__(*args, **kwargs)
self.plug_called = False
def plug_new(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
self.plug_called = True
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
pass
class TestBase(base.BaseTestCase):
def setUp(self):
super(TestBase, self).setUp()
@ -69,6 +86,16 @@ class TestBase(base.BaseTestCase):
self.device_exists = self.device_exists_p.start()
class TestABCDriverNoMtu(TestBase):
def test_plug_with_no_mtu_works(self):
driver = FakeInterfaceDriverNoMtu(self.conf)
self.device_exists.return_value = False
driver.plug(
mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), mtu=9000)
self.assertTrue(driver.plug_called)
class TestABCDriver(TestBase):
def setUp(self):
super(TestABCDriver, self).setUp()

View File

@ -0,0 +1,20 @@
---
features:
- Use the value of the network 'mtu' attribute for the MTU
of virtual network interfaces such as veth pairs, patch
ports, and tap devices involving a particular network.
- Enable end-to-end support for arbitrary MTUs including
jumbo frames between instances and provider networks by
moving MTU disparities between flat or VLAN networks and
overlay networks from layer-2 devices to layer-3 devices
that support path MTU discovery (PMTUD).
upgrade:
- Does not change MTU for existing virtual network interfaces.
- Actions that create virtual network interfaces on an existing
network with the 'mtu' attribute containing a value greater
than zero could cause issues for network traffic traversing
existing and new virtual network interfaces.
fixes:
- Explicitly configure MTU of virtual network interfaces
rather than using default values or incorrect values that
do not account for overlay protocol overhead.