Merge "Update MTU on existing devices"
This commit is contained in:
commit
14079d0f21
|
@ -46,6 +46,11 @@ OPTS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_veth(name1, name2, namespace2):
|
||||||
|
return (ip_lib.IPDevice(name1),
|
||||||
|
ip_lib.IPDevice(name2, namespace=namespace2))
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class LinuxInterfaceDriver(object):
|
class LinuxInterfaceDriver(object):
|
||||||
|
|
||||||
|
@ -54,6 +59,7 @@ class LinuxInterfaceDriver(object):
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
self._mtu_update_warn_logged = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def use_gateway_ips(self):
|
def use_gateway_ips(self):
|
||||||
|
@ -262,6 +268,11 @@ class LinuxInterfaceDriver(object):
|
||||||
bridge, namespace, prefix)
|
bridge, namespace, prefix)
|
||||||
else:
|
else:
|
||||||
LOG.info(_LI("Device %s already exists"), device_name)
|
LOG.info(_LI("Device %s already exists"), device_name)
|
||||||
|
if mtu:
|
||||||
|
self.set_mtu(
|
||||||
|
device_name, mtu, namespace=namespace, prefix=prefix)
|
||||||
|
else:
|
||||||
|
LOG.warning(_LW("No MTU configured for port %s"), port_id)
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
|
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
|
||||||
|
@ -284,6 +295,12 @@ class LinuxInterfaceDriver(object):
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def set_mtu(self, device_name, mtu, namespace=None, prefix=None):
|
||||||
|
"""Set MTU on the interface."""
|
||||||
|
if not self._mtu_update_warn_logged:
|
||||||
|
LOG.warning(_LW("Interface driver cannot update MTU for ports"))
|
||||||
|
self._mtu_update_warn_logged = True
|
||||||
|
|
||||||
|
|
||||||
class NullDriver(LinuxInterfaceDriver):
|
class NullDriver(LinuxInterfaceDriver):
|
||||||
def plug_new(self, network_id, port_id, device_name, mac_address,
|
def plug_new(self, network_id, port_id, device_name, mac_address,
|
||||||
|
@ -369,9 +386,7 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
|
||||||
# allow to set MTU that is higher than the least of all device MTUs on
|
# allow to set MTU that is higher than the least of all device MTUs on
|
||||||
# the bridge
|
# the bridge
|
||||||
if mtu:
|
if mtu:
|
||||||
ns_dev.link.set_mtu(mtu)
|
self.set_mtu(device_name, mtu, namespace=namespace, prefix=prefix)
|
||||||
if self.conf.ovs_use_veth:
|
|
||||||
root_dev.link.set_mtu(mtu)
|
|
||||||
else:
|
else:
|
||||||
LOG.warning(_LW("No MTU configured for port %s"), port_id)
|
LOG.warning(_LW("No MTU configured for port %s"), port_id)
|
||||||
|
|
||||||
|
@ -398,6 +413,16 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
|
||||||
LOG.error(_LE("Failed unplugging interface '%s'"),
|
LOG.error(_LE("Failed unplugging interface '%s'"),
|
||||||
device_name)
|
device_name)
|
||||||
|
|
||||||
|
def set_mtu(self, device_name, mtu, namespace=None, prefix=None):
|
||||||
|
if self.conf.ovs_use_veth:
|
||||||
|
tap_name = self._get_tap_name(device_name, prefix)
|
||||||
|
root_dev, ns_dev = _get_veth(
|
||||||
|
tap_name, device_name, namespace2=namespace)
|
||||||
|
root_dev.link.set_mtu(mtu)
|
||||||
|
else:
|
||||||
|
ns_dev = ip_lib.IPWrapper(namespace=namespace).device(device_name)
|
||||||
|
ns_dev.link.set_mtu(mtu)
|
||||||
|
|
||||||
|
|
||||||
class IVSInterfaceDriver(LinuxInterfaceDriver):
|
class IVSInterfaceDriver(LinuxInterfaceDriver):
|
||||||
"""Driver for creating an internal interface on an IVS bridge."""
|
"""Driver for creating an internal interface on an IVS bridge."""
|
||||||
|
@ -478,8 +503,7 @@ class BridgeInterfaceDriver(LinuxInterfaceDriver):
|
||||||
ns_veth.link.set_address(mac_address)
|
ns_veth.link.set_address(mac_address)
|
||||||
|
|
||||||
if mtu:
|
if mtu:
|
||||||
root_veth.link.set_mtu(mtu)
|
self.set_mtu(device_name, mtu, namespace=namespace, prefix=prefix)
|
||||||
ns_veth.link.set_mtu(mtu)
|
|
||||||
else:
|
else:
|
||||||
LOG.warning(_LW("No MTU configured for port %s"), port_id)
|
LOG.warning(_LW("No MTU configured for port %s"), port_id)
|
||||||
|
|
||||||
|
@ -495,3 +519,11 @@ class BridgeInterfaceDriver(LinuxInterfaceDriver):
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
LOG.error(_LE("Failed unplugging interface '%s'"),
|
LOG.error(_LE("Failed unplugging interface '%s'"),
|
||||||
device_name)
|
device_name)
|
||||||
|
|
||||||
|
def set_mtu(self, device_name, mtu, namespace=None, prefix=None):
|
||||||
|
tap_name = device_name.replace(prefix or self.DEV_NAME_PREFIX,
|
||||||
|
constants.TAP_DEVICE_PREFIX)
|
||||||
|
root_dev, ns_dev = _get_veth(
|
||||||
|
tap_name, device_name, namespace2=namespace)
|
||||||
|
root_dev.link.set_mtu(mtu)
|
||||||
|
ns_dev.link.set_mtu(mtu)
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import testtools
|
import testtools
|
||||||
|
@ -21,15 +23,63 @@ from neutron.agent.linux import ip_lib
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
from neutron.tests.common import net_helpers
|
from neutron.tests.common import net_helpers
|
||||||
from neutron.tests.functional.agent.linux import base
|
from neutron.tests.functional.agent.linux import base as linux_base
|
||||||
|
from neutron.tests.functional import base
|
||||||
|
|
||||||
|
|
||||||
class OVSInterfaceDriverTestCase(base.BaseOVSLinuxTestCase):
|
class InterfaceDriverTestCaseMixin(object):
|
||||||
|
def _test_mtu_set_after_action(self, device_name, br_name, namespace,
|
||||||
|
action=None):
|
||||||
|
mac_address = utils.get_random_mac('fa:16:3e:00:00:00'.split(':'))
|
||||||
|
|
||||||
|
plug = functools.partial(
|
||||||
|
self.interface.plug,
|
||||||
|
network_id=uuidutils.generate_uuid(),
|
||||||
|
port_id=uuidutils.generate_uuid(),
|
||||||
|
device_name=device_name,
|
||||||
|
mac_address=mac_address,
|
||||||
|
bridge=self.bridge_name,
|
||||||
|
namespace=namespace)
|
||||||
|
plug(mtu=1500)
|
||||||
|
self.assertTrue(ip_lib.device_exists(device_name, namespace))
|
||||||
|
|
||||||
|
action = action or plug
|
||||||
|
for mtu in (1450, 1500, 9000, 9000, 1450):
|
||||||
|
action(mtu=mtu)
|
||||||
|
self.assertEqual(
|
||||||
|
mtu,
|
||||||
|
ip_lib.IPDevice(device_name, namespace=namespace).link.mtu)
|
||||||
|
|
||||||
|
def test_plug_multiple_calls_update_mtu(self):
|
||||||
|
device_name = utils.get_rand_name()
|
||||||
|
namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
||||||
|
|
||||||
|
self._test_mtu_set_after_action(
|
||||||
|
device_name, self.bridge_name, namespace)
|
||||||
|
|
||||||
|
def test_set_mtu(self):
|
||||||
|
device_name = utils.get_rand_name()
|
||||||
|
namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
||||||
|
|
||||||
|
self._test_mtu_set_after_action(
|
||||||
|
device_name, self.bridge_name, namespace,
|
||||||
|
functools.partial(
|
||||||
|
self.interface.set_mtu,
|
||||||
|
device_name=device_name, namespace=namespace))
|
||||||
|
|
||||||
|
|
||||||
|
class OVSInterfaceDriverTestCase(linux_base.BaseOVSLinuxTestCase,
|
||||||
|
InterfaceDriverTestCaseMixin):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(OVSInterfaceDriverTestCase, self).setUp()
|
super(OVSInterfaceDriverTestCase, self).setUp()
|
||||||
conf = cfg.ConfigOpts()
|
conf = cfg.ConfigOpts()
|
||||||
conf.register_opts(interface.OPTS)
|
conf.register_opts(interface.OPTS)
|
||||||
self.interface = interface.OVSInterfaceDriver(conf)
|
self.interface = interface.OVSInterfaceDriver(conf)
|
||||||
|
self.bridge = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bridge_name(self):
|
||||||
|
return self.bridge.br_name
|
||||||
|
|
||||||
def test_plug_checks_if_bridge_exists(self):
|
def test_plug_checks_if_bridge_exists(self):
|
||||||
with testtools.ExpectedException(exceptions.BridgeDoesNotExist):
|
with testtools.ExpectedException(exceptions.BridgeDoesNotExist):
|
||||||
|
@ -44,50 +94,45 @@ class OVSInterfaceDriverTestCase(base.BaseOVSLinuxTestCase):
|
||||||
device_name = utils.get_rand_name()
|
device_name = utils.get_rand_name()
|
||||||
mac_address = utils.get_random_mac('fa:16:3e:00:00:00'.split(':'))
|
mac_address = utils.get_random_mac('fa:16:3e:00:00:00'.split(':'))
|
||||||
namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
||||||
bridge = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
|
|
||||||
|
|
||||||
self.assertFalse(bridge.get_port_name_list())
|
self.assertFalse(self.bridge.get_port_name_list())
|
||||||
self.interface.plug(network_id=uuidutils.generate_uuid(),
|
self.interface.plug(network_id=uuidutils.generate_uuid(),
|
||||||
port_id=uuidutils.generate_uuid(),
|
port_id=uuidutils.generate_uuid(),
|
||||||
device_name=device_name,
|
device_name=device_name,
|
||||||
mac_address=mac_address,
|
mac_address=mac_address,
|
||||||
bridge=bridge.br_name,
|
bridge=self.bridge.br_name,
|
||||||
namespace=namespace)
|
namespace=namespace)
|
||||||
self.assertIn(device_name, bridge.get_port_name_list())
|
self.assertIn(device_name, self.bridge.get_port_name_list())
|
||||||
self.assertTrue(ip_lib.device_exists(device_name, namespace))
|
self.assertTrue(ip_lib.device_exists(device_name, namespace))
|
||||||
|
|
||||||
def test_plug_with_namespace_sets_mtu_higher_than_bridge(self):
|
def test_plug_with_namespace_sets_mtu_higher_than_bridge(self):
|
||||||
device_mtu = 1450
|
# First, add a new linuxbridge port with reduced MTU to OVS bridge
|
||||||
|
|
||||||
# Create a new OVS bridge
|
|
||||||
ovs_bridge = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
|
|
||||||
self.assertFalse(ovs_bridge.get_port_name_list())
|
|
||||||
|
|
||||||
# Add a new linuxbridge port with reduced MTU to OVS bridge
|
|
||||||
lb_bridge = self.useFixture(
|
lb_bridge = self.useFixture(
|
||||||
net_helpers.LinuxBridgeFixture()).bridge
|
net_helpers.LinuxBridgeFixture()).bridge
|
||||||
lb_bridge_port = self.useFixture(
|
lb_bridge_port = self.useFixture(
|
||||||
net_helpers.LinuxBridgePortFixture(lb_bridge))
|
net_helpers.LinuxBridgePortFixture(lb_bridge))
|
||||||
lb_bridge_port.port.link.set_mtu(device_mtu - 1)
|
lb_bridge_port.port.link.set_mtu(1400)
|
||||||
ovs_bridge.add_port(lb_bridge_port.port.name)
|
self.bridge.add_port(lb_bridge_port.port.name)
|
||||||
|
|
||||||
|
device_name = utils.get_rand_name()
|
||||||
|
namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
||||||
|
|
||||||
# Now plug a device with intended MTU that is higher than for the port
|
# Now plug a device with intended MTU that is higher than for the port
|
||||||
# above and validate that its MTU is not reduced to the least MTU on
|
# above and validate that its MTU is not reduced to the least MTU on
|
||||||
# the bridge
|
# the bridge
|
||||||
device_name = utils.get_rand_name()
|
self._test_mtu_set_after_action(
|
||||||
mac_address = utils.get_random_mac('fa:16:3e:00:00:00'.split(':'))
|
device_name, self.bridge_name, namespace)
|
||||||
namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
|
||||||
self.interface.plug(network_id=uuidutils.generate_uuid(),
|
|
||||||
port_id=uuidutils.generate_uuid(),
|
|
||||||
device_name=device_name,
|
|
||||||
mac_address=mac_address,
|
|
||||||
bridge=ovs_bridge.br_name,
|
|
||||||
namespace=namespace,
|
|
||||||
mtu=device_mtu)
|
|
||||||
|
|
||||||
self.assertIn(device_name, ovs_bridge.get_port_name_list())
|
|
||||||
self.assertTrue(ip_lib.device_exists(device_name, namespace))
|
class BridgeInterfaceDriverTestCase(base.BaseSudoTestCase,
|
||||||
self.assertEqual(
|
InterfaceDriverTestCaseMixin):
|
||||||
device_mtu,
|
def setUp(self):
|
||||||
ip_lib.IPDevice(device_name, namespace=namespace).link.mtu
|
super(BridgeInterfaceDriverTestCase, self).setUp()
|
||||||
)
|
conf = cfg.ConfigOpts()
|
||||||
|
conf.register_opts(interface.OPTS)
|
||||||
|
self.interface = interface.BridgeInterfaceDriver(conf)
|
||||||
|
self.bridge = self.useFixture(net_helpers.LinuxBridgeFixture()).bridge
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bridge_name(self):
|
||||||
|
return self.bridge.name
|
||||||
|
|
|
@ -364,6 +364,12 @@ class TestABCDriver(TestBase):
|
||||||
[mock.call(device_name, namespace=ns),
|
[mock.call(device_name, namespace=ns),
|
||||||
mock.call().addr.list(scope='link', ip_version=6)])
|
mock.call().addr.list(scope='link', ip_version=6)])
|
||||||
|
|
||||||
|
def test_set_mtu_logs_once(self):
|
||||||
|
bc = BaseChild(self.conf)
|
||||||
|
with mock.patch('neutron.agent.linux.interface.LOG.warning') as log:
|
||||||
|
bc.set_mtu('dev', 9999)
|
||||||
|
log.assert_called_once_with(mock.ANY)
|
||||||
|
|
||||||
|
|
||||||
class TestOVSInterfaceDriver(TestBase):
|
class TestOVSInterfaceDriver(TestBase):
|
||||||
|
|
||||||
|
@ -447,6 +453,8 @@ class TestOVSInterfaceDriver(TestBase):
|
||||||
mock.call().ensure_namespace().add_device_to_namespace(
|
mock.call().ensure_namespace().add_device_to_namespace(
|
||||||
mock.ANY)])
|
mock.ANY)])
|
||||||
expected.extend([
|
expected.extend([
|
||||||
|
mock.call(namespace=namespace),
|
||||||
|
mock.call().device('tap0'),
|
||||||
mock.call().device().link.set_mtu(9000),
|
mock.call().device().link.set_mtu(9000),
|
||||||
mock.call().device().link.set_up(),
|
mock.call().device().link.set_up(),
|
||||||
])
|
])
|
||||||
|
@ -496,6 +504,10 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):
|
||||||
root_dev = mock.Mock()
|
root_dev = mock.Mock()
|
||||||
ns_dev = mock.Mock()
|
ns_dev = mock.Mock()
|
||||||
self.ip().add_veth = mock.Mock(return_value=(root_dev, ns_dev))
|
self.ip().add_veth = mock.Mock(return_value=(root_dev, ns_dev))
|
||||||
|
mock.patch.object(
|
||||||
|
interface, '_get_veth',
|
||||||
|
return_value=(root_dev, ns_dev)).start()
|
||||||
|
|
||||||
expected = [mock.call(),
|
expected = [mock.call(),
|
||||||
mock.call().add_veth('tap0', devname,
|
mock.call().add_veth('tap0', devname,
|
||||||
namespace2=namespace)]
|
namespace2=namespace)]
|
||||||
|
@ -558,6 +570,9 @@ class TestBridgeInterfaceDriver(TestBase):
|
||||||
ns_veth = mock.Mock()
|
ns_veth = mock.Mock()
|
||||||
|
|
||||||
self.ip().add_veth = mock.Mock(return_value=(root_veth, ns_veth))
|
self.ip().add_veth = mock.Mock(return_value=(root_veth, ns_veth))
|
||||||
|
mock.patch.object(
|
||||||
|
interface, '_get_veth',
|
||||||
|
return_value=(root_veth, ns_veth)).start()
|
||||||
|
|
||||||
self.device_exists.side_effect = device_exists
|
self.device_exists.side_effect = device_exists
|
||||||
br = interface.BridgeInterfaceDriver(self.conf)
|
br = interface.BridgeInterfaceDriver(self.conf)
|
||||||
|
|
Loading…
Reference in New Issue