From 17ba10b75961ef667e45b9dedbac34212a7e7e9b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 18 Aug 2020 11:25:49 +0100 Subject: [PATCH] functional: Add test for SR-IOV neutron ports Add a simple test to demonstrate the interaction between nova and neutron when creating an instance with a (pre-created) SR-IOV port. Change-Id: I9d0596f31ca342b952c35c742befd75fdc39d95c Signed-off-by: Stephen Finucane --- nova/tests/functional/libvirt/base.py | 14 ++-- .../libvirt/test_pci_sriov_servers.py | 65 ++++++++++++++++++- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/nova/tests/functional/libvirt/base.py b/nova/tests/functional/libvirt/base.py index 9fe5bdba13e3..f24add011ea3 100644 --- a/nova/tests/functional/libvirt/base.py +++ b/nova/tests/functional/libvirt/base.py @@ -321,12 +321,9 @@ class LibvirtNeutronFixture(nova_fixtures.NeutronFixture): 'subnet_id': subnet_4['id'] } ], - 'binding:vif_details': {'vlan': 42}, 'binding:vif_type': 'hw_veb', + 'binding:vif_details': {'vlan': 42}, 'binding:vnic_type': 'direct', - 'binding:profile': {'pci_vendor_info': '1377:0047', - 'pci_slot': '0000:81:00.1', - 'physical_network': 'physnet4'}, } def __init__(self, test): @@ -357,6 +354,15 @@ class LibvirtNeutronFixture(nova_fixtures.NeutronFixture): # network_2_port_1 below at the update call port = copy.deepcopy(port) port.update(body['port']) + + # the tenant ID is normally extracted from credentials in the request + # and is not present in the body + if 'tenant_id' not in port: + port['tenant_id'] = nova_fixtures.NeutronFixture.tenant_id + + # similarly, these attributes are set by neutron itself + port['admin_state_up'] = True + self._ports[port['id']] = port # this copy is here as nova sometimes modifies the returned port # locally and we want to avoid that nova modifies the fixture internals diff --git a/nova/tests/functional/libvirt/test_pci_sriov_servers.py b/nova/tests/functional/libvirt/test_pci_sriov_servers.py index e661c67266c9..ffab7c8473fd 100644 --- a/nova/tests/functional/libvirt/test_pci_sriov_servers.py +++ b/nova/tests/functional/libvirt/test_pci_sriov_servers.py @@ -74,6 +74,7 @@ class SRIOVServersTest(_PCIServersTestBase): { 'vendor_id': fakelibvirt.PCI_VEND_ID, 'product_id': fakelibvirt.VF_PROD_ID, + 'physical_network': 'physnet4', }, )] # PFs will be removed from pools unless they are specifically @@ -168,12 +169,74 @@ class SRIOVServersTest(_PCIServersTestBase): flavor_id=flavor_id_pfs, networks='none', expected_state='ERROR', ) + def test_create_server_with_neutron(self): + """Create an instance using a neutron-provisioned SR-IOV VIF.""" + + pci_info = fakelibvirt.HostPCIDevicesInfo(num_pfs=1, num_vfs=2) + + orig_create = nova.virt.libvirt.guest.Guest.create + + def fake_create(cls, xml, host): + tree = etree.fromstring(xml) + elem = tree.find('./devices/interface/source/address') + + # compare address + expected = ('0x81', '0x00', '0x2') + actual = ( + elem.get('bus'), elem.get('slot'), elem.get('function'), + ) + self.assertEqual(expected, actual) + + return orig_create(xml, host) + + self.stub_out( + 'nova.virt.libvirt.guest.Guest.create', + fake_create, + ) + + self.start_compute(pci_info=pci_info) + + # create the port + self.neutron.create_port({'port': self.neutron.network_4_port_1}) + + # ensure the binding details are currently unset + port = self.neutron.show_port( + base.LibvirtNeutronFixture.network_4_port_1['id'], + )['port'] + self.assertNotIn('binding:profile', port) + + # create a server using the VF via neutron + flavor_id = self._create_flavor() + self._create_server( + flavor_id=flavor_id, + networks=[ + {'port': base.LibvirtNeutronFixture.network_4_port_1['id']}, + ], + ) + + # ensure the binding details sent to "neutron" were correct + port = self.neutron.show_port( + base.LibvirtNeutronFixture.network_4_port_1['id'], + )['port'] + self.assertIn('binding:profile', port) + self.assertEqual( + { + 'pci_vendor_info': '8086:1515', + 'pci_slot': '0000:81:00.2', + 'physical_network': 'physnet4', + }, + port['binding:profile'], + ) + def test_get_server_diagnostics_server_with_VF(self): """Ensure server disagnostics include info on VF-type PCI devices.""" pci_info = fakelibvirt.HostPCIDevicesInfo() self.start_compute(pci_info=pci_info) + # create the SR-IOV port + self.neutron.create_port({'port': self.neutron.network_4_port_1}) + # create a server using the VF and multiple networks extra_spec = {'pci_passthrough:alias': f'{self.VFS_ALIAS_NAME}:1'} flavor_id = self._create_flavor(extra_spec=extra_spec) @@ -181,7 +244,7 @@ class SRIOVServersTest(_PCIServersTestBase): flavor_id=flavor_id, networks=[ {'uuid': base.LibvirtNeutronFixture.network_1['id']}, - {'uuid': base.LibvirtNeutronFixture.network_4['id']}, + {'port': base.LibvirtNeutronFixture.network_4_port_1['id']}, ], )