diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 12ec42d7f10d..a0eb22d192e4 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -37,6 +37,7 @@ import six from nova import exception from nova.i18n import _, _LE, _LW +from nova.network import model as network_model from nova import objects from nova import paths from nova.pci import utils as pci_utils @@ -1368,15 +1369,34 @@ def _ovs_vsctl(args): raise exception.AgentError(method=full_args) -def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, mtu=None): - _ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--', - 'add-port', bridge, dev, - '--', 'set', 'Interface', dev, - 'external-ids:iface-id=%s' % iface_id, - 'external-ids:iface-status=active', - 'external-ids:attached-mac=%s' % mac, - 'external-ids:vm-uuid=%s' % instance_id]) - _set_device_mtu(dev, mtu) +def _create_ovs_vif_cmd(bridge, dev, iface_id, mac, + instance_id, interface_type=None): + cmd = ['--', '--if-exists', 'del-port', dev, '--', + 'add-port', bridge, dev, + '--', 'set', 'Interface', dev, + 'external-ids:iface-id=%s' % iface_id, + 'external-ids:iface-status=active', + 'external-ids:attached-mac=%s' % mac, + 'external-ids:vm-uuid=%s' % instance_id] + if interface_type: + cmd += ['type=%s' % interface_type] + return cmd + + +def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, + mtu=None, interface_type=None): + _ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id, + mac, instance_id, + interface_type)) + # Note at present there is no support for setting the + # mtu for vhost-user type ports. + if interface_type != network_model.OVS_VHOSTUSER_INTERFACE_TYPE: + _set_device_mtu(dev, mtu) + else: + LOG.debug("MTU not set on %(interface_name)s interface " + "of type %(interface_type)s.", + {'interface_name': dev, + 'interface_type': interface_type}) def delete_ovs_vif_port(bridge, dev): @@ -1384,10 +1404,6 @@ def delete_ovs_vif_port(bridge, dev): delete_net_dev(dev) -def ovs_set_vhostuser_port_type(dev): - _ovs_vsctl(['--', 'set', 'Interface', dev, 'type=dpdkvhostuser']) - - def create_ivs_vif_port(dev, iface_id, mac, instance_id): utils.execute('ivs-ctl', 'add-port', dev, run_as_root=True) diff --git a/nova/network/model.py b/nova/network/model.py index c7376f862de1..c7979d7c2ac4 100644 --- a/nova/network/model.py +++ b/nova/network/model.py @@ -77,6 +77,8 @@ VIF_DETAILS_VHOSTUSER_SOCKET = 'vhostuser_socket' # Specifies whether vhost-user socket should be plugged # into ovs bridge. Valid values are True and False VIF_DETAILS_VHOSTUSER_OVS_PLUG = 'vhostuser_ovs_plug' +# ovs vhost user interface type name +OVS_VHOSTUSER_INTERFACE_TYPE = 'dpdkvhostuser' # Constants for dictionary keys in the 'vif_details' field that are # valid for VIF_TYPE_TAP. diff --git a/nova/tests/unit/network/test_linux_net.py b/nova/tests/unit/network/test_linux_net.py index a75dc100becb..26a531f2cad0 100644 --- a/nova/tests/unit/network/test_linux_net.py +++ b/nova/tests/unit/network/test_linux_net.py @@ -34,6 +34,7 @@ from nova import db from nova import exception from nova.network import driver from nova.network import linux_net +from nova.network import model as network_model from nova import objects from nova import test from nova import utils @@ -1210,13 +1211,37 @@ class LinuxNetworkTestCase(test.NoDBTestCase): linux_net._set_device_mtu('fake-dev') ex.assert_has_calls(calls) - def _ovs_vif_port(self, calls): + def _ovs_vif_port(self, calls, interface_type=None): with mock.patch.object(utils, 'execute', return_value=('', '')) as ex: linux_net.create_ovs_vif_port('fake-bridge', 'fake-dev', 'fake-iface-id', 'fake-mac', - 'fake-instance-uuid') + 'fake-instance-uuid', + interface_type=interface_type) ex.assert_has_calls(calls) + def test_ovs_vif_port_cmd(self): + expected = ['--', '--if-exists', + 'del-port', 'fake-dev', '--', 'add-port', + 'fake-bridge', 'fake-dev', + '--', 'set', 'Interface', 'fake-dev', + 'external-ids:iface-id=fake-iface-id', + 'external-ids:iface-status=active', + 'external-ids:attached-mac=fake-mac', + 'external-ids:vm-uuid=fake-instance-uuid' + ] + cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev', + 'fake-iface-id', 'fake-mac', + 'fake-instance-uuid') + + self.assertEqual(expected, cmd) + + expected += ['type=fake-type'] + cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev', + 'fake-iface-id', 'fake-mac', + 'fake-instance-uuid', + 'fake-type') + self.assertEqual(expected, cmd) + def test_ovs_vif_port(self): calls = [ mock.call('ovs-vsctl', '--timeout=120', '--', '--if-exists', @@ -1231,6 +1256,22 @@ class LinuxNetworkTestCase(test.NoDBTestCase): ] self._ovs_vif_port(calls) + @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): + linux_net.create_ovs_vif_port( + 'fake-bridge', + 'fake-dev', 'fake-iface-id', 'fake-mac', + "fake-instance-uuid", mtu=1500, + interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE) + mock_create_cmd.assert_called_once_with('fake-bridge', + 'fake-dev', 'fake-iface-id', 'fake-mac', + "fake-instance-uuid", network_model.OVS_VHOSTUSER_INTERFACE_TYPE) + self.assertFalse(mock_set_device_mtu.called) + self.assertTrue(mock_vsctl.called) + def test_ovs_vif_port_with_mtu(self): self.flags(network_device_mtu=10000) calls = [ @@ -1371,16 +1412,6 @@ class LinuxNetworkTestCase(test.NoDBTestCase): self.assertEqual(2, len(executes)) self.mox.UnsetStubs() - def test_ovs_set_vhostuser_type(self): - calls = [ - mock.call('ovs-vsctl', '--timeout=120', '--', 'set', - 'Interface', 'fake-dev', 'type=dpdkvhostuser', - run_as_root=True) - ] - with mock.patch.object(utils, 'execute', return_value=('', '')) as ex: - linux_net.ovs_set_vhostuser_port_type('fake-dev') - ex.assert_has_calls(calls) - @mock.patch('os.path.exists', return_value=True) @mock.patch('nova.utils.execute') def test_remove_bridge(self, mock_execute, mock_exists): diff --git a/nova/tests/unit/virt/libvirt/test_vif.py b/nova/tests/unit/virt/libvirt/test_vif.py index a9b4da225623..d7c18b615d72 100644 --- a/nova/tests/unit/virt/libvirt/test_vif.py +++ b/nova/tests/unit/virt/libvirt/test_vif.py @@ -1312,23 +1312,18 @@ class LibvirtVifTestCase(test.NoDBTestCase): def test_vhostuser_ovs_plug(self): calls = { - 'create_ovs_vif_port': [mock.call('br0', - 'usv-xxx-yyy-zzz', - 'aaa-bbb-ccc', - 'ca:fe:de:ad:be:ef', - 'instance-uuid', - 9000)], - 'ovs_set_vhostuser_port_type': [mock.call('usv-xxx-yyy-zzz')] + 'create_ovs_vif_port': [ + mock.call( + 'br0', 'usv-xxx-yyy-zzz', 'aaa-bbb-ccc', + 'ca:fe:de:ad:be:ef', 'instance-uuid', 9000, + interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE + )] } - with contextlib.nested( - mock.patch.object(linux_net, 'create_ovs_vif_port'), - mock.patch.object(linux_net, 'ovs_set_vhostuser_port_type') - ) as (create_ovs_vif_port, ovs_set_vhostuser_port_type): + with mock.patch.object(linux_net, + 'create_ovs_vif_port') as create_ovs_vif_port: d = vif.LibvirtGenericVIFDriver() d.plug_vhostuser(self.instance, self.vif_vhostuser_ovs) create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port']) - ovs_set_vhostuser_port_type.assert_has_calls( - calls['ovs_set_vhostuser_port_type']) def test_vhostuser_ovs_unplug(self): calls = { diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index f19dcf3e77db..54a445faefa8 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -675,10 +675,11 @@ class LibvirtGenericVIFDriver(object): port_name = os.path.basename( vif['details'][network_model.VIF_DETAILS_VHOSTUSER_SOCKET]) mtu = vif['network'].get_meta('mtu') - linux_net.create_ovs_vif_port(self.get_bridge_name(vif), - port_name, iface_id, vif['address'], - instance.uuid, mtu) - linux_net.ovs_set_vhostuser_port_type(port_name) + linux_net.create_ovs_vif_port( + self.get_bridge_name(vif), + port_name, iface_id, vif['address'], + instance.uuid, mtu, + interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE) def plug_vrouter(self, instance, vif): """Plug into Contrail's network port diff --git a/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml b/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml new file mode 100644 index 000000000000..642a7d231846 --- /dev/null +++ b/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - When plugging virtual interfaces of type vhost-user the MTU value will + not be applied to the interface by nova. vhost-user ports exist only in + userspace and are not backed by kernel netdevs, for this reason it is + not possible to set the mtu on a vhost-user interface using standard + tools such as ifconfig or ip link.