diff --git a/releasenotes/notes/vhost-user-mtu-support-cbc7d02a6665fab1.yaml b/releasenotes/notes/vhost-user-mtu-support-cbc7d02a6665fab1.yaml new file mode 100644 index 00000000..5d0ba181 --- /dev/null +++ b/releasenotes/notes/vhost-user-mtu-support-cbc7d02a6665fab1.yaml @@ -0,0 +1,10 @@ +--- +features: + - In the ocata cycle support was added for setting + the MTU of vhost-user port with ovs. + - vhost-user MTU support enable jumbo frames to + be used with vhost-user interfaces. +other: + - vhost-user MTU support requires ovs 2.6 or newer. + On older versions of ovs, the MTU request will + not be made and jumbo frames are not supported. diff --git a/vif_plug_ovs/linux_net.py b/vif_plug_ovs/linux_net.py index 87ff9aee..febc2c13 100644 --- a/vif_plug_ovs/linux_net.py +++ b/vif_plug_ovs/linux_net.py @@ -75,12 +75,12 @@ def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, _ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id, mac, instance_id, interface_type, vhost_server_path), timeout=timeout) - _update_device_mtu(dev, mtu, interface_type) + _update_device_mtu(dev, mtu, interface_type, timeout=timeout) @privsep.vif_plug.entrypoint -def update_ovs_vif_port(dev, mtu=None, interface_type=None): - _update_device_mtu(dev, mtu, interface_type) +def update_ovs_vif_port(dev, mtu=None, interface_type=None, timeout=None): + _update_device_mtu(dev, mtu, interface_type, timeout=timeout) @privsep.vif_plug.entrypoint @@ -168,13 +168,15 @@ def add_bridge_port(bridge, dev): processutils.execute('brctl', 'addif', bridge, dev) -def _update_device_mtu(dev, mtu, interface_type=None): - # Note at present there is no support for setting the - # mtu for vhost-user type ports. - if mtu and interface_type not in [ - constants.OVS_VHOSTUSER_INTERFACE_TYPE, - constants.OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE]: +def _update_device_mtu(dev, mtu, interface_type=None, timeout=120): + if not mtu: + return + if interface_type not in [ + constants.OVS_VHOSTUSER_INTERFACE_TYPE, + constants.OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE]: _set_device_mtu(dev, mtu) + elif _ovs_supports_mtu_requests(timeout=timeout): + _set_mtu_request(dev, mtu, timeout=timeout) else: LOG.debug("MTU not set on %(interface_name)s interface " "of type %(interface_type)s.", @@ -182,7 +184,25 @@ def _update_device_mtu(dev, mtu, interface_type=None): 'interface_type': interface_type}) +@privsep.vif_plug.entrypoint def _set_device_mtu(dev, mtu): """Set the device MTU.""" processutils.execute('ip', 'link', 'set', dev, 'mtu', mtu, check_exit_code=[0, 2, 254]) + + +@privsep.vif_plug.entrypoint +def _set_mtu_request(dev, mtu, timeout=None): + args = ['--', 'set', 'interface', dev, + 'mtu_request=%s' % mtu] + _ovs_vsctl(args, timeout=timeout) + + +@privsep.vif_plug.entrypoint +def _ovs_supports_mtu_requests(timeout=None): + args = ['--columns=mtu_request', 'list', 'interface'] + _, error = _ovs_vsctl(args, timeout=timeout) + if (error == 'ovs-vsctl: Interface does not contain' + + ' a column whose name matches "mtu_request"'): + return False + return True diff --git a/vif_plug_ovs/tests/test_linux_net.py b/vif_plug_ovs/tests/test_linux_net.py index 25a10b69..5afacfc3 100644 --- a/vif_plug_ovs/tests/test_linux_net.py +++ b/vif_plug_ovs/tests/test_linux_net.py @@ -157,11 +157,14 @@ class LinuxNetTest(testtools.TestCase): actual = linux_net._create_ovs_bridge_cmd(bridge, dp_type) self.assertEqual(expected, actual) + @mock.patch.object(linux_net, '_ovs_supports_mtu_requests') @mock.patch.object(linux_net, '_ovs_vsctl') @mock.patch.object(linux_net, '_create_ovs_vif_cmd') @mock.patch.object(linux_net, '_set_device_mtu') def test_ovs_vif_port_with_type_vhostuser(self, mock_set_device_mtu, - mock_create_cmd, mock_vsctl): + mock_create_cmd, mock_vsctl, + mock_ovs_supports_mtu_requests): + mock_ovs_supports_mtu_requests.return_value = True linux_net.create_ovs_vif_port( 'fake-bridge', 'fake-dev', 'fake-iface-id', 'fake-mac', @@ -174,11 +177,14 @@ class LinuxNetTest(testtools.TestCase): self.assertFalse(mock_set_device_mtu.called) self.assertTrue(mock_vsctl.called) + @mock.patch.object(linux_net, '_ovs_supports_mtu_requests') @mock.patch.object(linux_net, '_ovs_vsctl') @mock.patch.object(linux_net, '_create_ovs_vif_cmd') @mock.patch.object(linux_net, '_set_device_mtu') def test_ovs_vif_port_with_type_vhostuserclient(self, - mock_set_device_mtu, mock_create_cmd, mock_vsctl): + mock_set_device_mtu, mock_create_cmd, + mock_vsctl, mock_ovs_supports_mtu_requests): + mock_ovs_supports_mtu_requests.return_value = True linux_net.create_ovs_vif_port( 'fake-bridge', 'fake-dev', 'fake-iface-id', 'fake-mac', @@ -193,11 +199,14 @@ class LinuxNetTest(testtools.TestCase): self.assertFalse(mock_set_device_mtu.called) self.assertTrue(mock_vsctl.called) + @mock.patch.object(linux_net, '_ovs_supports_mtu_requests') @mock.patch.object(linux_net, '_ovs_vsctl') @mock.patch.object(linux_net, '_create_ovs_vif_cmd') @mock.patch.object(linux_net, '_set_device_mtu') def test_ovs_vif_port_with_no_mtu(self, mock_set_device_mtu, - mock_create_cmd, mock_vsctl): + mock_create_cmd, mock_vsctl, + mock_ovs_supports_mtu_requests): + mock_ovs_supports_mtu_requests.return_value = True linux_net.create_ovs_vif_port( 'fake-bridge', 'fake-dev', 'fake-iface-id', 'fake-mac', @@ -208,12 +217,18 @@ class LinuxNetTest(testtools.TestCase): self.assertFalse(mock_set_device_mtu.called) self.assertTrue(mock_vsctl.called) + @mock.patch.object(linux_net, '_ovs_supports_mtu_requests') + @mock.patch.object(linux_net, '_set_mtu_request') @mock.patch.object(linux_net, '_ovs_vsctl') @mock.patch.object(linux_net, '_create_ovs_vif_cmd', return_value='ovs_command') @mock.patch.object(linux_net, '_set_device_mtu') def test_ovs_vif_port_with_timeout(self, mock_set_device_mtu, - mock_create_cmd, mock_vsctl): + mock_create_cmd, mock_vsctl, + mock_set_mtu_request, + mock_ovs_supports_mtu_requests): + mock_ovs_supports_mtu_requests.return_value = True + linux_net.create_ovs_vif_port( 'fake-bridge', 'fake-dev', 'fake-iface-id', 'fake-mac', @@ -222,12 +237,17 @@ class LinuxNetTest(testtools.TestCase): self.assertFalse(mock_set_device_mtu.called) mock_vsctl.assert_called_with('ovs_command', timeout=42) + @mock.patch.object(linux_net, '_ovs_supports_mtu_requests') + @mock.patch.object(linux_net, '_set_mtu_request') @mock.patch.object(linux_net, '_ovs_vsctl') @mock.patch.object(linux_net, '_create_ovs_vif_cmd', return_value='ovs_command') @mock.patch.object(linux_net, '_set_device_mtu') def test_ovs_vif_port_with_no_timeout(self, mock_set_device_mtu, - mock_create_cmd, mock_vsctl): + mock_create_cmd, mock_vsctl, + mock_set_mtu_request, + mock_ovs_supports_mtu_requests): + mock_ovs_supports_mtu_requests.return_value = True linux_net.create_ovs_vif_port( 'fake-bridge', 'fake-dev', 'fake-iface-id', 'fake-mac', @@ -246,3 +266,30 @@ class LinuxNetTest(testtools.TestCase): [mock.call('ovs-vsctl', *args), mock.call('ovs-vsctl', '--timeout=%s' % timeout, *args)], mock_execute.mock_calls) + + @mock.patch.object(linux_net, '_ovs_vsctl') + def test_set_mtu_request(self, mock_vsctl): + dev = 'fake-dev' + mtu = 'fake-mtu' + timeout = 120 + linux_net._set_mtu_request(dev, mtu, timeout=timeout) + args = ['--', 'set', 'interface', dev, + 'mtu_request=%s' % mtu] + mock_vsctl.assert_called_with(args, timeout=timeout) + + @mock.patch.object(linux_net, '_ovs_vsctl') + def test_ovs_supports_mtu_requests(self, mock_vsctl): + args = ['--columns=mtu_request', 'list', 'interface'] + timeout = 120 + msg = 'ovs-vsctl: Interface does not contain' + \ + ' a column whose name matches "mtu_request"' + + mock_vsctl.return_value = (None, msg) + result = linux_net._ovs_supports_mtu_requests(timeout=timeout) + mock_vsctl.assert_called_with(args, timeout=timeout) + self.assertFalse(result) + + mock_vsctl.return_value = (None, None) + result = linux_net._ovs_supports_mtu_requests(timeout=timeout) + mock_vsctl.assert_called_with(args, timeout=timeout) + self.assertTrue(result)