diff --git a/lisa/microsoft/testsuites/core/provisioning.py b/lisa/microsoft/testsuites/core/provisioning.py index da2015e108..c67124ceff 100644 --- a/lisa/microsoft/testsuites/core/provisioning.py +++ b/lisa/microsoft/testsuites/core/provisioning.py @@ -635,8 +635,10 @@ def check_sriov(self, log: Logger, node: RemoteNode) -> None: else: pci_nic_check = True if pci_nic_check: - log.info(f"check_sriov: PCI nic count {len(node_nic_info.get_pci_nics())}") - assert_that(len(node_nic_info.get_pci_nics())).described_as( - f"VF count inside VM is {len(node_nic_info.get_pci_nics())}, " - f"actual sriov nic count is {sriov_count}" + pci_nics = node_nic_info.get_pci_nics_except_ib() + pci_nic_count = len(pci_nics) + log.info(f"check_sriov: PCI nic count (without IB) {pci_nic_count}") + assert_that(pci_nic_count).described_as( + f"VF count inside VM (without IB) is {pci_nic_count}, " + f"actual sriov nic count is {sriov_count}. " ).is_equal_to(sriov_count) diff --git a/lisa/microsoft/testsuites/network/common.py b/lisa/microsoft/testsuites/network/common.py index f2824103e5..4bb8225d96 100644 --- a/lisa/microsoft/testsuites/network/common.py +++ b/lisa/microsoft/testsuites/network/common.py @@ -1,6 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. -from typing import Dict, List, cast +from typing import Dict, List, Tuple, cast from assertpy import assert_that from retry import retry @@ -53,9 +53,11 @@ def initialize_nic_info( f"inside vm, it should equal to {interface_info.ip_addr}." ).is_true() if is_sriov: - assert_that(len(nics_info.get_device_slots())).described_as( - f"VF count inside VM is {len(set(nics_info.get_device_slots()))}, " - f"actual sriov nic count is {sriov_count}" + pci_nic_count = len(nics_info.get_pci_nics_except_ib()) + assert_that(pci_nic_count).described_as( + f"Ethernet VF count inside VM (without IB) is {pci_nic_count}, " + f"actual sriov nic count is {sriov_count}. " + f"Total PCI NICs: {nics_info.get_pci_nics()}" ).is_equal_to(sriov_count) vm_nics[node.name] = nics_info.nics @@ -70,12 +72,14 @@ def sriov_basic_test(environment: Environment) -> None: devices_slots = lspci.get_device_names_by_type( constants.DEVICE_TYPE_SRIOV, force_run=True ) - if len(devices_slots) != len(set(node.nics.get_device_slots())): + ethernet_device_slots = set(node.nics.get_device_slots_except_ib()) + if len(devices_slots) != len(ethernet_device_slots): node.nics.reload() + ethernet_device_slots = set(node.nics.get_device_slots_except_ib()) assert_that(devices_slots).described_as( "count of sriov devices listed from lspci is not expected," " please check the driver works properly" - ).is_length(len(set(node.nics.get_device_slots()))) + ).is_length(len(ethernet_device_slots)) # 2. Check module of sriov network device is loaded. for module_name in node.nics.get_used_modules(["hv_netvsc"]): @@ -172,7 +176,7 @@ def _find_matching_dest_nic( source_nic_info: NicInfo, vm_nics: Dict[str, Dict[str, NicInfo]], dest_node: RemoteNode, -) -> tuple[str, int]: +) -> Tuple[str, int]: """Find destination NIC on same subnet as source. Returns (nic_name, skipped_count).""" skipped_infiniband = 0 @@ -198,7 +202,7 @@ def _setup_nic_monitoring( remove_module: bool, turn_off_lower: bool, source_node: RemoteNode, -) -> tuple[str, str, str, str]: +) -> Tuple[str, str, str, str]: """Setup NIC monitoring based on configuration. Returns (source_nic, dest_nic, source_pci_nic, dest_pci_nic).""" source_synthetic_nic = source_nic_info.name diff --git a/lisa/microsoft/testsuites/network/sriov.py b/lisa/microsoft/testsuites/network/sriov.py index 97be2e0cbe..59ed5ebe15 100644 --- a/lisa/microsoft/testsuites/network/sriov.py +++ b/lisa/microsoft/testsuites/network/sriov.py @@ -2,7 +2,7 @@ # Licensed under the MIT license. import re from pathlib import Path -from typing import Any, Dict, List, cast +from typing import Any, Dict, List, Optional, cast from assertpy import assert_that from microsoft.testsuites.network.common import ( @@ -811,6 +811,9 @@ def verify_sriov_interrupts_change(self, environment: Environment) -> None: client_interrupt_inspector = client_node.tools[InterruptInspector] for _, client_nic_info in vm_nics[client_node.name].items(): if client_nic_info.is_pci_module_enabled: + # Skip InfiniBand interfaces — they use RDMA, not Ethernet SR-IOV + if client_nic_info.name and client_nic_info.name.startswith("ib"): + continue # 2. Get initial interrupts sum per irq and cpu number on client node. # only collect 'Completion Queue Interrupts' irqs initial_pci_interrupts_by_irqs = ( @@ -834,8 +837,13 @@ def verify_sriov_interrupts_change(self, environment: Environment) -> None: assert_that(len(initial_pci_interrupts_by_cpus)).described_as( "initial cpu count of interrupts should be equal to cpu count" ).is_equal_to(client_thread_count) - matched_server_nic_info: NicInfo + matched_server_nic_info: Optional[NicInfo] = None for _, server_nic_info in vm_nics[server_node.name].items(): + # Skip NICs without IP addresses (IB, enslaved VFs, etc.) + if not server_nic_info.ip_addr: + continue + if server_nic_info.name and server_nic_info.name.startswith("ib"): + continue if ( server_nic_info.ip_addr.rsplit(".", maxsplit=1)[0] == client_nic_info.ip_addr.rsplit(".", maxsplit=1)[0] diff --git a/lisa/microsoft/testsuites/network/stress.py b/lisa/microsoft/testsuites/network/stress.py index 2fef8bee3c..a1e1381767 100644 --- a/lisa/microsoft/testsuites/network/stress.py +++ b/lisa/microsoft/testsuites/network/stress.py @@ -1,6 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. -from typing import Any, cast +from typing import Any, Optional, cast from assertpy import assert_that from microsoft.testsuites.network.common import ( @@ -73,15 +73,20 @@ def stress_sriov_iperf(self, environment: Environment) -> None: client_nic_info_list = [ x for _, x in vm_nics[client_node.name].items() - if x.ip_addr == client_node.internal_address + if x.ip_addr and x.ip_addr == client_node.internal_address ] assert_that(client_nic_info_list).described_as( "not found the primary network interface." - ).is_not_none() + ).is_not_empty() client_nic_info = client_nic_info_list[0] isinstance(client_nic_info, NicInfo) - matched_server_nic_info: NicInfo + matched_server_nic_info: Optional[NicInfo] = None for _, server_nic_info in vm_nics[server_node.name].items(): + # Skip InfiniBand and NICs without IP addresses + if not server_nic_info.ip_addr: + continue + if server_nic_info.name and server_nic_info.name.startswith("ib"): + continue if ( server_nic_info.ip_addr.rsplit(".", maxsplit=1)[0] == client_nic_info.ip_addr.rsplit(".", maxsplit=1)[0] diff --git a/lisa/microsoft/testsuites/performance/common.py b/lisa/microsoft/testsuites/performance/common.py index 6805b89969..46c9a4df97 100644 --- a/lisa/microsoft/testsuites/performance/common.py +++ b/lisa/microsoft/testsuites/performance/common.py @@ -928,7 +928,9 @@ def check_sriov_count(node: RemoteNode, sriov_count: int) -> None: node_nic_info = node.nics node_nic_info.reload() - assert_that(len(node_nic_info.get_pci_nics())).described_as( - f"VF count inside VM is {len(node_nic_info.get_pci_nics())}," - f"actual sriov nic count is {sriov_count}" + pci_nics = node_nic_info.get_pci_nics_except_ib() + pci_nic_count = len(pci_nics) + assert_that(pci_nic_count).described_as( + f"VF count inside VM (without IB) is {pci_nic_count}, " + f"actual sriov nic count is {sriov_count}. " ).is_equal_to(sriov_count) diff --git a/lisa/nic.py b/lisa/nic.py index 7e91a99396..908a3573f8 100644 --- a/lisa/nic.py +++ b/lisa/nic.py @@ -185,6 +185,23 @@ def get_synthetic_devices(self) -> List[str]: self._node.log.debug(f"Found synthetic devices: {synthetic_devices}") return synthetic_devices + def get_pci_nics_except_ib(self) -> List[str]: + """ + Get NIC names for PCI-associated NICs, excluding InfiniBand (ib*) + """ + pci_nics = [] + for nic in self.nics.values(): + nic_name = nic.lower if nic.lower else nic.name + if nic_name and nic_name.startswith("ib"): + continue + if nic.name and nic.name.startswith("ib"): + continue + if nic.is_pci_only_nic: + pci_nics.append(nic.name) + elif nic.lower: + pci_nics.append(nic.lower) + return pci_nics + def get_pci_nics(self) -> List[str]: pci_nics = [] for nic in self.nics.values(): @@ -221,6 +238,20 @@ def get_used_modules(self, exclude_module_name: List[str]) -> List[str]: def get_device_slots(self) -> List[str]: return [x.pci_slot for x in self.nics.values() if x.pci_slot] + def get_device_slots_except_ib(self) -> List[str]: + """Get PCI slots for NICs, excluding InfiniBand (ib*) interfaces.""" + slots = [] + for nic in self.nics.values(): + if not nic.pci_slot: + continue + nic_name = nic.lower if nic.lower else nic.name + if nic_name and nic_name.startswith("ib"): + continue + if nic.name and nic.name.startswith("ib"): + continue + slots.append(nic.pci_slot) + return slots + def _get_nics_driver(self) -> None: for nic in [x.name for x in self.nics.values()]: self.get_nic_driver(nic) @@ -405,7 +436,7 @@ def _get_nic_uuid(self, nic_name: str) -> str: readlink = self._node.tools[Readlink] full_dev_path = readlink.get_target(f"/sys/class/net/{nic_name}/device") uuid = os.path.basename(full_dev_path) - self._node.log.debug(f"{nic_name} UUID:{uuid}") + self._node.log.debug(f"{nic_name} UUID: {uuid}") return uuid def _get_nic_uuids(self) -> None: diff --git a/lisa/tools/lspci.py b/lisa/tools/lspci.py index 0d4be6d5f3..63c6018273 100644 --- a/lisa/tools/lspci.py +++ b/lisa/tools/lspci.py @@ -412,7 +412,7 @@ def get_pci_slot_from_device_path(self, device_path: str) -> Optional[str]: """ Extract PCI slot information from a device path. """ - pci_slot = get_matched_str(device_path, PATTERN_PCI_SLOT) + pci_slot = get_matched_str(device_path, PATTERN_PCI_SLOT, first_match=False) return pci_slot if pci_slot else None