* [PATCH 1/2] dts: introduce abstract class for TG and SUT DPDK runtime environments
@ 2025-08-08 18:21 Andrew Bailey
2025-08-08 18:21 ` [PATCH 2/2] dts: enable port binding on the TG Andrew Bailey
0 siblings, 1 reply; 2+ messages in thread
From: Andrew Bailey @ 2025-08-08 18:21 UTC (permalink / raw)
To: luca.vizzarro; +Cc: dev, dmarx, probb, Andrew Bailey
DPDK runtime environment has logic in methods for two modes of use, one
for TG environments and one for SUT environments. TG nodes utilizing
these methods only require a single class attribute that DPDK runtime
environment holds. TG nodes using these methods do not require the
overhead of a new DPDK runtime evironment.
Lift shared methods into a new abstract class and split the existing
runtime class into SUT and TG specific runtime classes.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/framework/context.py | 4 +-
dts/framework/remote_session/dpdk.py | 151 ++++++++++++++++++---------
dts/framework/test_run.py | 9 +-
3 files changed, 110 insertions(+), 54 deletions(-)
diff --git a/dts/framework/context.py b/dts/framework/context.py
index 4360bc8699..086f07e0e9 100644
--- a/dts/framework/context.py
+++ b/dts/framework/context.py
@@ -15,7 +15,7 @@
from framework.testbed_model.topology import Topology
if TYPE_CHECKING:
- from framework.remote_session.dpdk import DPDKBuildEnvironment, DPDKRuntimeEnvironment
+ from framework.remote_session.dpdk import DPDKBuildEnvironment, DPDKSUTRuntimeEnvironment
from framework.testbed_model.traffic_generator.traffic_generator import TrafficGenerator
P = ParamSpec("P")
@@ -68,7 +68,7 @@ class Context:
tg_node: Node
topology: Topology
dpdk_build: "DPDKBuildEnvironment"
- dpdk: "DPDKRuntimeEnvironment"
+ dpdk: "DPDKSUTRuntimeEnvironment"
tg: "TrafficGenerator"
local: LocalContext = field(default_factory=LocalContext)
shell_pool: ShellPool = field(default_factory=ShellPool)
diff --git a/dts/framework/remote_session/dpdk.py b/dts/framework/remote_session/dpdk.py
index 606d6e22fe..8e45da4bd5 100644
--- a/dts/framework/remote_session/dpdk.py
+++ b/dts/framework/remote_session/dpdk.py
@@ -7,6 +7,7 @@
import os
import time
+from abc import ABC, abstractmethod
from collections.abc import Iterable
from dataclasses import dataclass
from functools import cached_property
@@ -302,14 +303,83 @@ def get_dpdk_build_info(self) -> DPDKBuildInfo:
return DPDKBuildInfo(dpdk_version=self.dpdk_version, compiler_version=self.compiler_version)
-class DPDKRuntimeEnvironment:
- """Class handling a DPDK runtime environment."""
+class DPDKRuntimeEnvironment(ABC):
+ """Shared methods between TG and SUT runtimes."""
- config: Final[DPDKRuntimeConfiguration]
- build: Final[DPDKBuildEnvironment | None]
_node: Final[Node]
+
+ def __init__(self, node: Node):
+ """DPDK runtime environment constructor.
+
+ Args:
+ node: The target node to manage a DPDK environment.
+ """
+ self._node = node
+
+ @abstractmethod
+ def _prepare_devbind_script(self):
+ """Prepare the devbind script.
+
+ This script is only available for Linux, if the detected session is not Linux then do
+ nothing.
+
+ Raises:
+ InternalError: If dpdk-devbind.py could not be found.
+ """
+
+ @abstractmethod
+ def setup(self) -> None:
+ """Set up the DPDK runtime on the target node."""
+
+
+class DPDKTGRuntimeEnvironment(DPDKRuntimeEnvironment):
+ """Class handling a DPDK runtime environment for a TG."""
+
+ def __init__(self, node: Node):
+ """DPDK TG environment constructor.
+
+ Args:
+ node: The target node to manage a DPDK environment.
+ """
+ super().__init__(node)
+
+ def setup(self) -> None:
+ """Set up the DPDK runtime on the target node."""
+ self._prepare_devbind_script()
+
+ def _prepare_devbind_script(self) -> None:
+ """Prepare the devbind script.
+
+ Copy the script build from the local repository.
+
+ This script is only available for Linux, if the detected session is not Linux then do
+ nothing.
+
+ Raises:
+ InternalError: If dpdk-devbind.py could not be found.
+ """
+ if not isinstance(self._node.main_session, LinuxSession):
+ return
+
+ local_script_path = Path("..", "usertools", "dpdk-devbind.py").resolve()
+ if not local_script_path.exists():
+ raise InternalError("Could not find dpdk-devbind.py locally.")
+
+ devbind_script_path = self._node.main_session.join_remote_path(
+ self._node.tmp_dir, local_script_path.name
+ )
+
+ self._node.main_session.copy_to(local_script_path, devbind_script_path)
+ self._node.main_session.devbind_script_path = devbind_script_path
+
+
+class DPDKSUTRuntimeEnvironment(DPDKRuntimeEnvironment):
+ """Class handling a DPDK runtime environment for a SUT."""
+
+ config: Final[DPDKRuntimeConfiguration]
_logger: Final[DTSLogger]
+ build: Final[DPDKBuildEnvironment]
timestamp: Final[str]
_virtual_devices: list[VirtualDevice]
_lcores: list[LogicalCore]
@@ -322,18 +392,18 @@ def __init__(
self,
config: DPDKRuntimeConfiguration,
node: Node,
- build_env: DPDKBuildEnvironment | None = None,
+ build_env: DPDKBuildEnvironment,
):
- """DPDK environment constructor.
+ """DPDK SUT environment constructor.
Args:
config: The configuration of DPDK.
node: The target node to manage a DPDK environment.
- build_env: The DPDK build environment, if any.
+ build_env: The DPDK build environment.
"""
- self.config = config
+ super().__init__(node)
self.build = build_env
- self._node = node
+ self.config = config
self._logger = get_dts_logger()
self.timestamp = f"{str(os.getpid())}_{time.strftime('%Y%m%d%H%M%S', time.localtime())}"
@@ -354,17 +424,11 @@ def __init__(
self._ports_bound_to_dpdk = False
self._kill_session = None
- def setup(self):
+ def setup(self) -> None:
"""Set up the DPDK runtime on the target node."""
- if self.build:
- self.build.setup()
+ self.build.setup()
self._prepare_devbind_script()
- def teardown(self) -> None:
- """Reset DPDK variables and bind port driver to the OS driver."""
- if self.build:
- self.build.teardown()
-
def run_dpdk_app(
self, app_path: PurePath, eal_params: EalParams, timeout: float = 30
) -> CommandResult:
@@ -385,38 +449,6 @@ def run_dpdk_app(
f"{app_path} {eal_params}", timeout, privileged=True, verify=True
)
- def _prepare_devbind_script(self) -> None:
- """Prepare the devbind script.
-
- If the environment has a build associated with it, then use the script within that build's
- tree. Otherwise, copy the script from the local repository.
-
- This script is only available for Linux, if the detected session is not Linux then do
- nothing.
-
- Raises:
- InternalError: If dpdk-devbind.py could not be found.
- """
- if not isinstance(self._node.main_session, LinuxSession):
- return
-
- if self.build:
- devbind_script_path = self._node.main_session.join_remote_path(
- self.build.remote_dpdk_tree_path, "usertools", "dpdk-devbind.py"
- )
- else:
- local_script_path = Path("..", "usertools", "dpdk-devbind.py").resolve()
- if not local_script_path.exists():
- raise InternalError("Could not find dpdk-devbind.py locally.")
-
- devbind_script_path = self._node.main_session.join_remote_path(
- self._node.tmp_dir, local_script_path.name
- )
-
- self._node.main_session.copy_to(local_script_path, devbind_script_path)
-
- self._node.main_session.devbind_script_path = devbind_script_path
-
def filter_lcores(
self,
filter_specifier: LogicalCoreCount | LogicalCoreList,
@@ -459,3 +491,24 @@ def kill_cleanup_dpdk_apps(self) -> None:
def get_virtual_devices(self) -> Iterable[VirtualDevice]:
"""The available DPDK virtual devices."""
return (v for v in self._virtual_devices)
+
+ def _prepare_devbind_script(self) -> None:
+ """Prepare the devbind script.
+
+ Use the script within the associated build's tree.
+
+ This script is only available for Linux, if the detected session is not Linux then do
+ nothing.
+ """
+ if not isinstance(self._node.main_session, LinuxSession):
+ return
+
+ devbind_script_path = self._node.main_session.join_remote_path(
+ self.build.remote_dpdk_tree_path, "usertools", "dpdk-devbind.py"
+ )
+
+ self._node.main_session.devbind_script_path = devbind_script_path
+
+ def teardown(self) -> None:
+ """Reset DPDK variables and bind port driver to the OS driver."""
+ self.build.teardown()
diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
index 4355aeeb4b..274dceebfd 100644
--- a/dts/framework/test_run.py
+++ b/dts/framework/test_run.py
@@ -111,7 +111,10 @@
from framework.context import Context, init_ctx
from framework.exception import InternalError, SkippedTestException, TestCaseVerifyError
from framework.logger import DTSLogger, get_dts_logger
-from framework.remote_session.dpdk import DPDKBuildEnvironment, DPDKRuntimeEnvironment
+from framework.remote_session.dpdk import (
+ DPDKBuildEnvironment,
+ DPDKSUTRuntimeEnvironment,
+)
from framework.settings import SETTINGS
from framework.test_result import Result, ResultNode, TestRunResult
from framework.test_suite import BaseConfig, TestCase, TestSuite
@@ -199,11 +202,11 @@ def __init__(
)
dpdk_build_env = DPDKBuildEnvironment(config.dpdk.build, sut_node)
- dpdk_runtime_env = DPDKRuntimeEnvironment(config.dpdk, sut_node, dpdk_build_env)
+ dpdk_sut_runtime_env = DPDKSUTRuntimeEnvironment(config.dpdk, sut_node, dpdk_build_env)
traffic_generator = create_traffic_generator(config.traffic_generator, tg_node)
self.ctx = Context(
- sut_node, tg_node, topology, dpdk_build_env, dpdk_runtime_env, traffic_generator
+ sut_node, tg_node, topology, dpdk_build_env, dpdk_sut_runtime_env, traffic_generator
)
self.result = result
self.selected_tests = list(self.config.filter_tests(tests_config))
--
2.50.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH 2/2] dts: enable port binding on the TG
2025-08-08 18:21 [PATCH 1/2] dts: introduce abstract class for TG and SUT DPDK runtime environments Andrew Bailey
@ 2025-08-08 18:21 ` Andrew Bailey
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Bailey @ 2025-08-08 18:21 UTC (permalink / raw)
To: luca.vizzarro; +Cc: dev, dmarx, probb, Andrew Bailey
Currently, ports on the TG are not bound to the correct drivers prior to
running DTS. This causes DTS to crash if they are not initially bound to
the intended drivers.
Leverage TG runtime environment to bind TG ports to correct drivers
before and after running DTS.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/framework/test_run.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
index 274dceebfd..16d7781536 100644
--- a/dts/framework/test_run.py
+++ b/dts/framework/test_run.py
@@ -114,6 +114,7 @@
from framework.remote_session.dpdk import (
DPDKBuildEnvironment,
DPDKSUTRuntimeEnvironment,
+ DPDKTGRuntimeEnvironment,
)
from framework.settings import SETTINGS
from framework.test_result import Result, ResultNode, TestRunResult
@@ -169,6 +170,7 @@ class TestRun:
ctx: Context
result: TestRunResult
selected_tests: list[TestScenario]
+ tg_runtime_env: DPDKTGRuntimeEnvironment
blocked: bool
remaining_tests: deque[TestScenario]
@@ -203,6 +205,7 @@ def __init__(
dpdk_build_env = DPDKBuildEnvironment(config.dpdk.build, sut_node)
dpdk_sut_runtime_env = DPDKSUTRuntimeEnvironment(config.dpdk, sut_node, dpdk_build_env)
+ self.tg_runtime_env = DPDKTGRuntimeEnvironment(tg_node)
traffic_generator = create_traffic_generator(config.traffic_generator, tg_node)
self.ctx = Context(
@@ -343,6 +346,7 @@ def next(self) -> State | None:
test_run.ctx.sut_node.setup()
test_run.ctx.tg_node.setup()
+ test_run.tg_runtime_env.setup()
test_run.ctx.dpdk.setup()
test_run.ctx.topology.setup()
--
2.50.1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-08-08 18:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-08 18:21 [PATCH 1/2] dts: introduce abstract class for TG and SUT DPDK runtime environments Andrew Bailey
2025-08-08 18:21 ` [PATCH 2/2] dts: enable port binding on the TG Andrew Bailey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).