From 77dee9505860be11c2b14c35d403fe2c49a0bcfd Mon Sep 17 00:00:00 2001 From: Sean Mooney Date: Thu, 11 Aug 2016 18:13:11 +0000 Subject: [PATCH] convert libvirt driver to use os-vif for vhost-user with ovs. - This change converts the libvirt vif driver to use os-vif for plug and unplug actions. Change-Id: I9e847046b8a18b7851e08d7367aad9d9feb4bec8 Blueprint: libvirt-os-vif-ovs-vhostuser --- nova/network/os_vif_util.py | 28 ++++++-- nova/tests/unit/network/test_os_vif_util.py | 79 +++++++++++++++++++++ nova/tests/unit/virt/libvirt/test_vif.py | 75 ++++++++++++------- nova/virt/libvirt/vif.py | 37 +++------- 4 files changed, 158 insertions(+), 61 deletions(-) diff --git a/nova/network/os_vif_util.py b/nova/network/os_vif_util.py index 6fd3bdb268..2ed3f7fadc 100644 --- a/nova/network/os_vif_util.py +++ b/nova/network/os_vif_util.py @@ -279,6 +279,29 @@ def _nova_to_osvif_vif_ovs(vif): return obj +# VIF_TYPE_VHOST_USER = 'vhostuser' +def _nova_to_osvif_vif_vhostuser(vif): + if vif['details'].get(model.VIF_DETAILS_VHOSTUSER_OVS_PLUG, False): + profile = objects.vif.VIFPortProfileOpenVSwitch( + interface_id=vif.get('ovs_interfaceid') or vif['id']) + obj = _get_vif_instance(vif, objects.vif.VIFVHostUser, + port_profile=profile, plugin="ovs") + if vif["network"]["bridge"] is not None: + obj.bridge_name = vif["network"]["bridge"] + obj.mode = vif['details'].get( + model.VIF_DETAILS_VHOSTUSER_MODE, 'server') + path = vif['details'].get( + model.VIF_DETAILS_VHOSTUSER_SOCKET, None) + if path: + obj.path = path + else: + raise exception.VifDetailsMissingVhostuserSockPath( + vif_id=vif['id']) + return obj + else: + raise NotImplementedError() + + # VIF_TYPE_IVS = 'ivs' def _nova_to_osvif_vif_ivs(vif): raise NotImplementedError() @@ -319,11 +342,6 @@ def _nova_to_osvif_vif_midonet(vif): raise NotImplementedError() -# VIF_TYPE_VHOSTUSER = 'vhostuser' -def _nova_to_osvif_vif_vhostuser(vif): - raise NotImplementedError() - - # VIF_TYPE_VROUTER = 'vrouter' def _nova_to_osvif_vif_vrouter(vif): raise NotImplementedError() diff --git a/nova/tests/unit/network/test_os_vif_util.py b/nova/tests/unit/network/test_os_vif_util.py index cb21f10ed7..e58509be99 100644 --- a/nova/tests/unit/network/test_os_vif_util.py +++ b/nova/tests/unit/network/test_os_vif_util.py @@ -546,6 +546,85 @@ class OSVIFUtilTestCase(test.NoDBTestCase): self.assertObjEqual(expect, actual) + def test_nova_to_osvif_vhostuser_ovs(self): + vif = model.VIF( + id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", + type=model.VIF_TYPE_VHOSTUSER, + address="22:52:25:62:e2:aa", + network=model.Network( + id="b82c1929-051e-481d-8110-4669916c7915", + label="Demo Net", + subnets=[]), + details={ + model.VIF_DETAILS_VHOSTUSER_MODE: 'client', + model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True, + model.VIF_DETAILS_VHOSTUSER_SOCKET: '/fake/socket', + model.VIF_DETAILS_PORT_FILTER: True + } + ) + + actual = os_vif_util.nova_to_osvif_vif(vif) + + expect = osv_objects.vif.VIFVHostUser( + id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", + active=False, + address="22:52:25:62:e2:aa", + plugin="ovs", + port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch( + interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536"), + vif_name="nicdc065497-3c", + path='/fake/socket', + mode='client', + has_traffic_filtering=True, + preserve_on_delete=False, + network=osv_objects.network.Network( + id="b82c1929-051e-481d-8110-4669916c7915", + bridge_interface=None, + label="Demo Net", + subnets=osv_objects.subnet.SubnetList( + objects=[]))) + + self.assertObjEqual(expect, actual) + + def test_nova_to_osvif_vhostuser_ovs_no_socket_path(self): + vif = model.VIF( + id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", + type=model.VIF_TYPE_VHOSTUSER, + address="22:52:25:62:e2:aa", + network=model.Network( + id="b82c1929-051e-481d-8110-4669916c7915", + label="Demo Net", + subnets=[]), + details={ + model.VIF_DETAILS_VHOSTUSER_MODE: 'client', + model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True, + model.VIF_DETAILS_PORT_FILTER: True + } + ) + + self.assertRaises(exception.VifDetailsMissingVhostuserSockPath, + os_vif_util.nova_to_osvif_vif, + vif) + + def test_nova_to_osvif_vhostuser_non_ovs(self): + vif = model.VIF( + id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", + active=False, + type=model.VIF_TYPE_VHOSTUSER, + address="22:52:25:62:e2:aa", + network=model.Network( + id="b82c1929-051e-481d-8110-4669916c7915", + label="Demo Net", + subnets=[]), + details={ + model.VIF_DETAILS_VHOSTUSER_MODE: 'client', + model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: False, + model.VIF_DETAILS_VHOSTUSER_SOCKET: '/fake/socket' + } + ) + + self.assertIsNone(os_vif_util.nova_to_osvif_vif(vif)) + def test_nova_to_osvif_vif_ivs_plain(self): vif = model.VIF( id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", diff --git a/nova/tests/unit/virt/libvirt/test_vif.py b/nova/tests/unit/virt/libvirt/test_vif.py index 729b62098f..0d02f057ff 100644 --- a/nova/tests/unit/virt/libvirt/test_vif.py +++ b/nova/tests/unit/virt/libvirt/test_vif.py @@ -40,6 +40,8 @@ from nova.virt.libvirt import vif CONF = cfg.CONF +MIN_LIBVIRT_VHOSTUSER_MQ = vif.MIN_LIBVIRT_VHOSTUSER_MQ + class LibvirtVifTestCase(test.NoDBTestCase): @@ -428,6 +430,16 @@ class LibvirtVifTestCase(test.NoDBTestCase): has_traffic_filtering=False, network=self.os_vif_network) + self.os_vif_vhostuser = osv_objects.vif.VIFVHostUser( + id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", + address="22:52:25:62:e2:aa", + plugin="openvswitch", + vif_name="vhudc065497-3c", + path='/var/run/openvswitch/vhudc065497-3c', + mode='client', + port_profile=self.os_vif_ovs_prof, + network=self.os_vif_network) + self.os_vif_inst_info = osv_objects.instance_info.InstanceInfo( uuid="d5b1090c-9e00-4fa4-9504-4b1494857970", name="instance-000004da", @@ -588,6 +600,42 @@ class LibvirtVifTestCase(test.NoDBTestCase): def test_virtio_multiqueue_in_kernel_4(self, mock_uname): self._test_virtio_multiqueue(10, '10') + @mock.patch.object(host.Host, "has_min_version") + def test_vhostuser_os_vif_multiqueue(self, has_min_version): + d = vif.LibvirtGenericVIFDriver() + hostimpl = host.Host("qemu:///system") + image_meta = objects.ImageMeta.from_dict( + {'properties': {'hw_vif_model': 'virtio', + 'hw_vif_multiqueue_enabled': 'true'}}) + flavor = objects.Flavor(name='m1.small', + memory_mb=128, + vcpus=4, + root_gb=0, + ephemeral_gb=0, + swap=0, + deleted_at=None, + deleted=0, + created_at=None, flavorid=1, + is_public=True, vcpu_weight=None, + id=2, disabled=False, rxtx_factor=1.0) + conf = d.get_base_config(None, 'ca:fe:de:ad:be:ef', image_meta, + flavor, 'kvm') + self.assertEqual(4, conf.vhost_queues) + self.assertEqual('vhost', conf.driver_name) + + has_min_version.return_value = True + d._set_config_VIFVHostUser(self.instance, self.os_vif_vhostuser, + conf, hostimpl) + self.assertEqual(4, conf.vhost_queues) + self.assertEqual('vhost', conf.driver_name) + has_min_version.assert_called_once_with(MIN_LIBVIRT_VHOSTUSER_MQ) + + has_min_version.return_value = False + d._set_config_VIFVHostUser(self.instance, self.os_vif_vhostuser, + conf, hostimpl) + self.assertEqual(None, conf.vhost_queues) + self.assertEqual(None, conf.driver_name) + def test_multiple_nics(self): conf = self._get_conf() # Tests multiple nic configuration and that target_dev is @@ -1321,33 +1369,6 @@ class LibvirtVifTestCase(test.NoDBTestCase): d.unplug(self.instance, self.vif_vhostuser_fp) mock_delete_fp_dev.assert_has_calls([mock.call('tap-xxx-yyy-zzz')]) - 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, - interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE - )] - } - with mock.patch.object(linux_net, - 'create_ovs_vif_port') as create_ovs_vif_port: - d = vif.LibvirtGenericVIFDriver() - d.plug(self.instance, self.vif_vhostuser_ovs) - create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port']) - - def test_vhostuser_ovs_unplug(self): - calls = { - 'delete_ovs_vif_port': [mock.call('br0', 'usv-xxx-yyy-zzz')] - } - with mock.patch.object(linux_net, - 'delete_ovs_vif_port') as delete_port: - d = vif.LibvirtGenericVIFDriver() - d.unplug(self.instance, self.vif_vhostuser_ovs) - delete_port.assert_has_calls(calls['delete_ovs_vif_port']) - def test_vhostuser_ovs_fp_plug(self): calls = { 'create_fp_dev': [mock.call('tap-xxx-yyy-zzz', diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 3422a8ecd7..de2ff6ceaa 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -445,6 +445,14 @@ class LibvirtGenericVIFDriver(object): conf.target_dev = vif.vif_name self._set_config_VIFPortProfile(instance, vif, conf) + def _set_config_VIFVHostUser(self, instance, vif, conf, host=None): + designer.set_vif_host_backend_vhostuser_config( + conf, vif.mode, vif.path) + if not host.has_min_version(MIN_LIBVIRT_VHOSTUSER_MQ): + LOG.debug('Queues are not a vhostuser supported feature.') + conf.driver_name = None + conf.vhost_queues = None + def _set_config_VIFPortProfileOpenVSwitch(self, profile, conf): conf.vporttype = "openvswitch" conf.add_vport_param("interfaceid", @@ -711,29 +719,12 @@ class LibvirtGenericVIFDriver(object): except processutils.ProcessExecutionError: LOG.exception(_LE("Failed while plugging vif"), instance=instance) - def plug_vhostuser_ovs(self, instance, vif): - """Plug a VIF_TYPE_VHOSTUSER into an ovs bridge""" - iface_id = self.get_ovs_interfaceid(vif) - 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, - interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE) - def plug_vhostuser(self, instance, vif): fp_plug = vif['details'].get( network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG, False) - ovs_plug = vif['details'].get( - network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG, - False) if fp_plug: self.plug_vhostuser_fp(instance, vif) - elif ovs_plug: - self.plug_vhostuser_ovs(instance, vif) def plug_vrouter(self, instance, vif): """Plug into Contrail's network port @@ -963,24 +954,12 @@ class LibvirtGenericVIFDriver(object): LOG.exception(_LE("Failed while unplugging vif"), instance=instance) - def unplug_vhostuser_ovs(self, instance, vif): - """Unplug a VIF_TYPE_VHOSTUSER into an ovs bridge""" - port_name = os.path.basename( - vif['details'][network_model.VIF_DETAILS_VHOSTUSER_SOCKET]) - linux_net.delete_ovs_vif_port(self.get_bridge_name(vif), - port_name) - def unplug_vhostuser(self, instance, vif): fp_plug = vif['details'].get( network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG, False) - ovs_plug = vif['details'].get( - network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG, - False) if fp_plug: self.unplug_vhostuser_fp(instance, vif) - elif ovs_plug: - self.unplug_vhostuser_ovs(instance, vif) def unplug_vrouter(self, instance, vif): """Unplug Contrail's network port -- 2.39.5