|
28 | 28 |
|
29 | 29 | import nova
|
30 | 30 | from nova import context
|
| 31 | +from nova import exception |
31 | 32 | from nova.network import constants
|
32 | 33 | from nova import objects
|
33 | 34 | from nova.objects import fields
|
@@ -1042,6 +1043,77 @@ def test_create_server_after_change_in_nonsriov_pf_to_sriov_pf(self):
|
1042 | 1043 | ],
|
1043 | 1044 | )
|
1044 | 1045 |
|
| 1046 | + def test_change_bound_port_vnic_type_kills_compute_at_restart(self): |
| 1047 | + """Create a server with a direct port and change the vnic_type of the |
| 1048 | + bound port to macvtap. Then restart the compute service. |
| 1049 | +
|
| 1050 | + As the vnic_type is changed on the port but the vif_type is hwveb |
| 1051 | + instead of macvtap the vif plug logic will try to look up the netdev |
| 1052 | + of the parent VF. Howvere that VF consumed by the instance so the |
| 1053 | + netdev does not exists. This causes that the compute service will fail |
| 1054 | + with an exception during startup |
| 1055 | + """ |
| 1056 | + pci_info = fakelibvirt.HostPCIDevicesInfo(num_pfs=1, num_vfs=2) |
| 1057 | + self.start_compute(pci_info=pci_info) |
| 1058 | + |
| 1059 | + # create a direct port |
| 1060 | + port = self.neutron.network_4_port_1 |
| 1061 | + self.neutron.create_port({'port': port}) |
| 1062 | + |
| 1063 | + # create a server using the VF via neutron |
| 1064 | + server = self._create_server(networks=[{'port': port['id']}]) |
| 1065 | + |
| 1066 | + # update the vnic_type of the port in neutron |
| 1067 | + port = copy.deepcopy(port) |
| 1068 | + port['binding:vnic_type'] = 'macvtap' |
| 1069 | + self.neutron.update_port(port['id'], {"port": port}) |
| 1070 | + |
| 1071 | + compute = self.computes['compute1'] |
| 1072 | + |
| 1073 | + # Force an update on the instance info cache to ensure nova gets the |
| 1074 | + # information about the updated port |
| 1075 | + with context.target_cell( |
| 1076 | + context.get_admin_context(), |
| 1077 | + self.host_mappings['compute1'].cell_mapping |
| 1078 | + ) as cctxt: |
| 1079 | + compute.manager._heal_instance_info_cache(cctxt) |
| 1080 | + |
| 1081 | + def fake_get_ifname_by_pci_address(pci_addr: str, pf_interface=False): |
| 1082 | + # we want to fail the netdev lookup only if the pci_address is |
| 1083 | + # already consumed by our instance. So we look into the instance |
| 1084 | + # definition to see if the device is attached to the instance as VF |
| 1085 | + conn = compute.manager.driver._host.get_connection() |
| 1086 | + dom = conn.lookupByUUIDString(server['id']) |
| 1087 | + dev = dom._def['devices']['nics'][0] |
| 1088 | + lookup_addr = pci_addr.replace(':', '_').replace('.', '_') |
| 1089 | + if ( |
| 1090 | + dev['type'] == 'hostdev' and |
| 1091 | + dev['source'] == 'pci_' + lookup_addr |
| 1092 | + ): |
| 1093 | + # nova tried to look up the netdev of an already consumed VF. |
| 1094 | + # So we have to fail |
| 1095 | + raise exception.PciDeviceNotFoundById(id=pci_addr) |
| 1096 | + |
| 1097 | + # We need to simulate the actual failure manually as in our functional |
| 1098 | + # environment all the PCI lookup is mocked. In reality nova tries to |
| 1099 | + # look up the netdev of the pci device on the host used by the port as |
| 1100 | + # the parent of the macvtap. However, as the originally direct port is |
| 1101 | + # bound to the instance, the VF pci device is already consumed by the |
| 1102 | + # instance and therefore there is no netdev for the VF. |
| 1103 | + self.libvirt.mock_get_ifname_by_pci_address.side_effect = ( |
| 1104 | + fake_get_ifname_by_pci_address |
| 1105 | + ) |
| 1106 | + # This is bug 1981813 as the compute service fails to start with an |
| 1107 | + # exception. |
| 1108 | + # Nova cannot prevent the vnic_type change on a bound port. Neutron |
| 1109 | + # should prevent that instead. But the nova-compute should still |
| 1110 | + # be able to start up and only log an ERROR for this instance in |
| 1111 | + # inconsistent state. |
| 1112 | + self.assertRaises( |
| 1113 | + exception.PciDeviceNotFoundById, |
| 1114 | + self.restart_compute_service, 'compute1' |
| 1115 | + ) |
| 1116 | + |
1045 | 1117 |
|
1046 | 1118 | class SRIOVAttachDetachTest(_PCIServersTestBase):
|
1047 | 1119 | # no need for aliases as these test will request SRIOV via neutron
|
|
0 commit comments