This patch gathers NIC info during a DTS run and writes it to an output json file. This allows the json file to be used when reporting results on the DTS results dashboard.
Signed-off-by: Koushik Bhargav Nimoji <[email protected]> --- v2: *Resolved merge conflicts --- dts/framework/test_run.py | 10 +++ dts/framework/testbed_model/linux_session.py | 75 ++++++++++++++++++++ dts/framework/testbed_model/os_session.py | 11 +++ 3 files changed, 96 insertions(+) diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py index 94dc6023a7..eebea280d7 100644 --- a/dts/framework/test_run.py +++ b/dts/framework/test_run.py @@ -98,6 +98,7 @@ "InternalError" -> "exit":ew """ +import json import random from collections import deque from collections.abc import Iterable @@ -370,6 +371,15 @@ def next(self) -> State | None: test_run.supported_capabilities = get_supported_capabilities( test_run.ctx.sut_node, test_run.ctx.topology, test_run.required_capabilities ) + + used_nic_info: list[dict[str, object]] = ( + self.test_run.ctx.sut_node.main_session.get_nic_info() + ) + with open(f"{SETTINGS.output_dir}/dut_info.json", "w") as file: + json.dump(used_nic_info, file, indent=3) + file.close() + self.logger.info(f"DUT NIC info written to: {SETTINGS.output_dir}/dut_info.json") + return TestRunExecution(test_run, self.result) def on_error(self, ex: BaseException) -> State | None: diff --git a/dts/framework/testbed_model/linux_session.py b/dts/framework/testbed_model/linux_session.py index 30c89ad70d..5f4b78cf1c 100644 --- a/dts/framework/testbed_model/linux_session.py +++ b/dts/framework/testbed_model/linux_session.py @@ -197,6 +197,81 @@ def unbind_ports(self, ports: list[Port]): if self._lshw_net_info: del self._lshw_net_info + def get_nic_info(self) -> list[dict[str, object]]: + """Overrides :meth`~.os_session.OSSession.get_nic_info`. + + Raises: + ConfigurationError: If the NIC info could not be found. + """ + port_data = { + port.get("businfo"): port for port in self._lshw_net_info if port.get("businfo") + } + + all_nic_info = [] + for port in self._config.ports: + pci_addr = port.pci + + command_result = self.send_command( + f"sudo lshw -c network -businfo | grep '{pci_addr}' | cut -d'@' -f1" + ) + bus_type = ( + command_result.stdout + if command_result.return_code == 0 and command_result.stdout + else None + ) + if bus_type is None: + raise ConfigurationError(f"Unable to get bus type for port {pci_addr}.") + bus_info = f"{bus_type}@{pci_addr}" + + nic_port: LshwOutput | None = port_data.get(bus_info) + if nic_port is None: + raise ConfigurationError(f"Port {pci_addr} could not be found on the node.") + + config: LshwConfigurationOutput | None = nic_port.get("configuration") + if config is None: + raise ConfigurationError( + f"Configuration info for port {pci_addr} could not be found on the node." + ) + + command_result = self.send_command( + f"sudo lspci -vv -s {pci_addr} | grep 'Engineering changes'" + ) + hardware_version = ( + command_result.stdout.split(":")[-1].strip() + if command_result.return_code == 0 and command_result.stdout + else None + ) + if hardware_version is None: + self._logger.error(f"Unable to get hardware version for NIC: {pci_addr}") + + nic_name = nic_port.get("logicalname") + nic_speed = None + if nic_name is not None: + command_result = self.send_command( + f"ethtool {nic_name} | grep 'Speed:' | awk '{{print $2}}'" + ) + nic_speed = ( + command_result.stdout + if command_result.return_code == 0 and command_result.stdout + else None + ) + if nic_speed is None: + self._logger.error(f"Unable to get speed for NIC: {pci_addr}") + + dut_json = { + "make": nic_port.get("vendor"), + "model": nic_port.get("product"), + "hardware version": hardware_version or "Unknown", + "firmware version": config.get("firmware"), + "deviceBusType": bus_type, + "deviceId": nic_port.get("serial"), + "pmd": config.get("driver"), + "speed": nic_speed or "Unknown", + } + all_nic_info.append(dut_json) + + return all_nic_info + def bind_ports_to_driver(self, ports: list[Port], driver_name: str) -> None: """Overrides :meth:`~.os_session.OSSession.bind_ports_to_driver`. diff --git a/dts/framework/testbed_model/os_session.py b/dts/framework/testbed_model/os_session.py index f2dc9b20a9..a16ba50045 100644 --- a/dts/framework/testbed_model/os_session.py +++ b/dts/framework/testbed_model/os_session.py @@ -581,6 +581,17 @@ def unbind_ports(self, ports: list[Port]) -> None: ports: The list of ports to unbind. """ + @abstractmethod + def get_nic_info(self) -> list[dict[str, object]]: + """Get NIC information. + + Returns: + NIC info as a list of dictionaries. + + Raises: + ConfigurationError: If the NIC info could not be found. + """ + @abstractmethod def bind_ports_to_driver(self, ports: list[Port], driver_name: str) -> None: """Bind `ports` to the given `driver_name`. -- 2.54.0

