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
<hostdev> in the libvirt XML. This caused device role tagging to not
work for PFs. This patch adds support for <hostdev> devices to
_build_device_metadata.

Change-Id: I24e5ff1b446f2ac41d589c026ce8ee8adad4bcbc
Closes-bug: 1743458
Closes-bug: 1694183
This commit is contained in:
Artom Lifshitz 2018-01-15 15:52:11 -05:00
parent d16d0d553b
commit abd01a757b
2 changed files with 63 additions and 3 deletions

View File

@ -1620,6 +1620,12 @@ class LibvirtConnTestCase(test.NoDBTestCase,
<alias name='net0'/>
<address type='ccw' cssid='0xfe' ssid='0x0' devno='0x0001'/>
</interface>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address bus="0x06" domain="0x0000" function="0x1"
slot="0x00"/>
</source>
</hostdev>
</devices>
</domain>"""
@ -1673,24 +1679,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
@ -1708,11 +1722,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,
@ -1774,6 +1790,11 @@ class LibvirtConnTestCase(test.NoDBTestCase,
objects.NetworkInterfaceMetadata)
self.assertEqual(['mytag3'], metadata[9].tags)
self.assertFalse(metadata[9].vf_trusted)
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')

View File

@ -8609,6 +8609,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.
@ -8646,6 +8682,9 @@ class LibvirtDriver(driver.ComputeDriver):
trusted_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: