From e57f66a26daf858d1348c8406108a33a323b7b2e Mon Sep 17 00:00:00 2001 From: Artom Lifshitz Date: Mon, 15 Jan 2018 15:52:11 -0500 Subject: [PATCH] Consider hostdev devices when building metadata Previously, device role tagging metadata would only be built for LibvirtConfigGuestInterface and LibvirtConfigGuestDisk. This didn't account for passed through PFs, which can also be tagged and appear as in the libvirt XML. This caused device role tagging to not work for PFs. This patch adds support for devices to _build_device_metadata. NOTE(artom): Conflicts in nova/tests/unit/virt/libvirt/test_driver.py due to trusted VFs not being present in Queens. Change-Id: I24e5ff1b446f2ac41d589c026ce8ee8adad4bcbc Closes-bug: 1743458 Closes-bug: 1694183 (cherry picked from commit abd01a757b8a83d714a6ab8b5085e7cc1b4a2c5c) --- nova/tests/unit/virt/libvirt/test_driver.py | 27 ++++++++++++-- nova/virt/libvirt/driver.py | 39 +++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index ebada5e865e6..d37c5a6983c0 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -1697,6 +1697,12 @@ class LibvirtConnTestCase(test.NoDBTestCase,
+ + +
+ + """ @@ -1750,24 +1756,32 @@ class LibvirtConnTestCase(test.NoDBTestCase, vif.instance_uuid = '32dfcb37-5af1-552b-357c-be8c3aa38310' vif.uuid = '12ec4b21-ef22-6c21-534b-ba3e3ab3a311' vif.tag = 'mytag1' + vif1 = obj_vif.VirtualInterface(context=self.context) vif1.address = '51:5a:2c:a4:5e:1b' vif1.network_id = 123 vif1.instance_uuid = '32dfcb37-5af1-552b-357c-be8c3aa38310' vif1.uuid = 'abec4b21-ef22-6c21-534b-ba3e3ab3a312' + vif2 = obj_vif.VirtualInterface(context=self.context) vif2.address = 'fa:16:3e:d1:28:e4' vif2.network_id = 123 vif2.instance_uuid = '32dfcb37-5af1-552b-357c-be8c3aa38310' vif2.uuid = '645686e4-7086-4eab-8c2f-c41f017a1b16' vif2.tag = 'mytag2' + vif3 = obj_vif.VirtualInterface(context=self.context) vif3.address = '52:54:00:14:6f:50' vif3.network_id = 123 vif3.instance_uuid = '32dfcb37-5af1-552b-357c-be8c3aa38310' vif3.uuid = '99cc3604-782d-4a32-a27c-bc33ac56ce86' vif3.tag = 'mytag3' - vifs = [vif, vif1, vif2, vif3] + + vif4 = obj_vif.VirtualInterface(context=self.context) + vif4.address = 'da:d1:f2:91:95:c1' + vif4.tag = 'pf_tag' + + vifs = [vif, vif1, vif2, vif3, vif4] network_info = _fake_network_info(self, 4) network_info[0]['vnic_type'] = network_model.VNIC_TYPE_DIRECT_PHYSICAL @@ -1784,11 +1798,13 @@ class LibvirtConnTestCase(test.NoDBTestCase, mock.patch('nova.virt.libvirt.host.Host.get_guest', return_value=guest), mock.patch.object(nova.virt.libvirt.guest.Guest, 'get_xml_desc', - return_value=xml)): + return_value=xml), + mock.patch.object(pci_utils, 'get_mac_by_pci_address', + return_value='da:d1:f2:91:95:c1')): metadata_obj = drvr._build_device_metadata(self.context, instance_ref) metadata = metadata_obj.devices - self.assertEqual(10, len(metadata)) + self.assertEqual(11, len(metadata)) self.assertIsInstance(metadata[0], objects.DiskMetadata) self.assertIsInstance(metadata[0].bus, @@ -1846,6 +1862,11 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(metadata[9], objects.NetworkInterfaceMetadata) self.assertEqual(['mytag3'], metadata[9].tags) + self.assertIsInstance(metadata[10], + objects.NetworkInterfaceMetadata) + self.assertEqual(['pf_tag'], metadata[10].tags) + self.assertEqual('da:d1:f2:91:95:c1', metadata[10].mac) + self.assertEqual('0000:06:00.1', metadata[10].bus.address) @mock.patch.object(host.Host, 'get_connection') @mock.patch.object(nova.virt.libvirt.guest.Guest, 'get_xml_desc') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 404a096171d7..907abe73274a 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -8675,6 +8675,42 @@ class LibvirtDriver(driver.ComputeDriver): device.bus = bus return device + def _build_hostdev_metadata(self, dev, vifs_to_expose, vlans_by_mac): + """Builds a metadata object for a hostdev. This can only be a PF, so we + don't need trusted_by_mac like in _build_interface_metadata because + only VFs can be trusted. + + :param dev: The LibvirtConfigGuestHostdevPCI to build metadata for. + :param vifs_to_expose: The list of tagged and/or vlan'ed + VirtualInterface objects. + :param vlans_by_mac: A dictionary of mac address -> vlan associations. + :return: A NetworkInterfaceMetadata object, or None. + """ + # Strip out the leading '0x' + pci_address = pci_utils.get_pci_address( + *[x[2:] for x in (dev.domain, dev.bus, dev.slot, dev.function)]) + try: + mac = pci_utils.get_mac_by_pci_address(pci_address, + pf_interface=True) + except exception.PciDeviceNotFoundById: + LOG.debug('Not exposing metadata for not found PCI device %s', + pci_address) + return None + + vif = vifs_to_expose.get(mac) + if not vif: + LOG.debug('No VIF found with MAC %s, not building metadata', mac) + return None + + device = objects.NetworkInterfaceMetadata(mac=mac) + device.bus = objects.PCIDeviceBus(address=pci_address) + if 'tag' in vif and vif.tag: + device.tags = [vif.tag] + vlan = vlans_by_mac.get(mac) + if vlan: + device.vlan = int(vlan) + return device + def _build_device_metadata(self, context, instance): """Builds a metadata object for instance devices, that maps the user provided tag to the hypervisor assigned device address. @@ -8710,6 +8746,9 @@ class LibvirtDriver(driver.ComputeDriver): vlans_by_mac) if isinstance(dev, vconfig.LibvirtConfigGuestDisk): device = self._build_disk_metadata(dev, tagged_bdms) + if isinstance(dev, vconfig.LibvirtConfigGuestHostdevPCI): + device = self._build_hostdev_metadata(dev, vifs_to_expose, + vlans_by_mac) if device: devices.append(device) if devices: