On Wed, Jun 24, 2026 at 10:06 PM Patrick Robb <[email protected]>
wrote:

>
>
> On Wed, Jun 24, 2026 at 5:33 PM Koushik Bhargav Nimoji <
> [email protected]> wrote:
>
>> 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
>> v3:
>>     *Fixed an issue with retrieving
>>      the NIC's hardware version
>> v4:
>>     *Moved nic info gathering step before the nics get
>>      binded to their respective drivers
>>     *Condensed some areas of code in order to make them
>>      more readable
>>     *Removed redundant None checks and added some where
>>      required
>>     *Fixed LshwOutput class to better reflect the lshw
>>      command output
>> ---
>>  dts/framework/test_run.py                    |  8 +++
>>  dts/framework/testbed_model/linux_session.py | 68 ++++++++++++++++++++
>>  dts/framework/testbed_model/os_session.py    | 11 ++++
>>  3 files changed, 87 insertions(+)
>>
>> diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
>> index 94dc6023a7..c92fe90f2e 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
>> @@ -347,6 +348,12 @@ def next(self) -> State | None:
>>          test_run.ctx.dpdk.setup()
>>          test_run.ctx.topology.setup()
>>
>> +        used_nic_info: list[dict[str, str]] =
>> self.test_run.ctx.sut_node.main_session.get_nic_info()
>>
>
> drop "used" for nic_info or change to testrun_nic_info?
>
>
>> +        with open(f"{SETTINGS.output_dir}/dut_info.json", "w") as file:
>> +            json.dump(used_nic_info, file, indent=3)
>> +
>> +        self.logger.info(f"DUT NIC info written to:
>> {SETTINGS.output_dir}/dut_info.json")
>> +
>>          if test_run.config.use_virtual_functions:
>>              test_run.ctx.topology.instantiate_vf_ports()
>>          if test_run.ctx.sut_node.cryptodevs and test_run.config.crypto:
>> @@ -370,6 +377,7 @@ 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
>>          )
>> +
>>          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 3a6e97974b..9e9146c372 100644
>> --- a/dts/framework/testbed_model/linux_session.py
>> +++ b/dts/framework/testbed_model/linux_session.py
>> @@ -38,6 +38,8 @@ class LshwConfigurationOutput(TypedDict):
>>      driver: str
>>      #:
>>      link: str
>> +    #:
>> +    firmware: str
>>
>>
>>  class LshwOutput(TypedDict):
>> @@ -61,6 +63,12 @@ class LshwOutput(TypedDict):
>>              ...
>>      """
>>
>> +    #:
>> +    vendor: NotRequired[str]
>> +    #:
>> +    product: NotRequired[str]
>> +    #:
>> +    version: NotRequired[str]
>>      #:
>>      businfo: str
>>      #:
>> @@ -197,6 +205,66 @@ 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, str]]:
>> +        """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: list[dict[str, str]] = []
>> +        for port in self._config.ports:
>> +            pci_addr = port.pci
>> +
>> +            command_result = self.send_command(
>>
>
> rename to lshw_result please.
>
>
>> +                f"sudo lshw -c network -businfo | grep '{pci_addr}' |
>> cut -d'@' -f1"
>> +            )
>> +            if command_result.return_code != 0 and command_result.stdout
>> == "":
>> +                raise ConfigurationError(f"Unable to get bus type for
>> port {pci_addr}.")
>> +            bus_type = command_result.stdout
>> +
>> +            bus_info = f"{bus_type}@{pci_addr}"
>> +            nic_port: LshwOutput | None = port_data[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["configuration"]
>> +            if config is None:
>> +                raise ConfigurationError(
>> +                    f"Configuration info for port {pci_addr} could not
>> be found on the node."
>> +                )
>> +
>> +            if "logicalname" not in nic_port:
>> +                raise ConfigurationError(
>> +                    f"Logical name for port {pci_addr} could not be
>> found on the node."
>> +                )
>> +
>> +            command_result = self.send_command(
>>
>
> ethtool_result
>
>
>> +                f"ethtool {nic_port['logicalname']} | grep 'Speed:' |
>> awk '{{print $2}}'"
>> +            )
>
> +            if command_result.return_code == 0 and command_result.stdout:
>> +                nic_speed = command_result.stdout
>> +            else:
>> +                self._logger.error(f"Unable to get speed for NIC:
>> {pci_addr}")
>> +                nic_speed = None
>> +
>> +            dut_json = {
>> +                "make": nic_port["vendor"] if "vendor" in nic_port else
>> "Unknown",
>> +                "model": nic_port["product"] if "product" in nic_port
>> else "Unknown",
>> +                "hardware version": nic_port["version"] if "version" in
>> nic_port else "Unknown",
>> +                "firmware version": config["firmware"] if "firmware" in
>> config else "Unknown",
>> +                "deviceBusType": bus_type,
>> +                "deviceId": nic_port["serial"] if "serial" in nic_port
>> else "Unknown",
>> +                "pmd": config["driver"] if "driver" in config else
>> "Unknown",
>> +                "speed": nic_speed or "Unknown",
>> +            }
>> +            all_nic_info.append(dut_json)
>> +
>> +        return all_nic_info
>> +
>>
>
> What is the intended behavior for cryptodev tests? I realize the ports
> list will be empty and we will not enter the initial loop, but is this
> intended? Do we want to gether cryptodev info too?
>
>
The intended behavior here is to skip cryptodev devices. Not entering the
initial loop, and therefore returning an empty list is the expected
behavior when running cryptodev tests.

>

>      def bind_ports_to_driver(self, ports: list[Port], driver_name: str)
>> -> None:
>>
>>
> Reviewed-by: Patrick Robb <[email protected]>
>

Reply via email to