summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Mooney <sean.k.mooney@intel.com>2016-01-22 17:00:36 +0000
committerMatt Riedemann <mriedem@us.ibm.com>2016-03-22 11:54:12 -0400
commitc7eb823fe73e3db5dca48df5879db18cbab5bd8d (patch)
tree9d5c8e4425b8c93b3a82925d12f29661fd7a2d0a
parentce6dbea46c4c5b01a6907e90dd427a49ec453131 (diff)
downloadnova-c7eb823fe73e3db5dca48df5879db18cbab5bd8d.tar.gz
stop setting mtu when plugging vhost-user ports
vhost-user is a userspace protocol to establish connectivity between a virto-net frontend typically qemu and a userspace virtio backend such as ovs with dpdk. vhost-user interfaces exist only in userspace from the host perspective and are not represented in the linux networking stack as kernel netdevs. As a result attempting to set the mtu on a vhost-user interface using ifconfig or ip link will fail with a device not found error. - this change removes a call to _set_device_mtu when plugging vhost-user interfaces. - this change prevents the device not found error from occurring which stopped vms booting with vhost-user interfaces due to an uncaught exception resulting in a failure to set the interface type in ovs. - this change make creating vhost-user interface an atomic action. This latent bug is only triggered when the mtu value is set to a value other than 0 which was the default proir to mitaka. Change-Id: I2e17723d5052d57cd1557bd8a173c06ea0dcb2d4 Closes-Bug: #1533876 (cherry picked from commit adf7ba61dd73fe4bfffa20295be9a4b1006a1fe6)
-rw-r--r--nova/network/linux_net.py42
-rw-r--r--nova/network/model.py2
-rw-r--r--nova/tests/unit/network/test_linux_net.py55
-rw-r--r--nova/tests/unit/virt/libvirt/test_vif.py21
-rw-r--r--nova/virt/libvirt/vif.py9
-rw-r--r--releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml7
6 files changed, 95 insertions, 41 deletions
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index e2f40ff3cb..40064a05de 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
@@ -1365,15 +1366,34 @@ def _ovs_vsctl(args):
raise exception.OvsConfigurationFailure(inner_exception=e)
-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, delete_dev=True):
@@ -1382,10 +1402,6 @@ def delete_ovs_vif_port(bridge, dev, delete_dev=True):
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 b28bc37aa9..8088ee8805 100644
--- a/nova/network/model.py
+++ b/nova/network/model.py
@@ -80,6 +80,8 @@ VIF_DETAILS_VHOSTUSER_OVS_PLUG = 'vhostuser_ovs_plug'
# Specifies whether vhost-user socket should be used to
# create a fp netdevice interface.
VIF_DETAILS_VHOSTUSER_FP_PLUG = 'vhostuser_fp_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 2cbe02b4d3..8b35656d32 100644
--- a/nova/tests/unit/network/test_linux_net.py
+++ b/nova/tests/unit/network/test_linux_net.py
@@ -33,6 +33,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
@@ -1216,13 +1217,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',
@@ -1237,6 +1262,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 = [
@@ -1377,16 +1418,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 bf33eab910..6f48247b62 100644
--- a/nova/tests/unit/virt/libvirt/test_vif.py
+++ b/nova/tests/unit/virt/libvirt/test_vif.py
@@ -1313,22 +1313,19 @@ 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',
- 'f0000000-0000-0000-0000-000000000001',
- 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',
+ 'f0000000-0000-0000-0000-000000000001', 9000,
+ interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE
+ )]
}
- with test.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 ec05a53e74..576c0ae5a4 100644
--- a/nova/virt/libvirt/vif.py
+++ b/nova/virt/libvirt/vif.py
@@ -677,10 +677,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_vhostuser(self, instance, vif):
fp_plug = vif['details'].get(
diff --git a/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml b/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml
new file mode 100644
index 0000000000..642a7d2318
--- /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.