[PATCH v1] dts: report dut/NIC info during DTS run
Koushik Bhargav Nimoji
knimoji at iol.unh.edu
Tue Jun 2 18:36:47 CEST 2026
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 <knimoji at iol.unh.edu>
---
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 ee943462c2..2269fe60ae 100644
--- a/dts/framework/testbed_model/linux_session.py
+++ b/dts/framework/testbed_model/linux_session.py
@@ -181,6 +181,81 @@ def get_port_info(self, pci_address: str) -> PortInfo:
return PortInfo(mac_address, logical_name, driver, is_link_up)
+ 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 2c267afed1..4d5ba0e7f6 100644
--- a/dts/framework/testbed_model/os_session.py
+++ b/dts/framework/testbed_model/os_session.py
@@ -573,6 +573,17 @@ def get_port_info(self, pci_address: str) -> PortInfo:
ConfigurationError: If the port could not be found.
"""
+ @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
More information about the dev
mailing list