xref: /dpdk/dts/framework/testbed_model/sut_node.py (revision bfad0948df75e95e04cba1804a2749cfc91c56fb)
178534506SJuraj Linkeš# SPDX-License-Identifier: BSD-3-Clause
278534506SJuraj Linkeš# Copyright(c) 2010-2014 Intel Corporation
378534506SJuraj Linkeš# Copyright(c) 2023 PANTHEON.tech s.r.o.
488489c05SJeremy Spewock# Copyright(c) 2023 University of New Hampshire
5fd8cd8eeSLuca Vizzarro# Copyright(c) 2024 Arm Limited
678534506SJuraj Linkeš
76ef07151SJuraj Linkeš"""System under test (DPDK + hardware) node.
86ef07151SJuraj Linkeš
96ef07151SJuraj LinkešA system under test (SUT) is the combination of DPDK
106ef07151SJuraj Linkešand the hardware we're testing with DPDK (NICs, crypto and other devices).
116ef07151SJuraj LinkešAn SUT node is where this SUT runs.
126ef07151SJuraj Linkeš"""
136ef07151SJuraj Linkeš
146ef07151SJuraj Linkeš
15680d8a24SJuraj Linkešimport os
16680d8a24SJuraj Linkešimport tarfile
17c020b7ceSJuraj Linkešimport time
18680d8a24SJuraj Linkešfrom pathlib import PurePath
19680d8a24SJuraj Linkeš
2088489c05SJeremy Spewockfrom framework.config import (
2188489c05SJeremy Spewock    BuildTargetConfiguration,
2288489c05SJeremy Spewock    BuildTargetInfo,
2388489c05SJeremy Spewock    NodeInfo,
24634bed13SJuraj Linkeš    SutNodeConfiguration,
25a24f9604SJuraj Linkeš    TestRunConfiguration,
2688489c05SJeremy Spewock)
27967fc62bSLuca Vizzarrofrom framework.params.eal import EalParams
282b2f5a8aSLuca Vizzarrofrom framework.remote_session.remote_session import CommandResult
29680d8a24SJuraj Linkešfrom framework.settings import SETTINGS
30b8bdc4c5SJuraj Linkešfrom framework.utils import MesonArgs
31680d8a24SJuraj Linkeš
3278534506SJuraj Linkešfrom .node import Node
33*bfad0948SLuca Vizzarrofrom .os_session import OSSession
34840b1e01SJuraj Linkešfrom .virtual_device import VirtualDevice
3578534506SJuraj Linkeš
3678534506SJuraj Linkeš
3778534506SJuraj Linkešclass SutNode(Node):
386ef07151SJuraj Linkeš    """The system under test node.
396ef07151SJuraj Linkeš
406ef07151SJuraj Linkeš    The SUT node extends :class:`Node` with DPDK specific features:
416ef07151SJuraj Linkeš
426ef07151SJuraj Linkeš        * DPDK build,
436ef07151SJuraj Linkeš        * Gathering of DPDK build info,
446ef07151SJuraj Linkeš        * The running of DPDK apps, interactively or one-time execution,
456ef07151SJuraj Linkeš        * DPDK apps cleanup.
466ef07151SJuraj Linkeš
476ef07151SJuraj Linkeš    The :option:`--tarball` command line argument and the :envvar:`DTS_DPDK_TARBALL`
486ef07151SJuraj Linkeš    environment variable configure the path to the DPDK tarball
496ef07151SJuraj Linkeš    or the git commit ID, tag ID or tree ID to test.
506ef07151SJuraj Linkeš
516ef07151SJuraj Linkeš    Attributes:
52a24f9604SJuraj Linkeš        config: The SUT node configuration.
53a24f9604SJuraj Linkeš        virtual_devices: The virtual devices used on the node.
5478534506SJuraj Linkeš    """
55680d8a24SJuraj Linkeš
56634bed13SJuraj Linkeš    config: SutNodeConfiguration
57a24f9604SJuraj Linkeš    virtual_devices: list[VirtualDevice]
58*bfad0948SLuca Vizzarro    dpdk_prefix_list: list[str]
59*bfad0948SLuca Vizzarro    dpdk_timestamp: str
60680d8a24SJuraj Linkeš    _build_target_config: BuildTargetConfiguration | None
61b8bdc4c5SJuraj Linkeš    _env_vars: dict
62680d8a24SJuraj Linkeš    _remote_tmp_dir: PurePath
63680d8a24SJuraj Linkeš    __remote_dpdk_dir: PurePath | None
64680d8a24SJuraj Linkeš    _app_compile_timeout: float
65c020b7ceSJuraj Linkeš    _dpdk_kill_session: OSSession | None
6688489c05SJeremy Spewock    _dpdk_version: str | None
6788489c05SJeremy Spewock    _node_info: NodeInfo | None
6888489c05SJeremy Spewock    _compiler_version: str | None
6968010b2aSJeremy Spewock    _path_to_devbind_script: PurePath | None
70680d8a24SJuraj Linkeš
71634bed13SJuraj Linkeš    def __init__(self, node_config: SutNodeConfiguration):
726ef07151SJuraj Linkeš        """Extend the constructor with SUT node specifics.
736ef07151SJuraj Linkeš
746ef07151SJuraj Linkeš        Args:
756ef07151SJuraj Linkeš            node_config: The SUT node's test run configuration.
766ef07151SJuraj Linkeš        """
77f614e737SJuraj Linkeš        super().__init__(node_config)
78a24f9604SJuraj Linkeš        self.virtual_devices = []
79*bfad0948SLuca Vizzarro        self.dpdk_prefix_list = []
80680d8a24SJuraj Linkeš        self._build_target_config = None
81b8bdc4c5SJuraj Linkeš        self._env_vars = {}
82680d8a24SJuraj Linkeš        self._remote_tmp_dir = self.main_session.get_remote_tmp_dir()
83680d8a24SJuraj Linkeš        self.__remote_dpdk_dir = None
84680d8a24SJuraj Linkeš        self._app_compile_timeout = 90
85c020b7ceSJuraj Linkeš        self._dpdk_kill_session = None
86*bfad0948SLuca Vizzarro        self.dpdk_timestamp = (
87c020b7ceSJuraj Linkeš            f"{str(os.getpid())}_{time.strftime('%Y%m%d%H%M%S', time.localtime())}"
88c020b7ceSJuraj Linkeš        )
8988489c05SJeremy Spewock        self._dpdk_version = None
9088489c05SJeremy Spewock        self._node_info = None
9188489c05SJeremy Spewock        self._compiler_version = None
9268010b2aSJeremy Spewock        self._path_to_devbind_script = None
93cecfe0aaSJuraj Linkeš        self._logger.info(f"Created node: {self.name}")
94680d8a24SJuraj Linkeš
95680d8a24SJuraj Linkeš    @property
96680d8a24SJuraj Linkeš    def _remote_dpdk_dir(self) -> PurePath:
976ef07151SJuraj Linkeš        """The remote DPDK dir.
986ef07151SJuraj Linkeš
996ef07151SJuraj Linkeš        This internal property should be set after extracting the DPDK tarball. If it's not set,
1006ef07151SJuraj Linkeš        that implies the DPDK setup step has been skipped, in which case we can guess where
1016ef07151SJuraj Linkeš        a previous build was located.
1026ef07151SJuraj Linkeš        """
103680d8a24SJuraj Linkeš        if self.__remote_dpdk_dir is None:
104680d8a24SJuraj Linkeš            self.__remote_dpdk_dir = self._guess_dpdk_remote_dir()
105680d8a24SJuraj Linkeš        return self.__remote_dpdk_dir
106680d8a24SJuraj Linkeš
107680d8a24SJuraj Linkeš    @_remote_dpdk_dir.setter
108680d8a24SJuraj Linkeš    def _remote_dpdk_dir(self, value: PurePath) -> None:
109680d8a24SJuraj Linkeš        self.__remote_dpdk_dir = value
110680d8a24SJuraj Linkeš
111680d8a24SJuraj Linkeš    @property
112680d8a24SJuraj Linkeš    def remote_dpdk_build_dir(self) -> PurePath:
1136ef07151SJuraj Linkeš        """The remote DPDK build directory.
1146ef07151SJuraj Linkeš
1156ef07151SJuraj Linkeš        This is the directory where DPDK was built.
1166ef07151SJuraj Linkeš        We assume it was built in a subdirectory of the extracted tarball.
1176ef07151SJuraj Linkeš        """
118680d8a24SJuraj Linkeš        if self._build_target_config:
119680d8a24SJuraj Linkeš            return self.main_session.join_remote_path(
120680d8a24SJuraj Linkeš                self._remote_dpdk_dir, self._build_target_config.name
121680d8a24SJuraj Linkeš            )
122680d8a24SJuraj Linkeš        else:
123680d8a24SJuraj Linkeš            return self.main_session.join_remote_path(self._remote_dpdk_dir, "build")
124680d8a24SJuraj Linkeš
125680d8a24SJuraj Linkeš    @property
126680d8a24SJuraj Linkeš    def dpdk_version(self) -> str:
1276ef07151SJuraj Linkeš        """Last built DPDK version."""
128680d8a24SJuraj Linkeš        if self._dpdk_version is None:
129517b4b26SJuraj Linkeš            self._dpdk_version = self.main_session.get_dpdk_version(self._remote_dpdk_dir)
130680d8a24SJuraj Linkeš        return self._dpdk_version
131680d8a24SJuraj Linkeš
13288489c05SJeremy Spewock    @property
13388489c05SJeremy Spewock    def node_info(self) -> NodeInfo:
1346ef07151SJuraj Linkeš        """Additional node information."""
13588489c05SJeremy Spewock        if self._node_info is None:
13688489c05SJeremy Spewock            self._node_info = self.main_session.get_node_info()
13788489c05SJeremy Spewock        return self._node_info
13888489c05SJeremy Spewock
13988489c05SJeremy Spewock    @property
14088489c05SJeremy Spewock    def compiler_version(self) -> str:
1416ef07151SJuraj Linkeš        """The node's compiler version."""
14288489c05SJeremy Spewock        if self._compiler_version is None:
14388489c05SJeremy Spewock            if self._build_target_config is not None:
14488489c05SJeremy Spewock                self._compiler_version = self.main_session.get_compiler_version(
14588489c05SJeremy Spewock                    self._build_target_config.compiler.name
14688489c05SJeremy Spewock                )
14788489c05SJeremy Spewock            else:
14888489c05SJeremy Spewock                self._logger.warning(
149517b4b26SJuraj Linkeš                    "Failed to get compiler version because _build_target_config is None."
15088489c05SJeremy Spewock                )
15188489c05SJeremy Spewock                return ""
15288489c05SJeremy Spewock        return self._compiler_version
15388489c05SJeremy Spewock
15468010b2aSJeremy Spewock    @property
15568010b2aSJeremy Spewock    def path_to_devbind_script(self) -> PurePath:
1566ef07151SJuraj Linkeš        """The path to the dpdk-devbind.py script on the node."""
15768010b2aSJeremy Spewock        if self._path_to_devbind_script is None:
15868010b2aSJeremy Spewock            self._path_to_devbind_script = self.main_session.join_remote_path(
15968010b2aSJeremy Spewock                self._remote_dpdk_dir, "usertools", "dpdk-devbind.py"
16068010b2aSJeremy Spewock            )
16168010b2aSJeremy Spewock        return self._path_to_devbind_script
16268010b2aSJeremy Spewock
16388489c05SJeremy Spewock    def get_build_target_info(self) -> BuildTargetInfo:
1646ef07151SJuraj Linkeš        """Get additional build target information.
1656ef07151SJuraj Linkeš
1666ef07151SJuraj Linkeš        Returns:
1676ef07151SJuraj Linkeš            The build target information,
1686ef07151SJuraj Linkeš        """
16988489c05SJeremy Spewock        return BuildTargetInfo(
17088489c05SJeremy Spewock            dpdk_version=self.dpdk_version, compiler_version=self.compiler_version
17188489c05SJeremy Spewock        )
17288489c05SJeremy Spewock
173680d8a24SJuraj Linkeš    def _guess_dpdk_remote_dir(self) -> PurePath:
174680d8a24SJuraj Linkeš        return self.main_session.guess_dpdk_remote_dir(self._remote_tmp_dir)
175680d8a24SJuraj Linkeš
176a24f9604SJuraj Linkeš    def set_up_test_run(self, test_run_config: TestRunConfiguration) -> None:
177a24f9604SJuraj Linkeš        """Extend the test run setup with vdev config.
1786ef07151SJuraj Linkeš
179a24f9604SJuraj Linkeš        Args:
180a24f9604SJuraj Linkeš            test_run_config: A test run configuration according to which
181a24f9604SJuraj Linkeš                the setup steps will be taken.
182680d8a24SJuraj Linkeš        """
183a24f9604SJuraj Linkeš        super().set_up_test_run(test_run_config)
184a24f9604SJuraj Linkeš        for vdev in test_run_config.vdevs:
185a24f9604SJuraj Linkeš            self.virtual_devices.append(VirtualDevice(vdev))
186a24f9604SJuraj Linkeš
187a24f9604SJuraj Linkeš    def tear_down_test_run(self) -> None:
188a24f9604SJuraj Linkeš        """Extend the test run teardown with virtual device teardown."""
189a24f9604SJuraj Linkeš        super().tear_down_test_run()
190a24f9604SJuraj Linkeš        self.virtual_devices = []
191a24f9604SJuraj Linkeš
192a24f9604SJuraj Linkeš    def set_up_build_target(self, build_target_config: BuildTargetConfiguration) -> None:
193a24f9604SJuraj Linkeš        """Set up DPDK the SUT node and bind ports.
194a24f9604SJuraj Linkeš
195a24f9604SJuraj Linkeš        DPDK setup includes setting all internals needed for the build, the copying of DPDK tarball
196a24f9604SJuraj Linkeš        and then building DPDK. The drivers are bound to those that DPDK needs.
197a24f9604SJuraj Linkeš
198a24f9604SJuraj Linkeš        Args:
199a24f9604SJuraj Linkeš            build_target_config: The build target test run configuration according to which
200a24f9604SJuraj Linkeš                the setup steps will be taken.
201a24f9604SJuraj Linkeš        """
202680d8a24SJuraj Linkeš        self._configure_build_target(build_target_config)
203680d8a24SJuraj Linkeš        self._copy_dpdk_tarball()
204680d8a24SJuraj Linkeš        self._build_dpdk()
20568010b2aSJeremy Spewock        self.bind_ports_to_driver()
20668010b2aSJeremy Spewock
207a24f9604SJuraj Linkeš    def tear_down_build_target(self) -> None:
208a24f9604SJuraj Linkeš        """Reset DPDK variables and bind port driver to the OS driver."""
209a24f9604SJuraj Linkeš        self._env_vars = {}
210a24f9604SJuraj Linkeš        self._build_target_config = None
211a24f9604SJuraj Linkeš        self.__remote_dpdk_dir = None
212a24f9604SJuraj Linkeš        self._dpdk_version = None
213a24f9604SJuraj Linkeš        self._compiler_version = None
21468010b2aSJeremy Spewock        self.bind_ports_to_driver(for_dpdk=False)
215680d8a24SJuraj Linkeš
216517b4b26SJuraj Linkeš    def _configure_build_target(self, build_target_config: BuildTargetConfiguration) -> None:
2176ef07151SJuraj Linkeš        """Populate common environment variables and set build target config."""
218b8bdc4c5SJuraj Linkeš        self._env_vars = {}
219680d8a24SJuraj Linkeš        self._build_target_config = build_target_config
220517b4b26SJuraj Linkeš        self._env_vars.update(self.main_session.get_dpdk_build_env_vars(build_target_config.arch))
221680d8a24SJuraj Linkeš        self._env_vars["CC"] = build_target_config.compiler.name
222680d8a24SJuraj Linkeš        if build_target_config.compiler_wrapper:
223680d8a24SJuraj Linkeš            self._env_vars["CC"] = (
224517b4b26SJuraj Linkeš                f"'{build_target_config.compiler_wrapper} {build_target_config.compiler.name}'"
225517b4b26SJuraj Linkeš            )  # fmt: skip
226680d8a24SJuraj Linkeš
227680d8a24SJuraj Linkeš    @Node.skip_setup
228680d8a24SJuraj Linkeš    def _copy_dpdk_tarball(self) -> None:
2296ef07151SJuraj Linkeš        """Copy to and extract DPDK tarball on the SUT node."""
230680d8a24SJuraj Linkeš        self._logger.info("Copying DPDK tarball to SUT.")
231b8bdc4c5SJuraj Linkeš        self.main_session.copy_to(SETTINGS.dpdk_tarball_path, self._remote_tmp_dir)
232680d8a24SJuraj Linkeš
233680d8a24SJuraj Linkeš        # construct remote tarball path
234680d8a24SJuraj Linkeš        # the basename is the same on local host and on remote Node
235680d8a24SJuraj Linkeš        remote_tarball_path = self.main_session.join_remote_path(
236680d8a24SJuraj Linkeš            self._remote_tmp_dir, os.path.basename(SETTINGS.dpdk_tarball_path)
237680d8a24SJuraj Linkeš        )
238680d8a24SJuraj Linkeš
239680d8a24SJuraj Linkeš        # construct remote path after extracting
240680d8a24SJuraj Linkeš        with tarfile.open(SETTINGS.dpdk_tarball_path) as dpdk_tar:
241680d8a24SJuraj Linkeš            dpdk_top_dir = dpdk_tar.getnames()[0]
242680d8a24SJuraj Linkeš        self._remote_dpdk_dir = self.main_session.join_remote_path(
243680d8a24SJuraj Linkeš            self._remote_tmp_dir, dpdk_top_dir
244680d8a24SJuraj Linkeš        )
245680d8a24SJuraj Linkeš
246680d8a24SJuraj Linkeš        self._logger.info(
247680d8a24SJuraj Linkeš            f"Extracting DPDK tarball on SUT: "
248680d8a24SJuraj Linkeš            f"'{remote_tarball_path}' into '{self._remote_dpdk_dir}'."
249680d8a24SJuraj Linkeš        )
250680d8a24SJuraj Linkeš        # clean remote path where we're extracting
251680d8a24SJuraj Linkeš        self.main_session.remove_remote_dir(self._remote_dpdk_dir)
252680d8a24SJuraj Linkeš
253680d8a24SJuraj Linkeš        # then extract to remote path
254517b4b26SJuraj Linkeš        self.main_session.extract_remote_tarball(remote_tarball_path, self._remote_dpdk_dir)
255680d8a24SJuraj Linkeš
256680d8a24SJuraj Linkeš    @Node.skip_setup
257680d8a24SJuraj Linkeš    def _build_dpdk(self) -> None:
2586ef07151SJuraj Linkeš        """Build DPDK.
2596ef07151SJuraj Linkeš
2606ef07151SJuraj Linkeš        Uses the already configured target. Assumes that the tarball has
261680d8a24SJuraj Linkeš        already been copied to and extracted on the SUT node.
262680d8a24SJuraj Linkeš        """
263680d8a24SJuraj Linkeš        self.main_session.build_dpdk(
264680d8a24SJuraj Linkeš            self._env_vars,
265680d8a24SJuraj Linkeš            MesonArgs(default_library="static", enable_kmods=True, libdir="lib"),
266680d8a24SJuraj Linkeš            self._remote_dpdk_dir,
267680d8a24SJuraj Linkeš            self.remote_dpdk_build_dir,
268680d8a24SJuraj Linkeš        )
269680d8a24SJuraj Linkeš
270680d8a24SJuraj Linkeš    def build_dpdk_app(self, app_name: str, **meson_dpdk_args: str | bool) -> PurePath:
2716ef07151SJuraj Linkeš        """Build one or all DPDK apps.
2726ef07151SJuraj Linkeš
2736ef07151SJuraj Linkeš        Requires DPDK to be already built on the SUT node.
2746ef07151SJuraj Linkeš
2756ef07151SJuraj Linkeš        Args:
2766ef07151SJuraj Linkeš            app_name: The name of the DPDK app to build.
2776ef07151SJuraj Linkeš                When `app_name` is ``all``, build all example apps.
2786ef07151SJuraj Linkeš            meson_dpdk_args: The arguments found in ``meson_options.txt`` in root DPDK directory.
2796ef07151SJuraj Linkeš                Do not use ``-D`` with them.
2806ef07151SJuraj Linkeš
2816ef07151SJuraj Linkeš        Returns:
2826ef07151SJuraj Linkeš            The directory path of the built app. If building all apps, return
283680d8a24SJuraj Linkeš            the path to the examples directory (where all apps reside).
284680d8a24SJuraj Linkeš        """
285680d8a24SJuraj Linkeš        self.main_session.build_dpdk(
286680d8a24SJuraj Linkeš            self._env_vars,
287680d8a24SJuraj Linkeš            MesonArgs(examples=app_name, **meson_dpdk_args),  # type: ignore [arg-type]
288680d8a24SJuraj Linkeš            # ^^ https://github.com/python/mypy/issues/11583
289680d8a24SJuraj Linkeš            self._remote_dpdk_dir,
290680d8a24SJuraj Linkeš            self.remote_dpdk_build_dir,
291680d8a24SJuraj Linkeš            rebuild=True,
292680d8a24SJuraj Linkeš            timeout=self._app_compile_timeout,
293680d8a24SJuraj Linkeš        )
294680d8a24SJuraj Linkeš
295680d8a24SJuraj Linkeš        if app_name == "all":
296517b4b26SJuraj Linkeš            return self.main_session.join_remote_path(self.remote_dpdk_build_dir, "examples")
297680d8a24SJuraj Linkeš        return self.main_session.join_remote_path(
298680d8a24SJuraj Linkeš            self.remote_dpdk_build_dir, "examples", f"dpdk-{app_name}"
299680d8a24SJuraj Linkeš        )
300c020b7ceSJuraj Linkeš
301c020b7ceSJuraj Linkeš    def kill_cleanup_dpdk_apps(self) -> None:
3026ef07151SJuraj Linkeš        """Kill all dpdk applications on the SUT, then clean up hugepages."""
303c020b7ceSJuraj Linkeš        if self._dpdk_kill_session and self._dpdk_kill_session.is_alive():
304c020b7ceSJuraj Linkeš            # we can use the session if it exists and responds
305*bfad0948SLuca Vizzarro            self._dpdk_kill_session.kill_cleanup_dpdk_apps(self.dpdk_prefix_list)
306c020b7ceSJuraj Linkeš        else:
307c020b7ceSJuraj Linkeš            # otherwise, we need to (re)create it
308c020b7ceSJuraj Linkeš            self._dpdk_kill_session = self.create_session("dpdk_kill")
309*bfad0948SLuca Vizzarro        self.dpdk_prefix_list = []
310c020b7ceSJuraj Linkeš
311444833c0SJuraj Linkeš    def run_dpdk_app(
312fd8cd8eeSLuca Vizzarro        self, app_path: PurePath, eal_params: EalParams, timeout: float = 30
313444833c0SJuraj Linkeš    ) -> CommandResult:
3146ef07151SJuraj Linkeš        """Run DPDK application on the remote node.
3156ef07151SJuraj Linkeš
3166ef07151SJuraj Linkeš        The application is not run interactively - the command that starts the application
3176ef07151SJuraj Linkeš        is executed and then the call waits for it to finish execution.
3186ef07151SJuraj Linkeš
3196ef07151SJuraj Linkeš        Args:
3206ef07151SJuraj Linkeš            app_path: The remote path to the DPDK application.
321fd8cd8eeSLuca Vizzarro            eal_params: EAL parameters to run the DPDK application with.
3226ef07151SJuraj Linkeš            timeout: Wait at most this long in seconds for `command` execution to complete.
3236ef07151SJuraj Linkeš
3246ef07151SJuraj Linkeš        Returns:
3256ef07151SJuraj Linkeš            The result of the DPDK app execution.
326444833c0SJuraj Linkeš        """
327444833c0SJuraj Linkeš        return self.main_session.send_command(
328fd8cd8eeSLuca Vizzarro            f"{app_path} {eal_params}", timeout, privileged=True, verify=True
329444833c0SJuraj Linkeš        )
330444833c0SJuraj Linkeš
331d99250aaSJuraj Linkeš    def configure_ipv4_forwarding(self, enable: bool) -> None:
3326ef07151SJuraj Linkeš        """Enable/disable IPv4 forwarding on the node.
3336ef07151SJuraj Linkeš
3346ef07151SJuraj Linkeš        Args:
3356ef07151SJuraj Linkeš            enable: If :data:`True`, enable the forwarding, otherwise disable it.
3366ef07151SJuraj Linkeš        """
337d99250aaSJuraj Linkeš        self.main_session.configure_ipv4_forwarding(enable)
338d99250aaSJuraj Linkeš
33968010b2aSJeremy Spewock    def bind_ports_to_driver(self, for_dpdk: bool = True) -> None:
34068010b2aSJeremy Spewock        """Bind all ports on the SUT to a driver.
34168010b2aSJeremy Spewock
34268010b2aSJeremy Spewock        Args:
3436ef07151SJuraj Linkeš            for_dpdk: If :data:`True`, binds ports to os_driver_for_dpdk.
3446ef07151SJuraj Linkeš                If :data:`False`, binds to os_driver.
34568010b2aSJeremy Spewock        """
34668010b2aSJeremy Spewock        for port in self.ports:
34768010b2aSJeremy Spewock            driver = port.os_driver_for_dpdk if for_dpdk else port.os_driver
34868010b2aSJeremy Spewock            self.main_session.send_command(
34968010b2aSJeremy Spewock                f"{self.path_to_devbind_script} -b {driver} --force {port.pci}",
35068010b2aSJeremy Spewock                privileged=True,
35168010b2aSJeremy Spewock                verify=True,
35268010b2aSJeremy Spewock            )
353