[RFC PATCH] dts: resolve trex driver binding issue

Luca Vizzarro Luca.Vizzarro at arm.com
Fri Oct 16 18:28:04 CEST 2026


Hi Koushik,

Apologies for the long wait. To start off, could you please address the 
AI Code Review as it raised a few concerns:

http://mails.dpdk.org/archives/test-report/2026-August/1029040.html

The patch will also require rebasing.

On 11/08/2026 19:55, Koushik Bhargav Nimoji wrote:
> diff --git a/dts/framework/test_result.py b/dts/framework/test_result.py
> index 21faa55dc1..13ed8f671c 100644
> --- a/dts/framework/test_result.py
> +++ b/dts/framework/test_result.py
> @@ -117,6 +117,7 @@ class ResultNode(BaseModel):
>       label: str
>       children: list[Union["ResultNode", ResultLeaf]] = Field(default_factory=list)
>       parent: Union["ResultNode", None] = None
> +    ports: list[dict[str, str]] | None = None

This attribute lacks the appropriate documentation. Also unless I missed 
something, I am not sure how this belongs to this patch. Can you please 
clarify?

>   
>       def add_child(self, label: str) -> "ResultNode":
>           """Creates and append a child node to the model.
> diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
> index c20a0fa885..b23930b953 100644
> --- a/dts/framework/test_run.py
> +++ b/dts/framework/test_run.py
> @@ -115,7 +115,7 @@
>   from framework.remote_session.dpdk import DPDKBuildEnvironment, DPDKRuntimeEnvironment
>   from framework.settings import SETTINGS
>   from framework.test_result import Result, ResultNode, TestRunResult
> -from framework.test_suite import BaseConfig, TestCase, TestCaseType, TestSuite
> +from framework.test_suite import BaseConfig, TestCase, TestCaseType, TestSuite, TestSuiteType
>   from framework.testbed_model.capability import (
>       Capability,
>       get_supported_capabilities,
> @@ -375,11 +375,6 @@ def next(self) -> State | None:
>               ctx.topology.bind_cryptodevs("dpdk")
>   
>           ctx.topology.configure_ports("sut", "dpdk")
> -        if ctx.func_tg and ctx.topology.type is not LinkTopology.NO_LINK:
> -            ctx.func_tg.setup(ctx.topology)
> -        if ctx.perf_tg and ctx.topology.type is not LinkTopology.NO_LINK:
> -            ctx.perf_tg.setup(ctx.topology)
> -
>           self.result.ports = [
>               port.to_dict() for port in ctx.topology.sut_ports + ctx.topology.tg_ports
>           ]
> @@ -506,12 +501,34 @@ class TestSuiteSetup(TestSuiteState):
>       """Test suite setup."""
>   
>       logger_name: ClassVar[str] = "test_suite_setup"
> +    test_run: TestRun

Unsure why this is necessary, given it's already inherited by 
TestSuiteState.

>   
>       def before(self) -> None:
>           """Hook before the state is processed."""
>           super().before()
>           self.logger.set_custom_log_file(self.test_suite.name)
>   
> +        ctx = self.test_run.ctx
> +        testsuite_type = self.test_suite.testsuite_type

nit: stick to the snake case, so test_suite_type

> +        if (
> +            ctx.topology.type is not LinkTopology.NO_LINK
> +            and testsuite_type is not TestSuiteType.CRYPTO
> +        ):
> +            if testsuite_type == TestSuiteType.FUNC:
> +                required_tg, other_tg = ctx.func_tg, ctx.perf_tg
> +            else:
> +                required_tg, other_tg = ctx.perf_tg, ctx.func_tg
> +
> +            if other_tg and other_tg.is_setup:
> +                other_tg.teardown()
> +
> +                if testsuite_type == TestSuiteType.FUNC and ctx.tg_node:
> +                    for port in ctx.topology.tg_ports:
> +                        ctx.tg_node.main_session.bind_ports_to_driver([port], port.config.os_driver)

I am a bit confused why this happens here. The driver to be bound to 
should be governed by the TG that uses such ports. Could be os_driver, 
could be dpdk_driver, regardless of Scapy and TRex.

> +
> +            if required_tg and not required_tg.is_setup:
> +                required_tg.setup(ctx.topology)
> +
>       @property
>       def description(self) -> str:
>           """State description."""
> diff --git a/dts/framework/test_suite.py b/dts/framework/test_suite.py
> index 69ce26040a..554fe3a475 100644
> --- a/dts/framework/test_suite.py
> +++ b/dts/framework/test_suite.py
> @@ -45,6 +45,17 @@ class BaseConfig(FrozenModel):
>       """Base for a custom test suite configuration."""
>   
>   
> +class TestSuiteType(Enum):
> +    """Enum to specify test suite type."""
> +
> +    FUNC = auto()
> +    PERF = auto()
> +    CRYPTO = auto()
> +
> +
> +TestSuiteClassType = TypeVar("TestSuiteClassType", bound=type["TestSuite"])
> +
> +
>   class TestSuite(TestProtocol):
>       """The base class with building blocks needed by most test cases.
>   
> @@ -85,6 +96,30 @@ class TestSuite(TestProtocol):
>       _sut_ip_address_egress: Union[IPv4Interface, IPv6Interface]
>       _tg_ip_address_ingress: Union[IPv4Interface, IPv6Interface]
>       _tg_ip_address_egress: Union[IPv4Interface, IPv6Interface]
> +    testsuite_type: ClassVar[TestSuiteType]
nit: snake_case
> +
> +    @classmethod
> +    def make_decorator(
> +        cls, testsuite_type: TestSuiteType
nit: snake_case
> +    ) -> Callable[[TestSuiteClassType], TestSuiteClassType]:
> +        """Creates a decorator for test suites.
> +
> +        The decorator casts the decorated function as :class:`TestSuite`,
> +        sets it as `testsuite_type` and initializes a variable to
> +        determine the type of test suite.
> +
> +        Args:
> +            testsuite_type: A functional, performance, or cryptodev test suite.
nit: snake_case
> +
> +        Returns:
> +            The decorator of a functional, performance, or cryptodev test suite.
> +        """
> +
> +        def _decorator(testsuite_cls: TestSuiteClassType) -> TestSuiteClassType:
> +            testsuite_cls.testsuite_type = testsuite_type
> +            return testsuite_cls
nit: snake_case
> +
> +        return _decorator

So the above function doesn't really use cls, making it a @static_method 
instead of a @class_method. Given static_method is discouraged, it 
ultimately means that this method should rather be a module-level 
function. But I do understand that we'd also prefer to have consistency 
and this is already done for TestCase. So I am ok with either.

>   
>       def __init__(self, config: BaseConfig) -> None:
>           """Initialize the test suite testbed information and basic configuration.
> @@ -270,6 +305,11 @@ def _adjust_addresses(self, packets: list[Packet], expected: bool = False) -> li
>           return ret_packets
>   
>   
> +#: Test suite type decorators
> +func_suite: Callable[[Any], type["TestSuite"]] = TestSuite.make_decorator(TestSuiteType.FUNC)
> +perf_suite: Callable[[Any], type["TestSuite"]] = TestSuite.make_decorator(TestSuiteType.PERF)
> +crypto_suite: Callable[[Any], type["TestSuite"]] = TestSuite.make_decorator(TestSuiteType.CRYPTO)
> +
>   #: The generic type for a method of an instance of TestSuite
>   TestSuiteMethodType = TypeVar("TestSuiteMethodType", bound=Callable[[TestSuite], None])
>   
Many thanks,
Luca


More information about the dev mailing list