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 578534506SJuraj Linkeš 6680d8a24SJuraj Linkešimport os 7680d8a24SJuraj Linkešimport tarfile 8c020b7ceSJuraj Linkešimport time 9680d8a24SJuraj Linkešfrom pathlib import PurePath 1088489c05SJeremy Spewockfrom typing import Type 11680d8a24SJuraj Linkeš 1288489c05SJeremy Spewockfrom framework.config import ( 1388489c05SJeremy Spewock BuildTargetConfiguration, 1488489c05SJeremy Spewock BuildTargetInfo, 1588489c05SJeremy Spewock NodeInfo, 16634bed13SJuraj Linkeš SutNodeConfiguration, 1788489c05SJeremy Spewock) 1888489c05SJeremy Spewockfrom framework.remote_session import CommandResult, InteractiveShellType, OSSession 19680d8a24SJuraj Linkešfrom framework.settings import SETTINGS 20b8bdc4c5SJuraj Linkešfrom framework.utils import MesonArgs 21680d8a24SJuraj Linkeš 22c020b7ceSJuraj Linkešfrom .hw import LogicalCoreCount, LogicalCoreList, VirtualDevice 2378534506SJuraj Linkešfrom .node import Node 2478534506SJuraj Linkeš 2578534506SJuraj Linkeš 2688489c05SJeremy Spewockclass EalParameters(object): 2788489c05SJeremy Spewock def __init__( 2888489c05SJeremy Spewock self, 2988489c05SJeremy Spewock lcore_list: LogicalCoreList, 3088489c05SJeremy Spewock memory_channels: int, 3188489c05SJeremy Spewock prefix: str, 3288489c05SJeremy Spewock no_pci: bool, 3388489c05SJeremy Spewock vdevs: list[VirtualDevice], 3488489c05SJeremy Spewock other_eal_param: str, 3588489c05SJeremy Spewock ): 3688489c05SJeremy Spewock """ 3788489c05SJeremy Spewock Generate eal parameters character string; 3888489c05SJeremy Spewock :param lcore_list: the list of logical cores to use. 3988489c05SJeremy Spewock :param memory_channels: the number of memory channels to use. 4088489c05SJeremy Spewock :param prefix: set file prefix string, eg: 4188489c05SJeremy Spewock prefix='vf' 4288489c05SJeremy Spewock :param no_pci: switch of disable PCI bus eg: 4388489c05SJeremy Spewock no_pci=True 4488489c05SJeremy Spewock :param vdevs: virtual device list, eg: 4588489c05SJeremy Spewock vdevs=[ 4688489c05SJeremy Spewock VirtualDevice('net_ring0'), 4788489c05SJeremy Spewock VirtualDevice('net_ring1') 4888489c05SJeremy Spewock ] 4988489c05SJeremy Spewock :param other_eal_param: user defined DPDK eal parameters, eg: 5088489c05SJeremy Spewock other_eal_param='--single-file-segments' 5188489c05SJeremy Spewock """ 5288489c05SJeremy Spewock self._lcore_list = f"-l {lcore_list}" 5388489c05SJeremy Spewock self._memory_channels = f"-n {memory_channels}" 5488489c05SJeremy Spewock self._prefix = prefix 5588489c05SJeremy Spewock if prefix: 5688489c05SJeremy Spewock self._prefix = f"--file-prefix={prefix}" 5788489c05SJeremy Spewock self._no_pci = "--no-pci" if no_pci else "" 5888489c05SJeremy Spewock self._vdevs = " ".join(f"--vdev {vdev}" for vdev in vdevs) 5988489c05SJeremy Spewock self._other_eal_param = other_eal_param 6088489c05SJeremy Spewock 6188489c05SJeremy Spewock def __str__(self) -> str: 6288489c05SJeremy Spewock return ( 6388489c05SJeremy Spewock f"{self._lcore_list} " 6488489c05SJeremy Spewock f"{self._memory_channels} " 6588489c05SJeremy Spewock f"{self._prefix} " 6688489c05SJeremy Spewock f"{self._no_pci} " 6788489c05SJeremy Spewock f"{self._vdevs} " 6888489c05SJeremy Spewock f"{self._other_eal_param}" 6988489c05SJeremy Spewock ) 7088489c05SJeremy Spewock 7188489c05SJeremy Spewock 7278534506SJuraj Linkešclass SutNode(Node): 7378534506SJuraj Linkeš """ 7478534506SJuraj Linkeš A class for managing connections to the System under Test, providing 7578534506SJuraj Linkeš methods that retrieve the necessary information about the node (such as 7678534506SJuraj Linkeš CPU, memory and NIC details) and configuration capabilities. 77680d8a24SJuraj Linkeš Another key capability is building DPDK according to given build target. 7878534506SJuraj Linkeš """ 79680d8a24SJuraj Linkeš 80634bed13SJuraj Linkeš config: SutNodeConfiguration 81c020b7ceSJuraj Linkeš _dpdk_prefix_list: list[str] 82c020b7ceSJuraj Linkeš _dpdk_timestamp: str 83680d8a24SJuraj Linkeš _build_target_config: BuildTargetConfiguration | None 84b8bdc4c5SJuraj Linkeš _env_vars: dict 85680d8a24SJuraj Linkeš _remote_tmp_dir: PurePath 86680d8a24SJuraj Linkeš __remote_dpdk_dir: PurePath | None 87680d8a24SJuraj Linkeš _app_compile_timeout: float 88c020b7ceSJuraj Linkeš _dpdk_kill_session: OSSession | None 8988489c05SJeremy Spewock _dpdk_version: str | None 9088489c05SJeremy Spewock _node_info: NodeInfo | None 9188489c05SJeremy Spewock _compiler_version: str | None 92680d8a24SJuraj Linkeš 93634bed13SJuraj Linkeš def __init__(self, node_config: SutNodeConfiguration): 94680d8a24SJuraj Linkeš super(SutNode, self).__init__(node_config) 95c020b7ceSJuraj Linkeš self._dpdk_prefix_list = [] 96680d8a24SJuraj Linkeš self._build_target_config = None 97b8bdc4c5SJuraj Linkeš self._env_vars = {} 98680d8a24SJuraj Linkeš self._remote_tmp_dir = self.main_session.get_remote_tmp_dir() 99680d8a24SJuraj Linkeš self.__remote_dpdk_dir = None 100680d8a24SJuraj Linkeš self._app_compile_timeout = 90 101c020b7ceSJuraj Linkeš self._dpdk_kill_session = None 102c020b7ceSJuraj Linkeš self._dpdk_timestamp = ( 103c020b7ceSJuraj Linkeš f"{str(os.getpid())}_{time.strftime('%Y%m%d%H%M%S', time.localtime())}" 104c020b7ceSJuraj Linkeš ) 10588489c05SJeremy Spewock self._dpdk_version = None 10688489c05SJeremy Spewock self._node_info = None 10788489c05SJeremy Spewock self._compiler_version = None 108*cecfe0aaSJuraj Linkeš self._logger.info(f"Created node: {self.name}") 109680d8a24SJuraj Linkeš 110680d8a24SJuraj Linkeš @property 111680d8a24SJuraj Linkeš def _remote_dpdk_dir(self) -> PurePath: 112680d8a24SJuraj Linkeš if self.__remote_dpdk_dir is None: 113680d8a24SJuraj Linkeš self.__remote_dpdk_dir = self._guess_dpdk_remote_dir() 114680d8a24SJuraj Linkeš return self.__remote_dpdk_dir 115680d8a24SJuraj Linkeš 116680d8a24SJuraj Linkeš @_remote_dpdk_dir.setter 117680d8a24SJuraj Linkeš def _remote_dpdk_dir(self, value: PurePath) -> None: 118680d8a24SJuraj Linkeš self.__remote_dpdk_dir = value 119680d8a24SJuraj Linkeš 120680d8a24SJuraj Linkeš @property 121680d8a24SJuraj Linkeš def remote_dpdk_build_dir(self) -> PurePath: 122680d8a24SJuraj Linkeš if self._build_target_config: 123680d8a24SJuraj Linkeš return self.main_session.join_remote_path( 124680d8a24SJuraj Linkeš self._remote_dpdk_dir, self._build_target_config.name 125680d8a24SJuraj Linkeš ) 126680d8a24SJuraj Linkeš else: 127680d8a24SJuraj Linkeš return self.main_session.join_remote_path(self._remote_dpdk_dir, "build") 128680d8a24SJuraj Linkeš 129680d8a24SJuraj Linkeš @property 130680d8a24SJuraj Linkeš def dpdk_version(self) -> str: 131680d8a24SJuraj Linkeš if self._dpdk_version is None: 132680d8a24SJuraj Linkeš self._dpdk_version = self.main_session.get_dpdk_version( 133680d8a24SJuraj Linkeš self._remote_dpdk_dir 134680d8a24SJuraj Linkeš ) 135680d8a24SJuraj Linkeš return self._dpdk_version 136680d8a24SJuraj Linkeš 13788489c05SJeremy Spewock @property 13888489c05SJeremy Spewock def node_info(self) -> NodeInfo: 13988489c05SJeremy Spewock if self._node_info is None: 14088489c05SJeremy Spewock self._node_info = self.main_session.get_node_info() 14188489c05SJeremy Spewock return self._node_info 14288489c05SJeremy Spewock 14388489c05SJeremy Spewock @property 14488489c05SJeremy Spewock def compiler_version(self) -> str: 14588489c05SJeremy Spewock if self._compiler_version is None: 14688489c05SJeremy Spewock if self._build_target_config is not None: 14788489c05SJeremy Spewock self._compiler_version = self.main_session.get_compiler_version( 14888489c05SJeremy Spewock self._build_target_config.compiler.name 14988489c05SJeremy Spewock ) 15088489c05SJeremy Spewock else: 15188489c05SJeremy Spewock self._logger.warning( 15288489c05SJeremy Spewock "Failed to get compiler version because" 15388489c05SJeremy Spewock "_build_target_config is None." 15488489c05SJeremy Spewock ) 15588489c05SJeremy Spewock return "" 15688489c05SJeremy Spewock return self._compiler_version 15788489c05SJeremy Spewock 15888489c05SJeremy Spewock def get_build_target_info(self) -> BuildTargetInfo: 15988489c05SJeremy Spewock return BuildTargetInfo( 16088489c05SJeremy Spewock dpdk_version=self.dpdk_version, compiler_version=self.compiler_version 16188489c05SJeremy Spewock ) 16288489c05SJeremy Spewock 163680d8a24SJuraj Linkeš def _guess_dpdk_remote_dir(self) -> PurePath: 164680d8a24SJuraj Linkeš return self.main_session.guess_dpdk_remote_dir(self._remote_tmp_dir) 165680d8a24SJuraj Linkeš 166680d8a24SJuraj Linkeš def _set_up_build_target( 167680d8a24SJuraj Linkeš self, build_target_config: BuildTargetConfiguration 168680d8a24SJuraj Linkeš ) -> None: 169680d8a24SJuraj Linkeš """ 170680d8a24SJuraj Linkeš Setup DPDK on the SUT node. 171680d8a24SJuraj Linkeš """ 17288489c05SJeremy Spewock # we want to ensure that dpdk_version and compiler_version is reset for new 17388489c05SJeremy Spewock # build targets 17488489c05SJeremy Spewock self._dpdk_version = None 17588489c05SJeremy Spewock self._compiler_version = None 176680d8a24SJuraj Linkeš self._configure_build_target(build_target_config) 177680d8a24SJuraj Linkeš self._copy_dpdk_tarball() 178680d8a24SJuraj Linkeš self._build_dpdk() 179680d8a24SJuraj Linkeš 180680d8a24SJuraj Linkeš def _configure_build_target( 181680d8a24SJuraj Linkeš self, build_target_config: BuildTargetConfiguration 182680d8a24SJuraj Linkeš ) -> None: 183680d8a24SJuraj Linkeš """ 184680d8a24SJuraj Linkeš Populate common environment variables and set build target config. 185680d8a24SJuraj Linkeš """ 186b8bdc4c5SJuraj Linkeš self._env_vars = {} 187680d8a24SJuraj Linkeš self._build_target_config = build_target_config 188680d8a24SJuraj Linkeš self._env_vars.update( 189680d8a24SJuraj Linkeš self.main_session.get_dpdk_build_env_vars(build_target_config.arch) 190680d8a24SJuraj Linkeš ) 191680d8a24SJuraj Linkeš self._env_vars["CC"] = build_target_config.compiler.name 192680d8a24SJuraj Linkeš if build_target_config.compiler_wrapper: 193680d8a24SJuraj Linkeš self._env_vars["CC"] = ( 194680d8a24SJuraj Linkeš f"'{build_target_config.compiler_wrapper} " 195680d8a24SJuraj Linkeš f"{build_target_config.compiler.name}'" 196680d8a24SJuraj Linkeš ) 197680d8a24SJuraj Linkeš 198680d8a24SJuraj Linkeš @Node.skip_setup 199680d8a24SJuraj Linkeš def _copy_dpdk_tarball(self) -> None: 200680d8a24SJuraj Linkeš """ 201680d8a24SJuraj Linkeš Copy to and extract DPDK tarball on the SUT node. 202680d8a24SJuraj Linkeš """ 203680d8a24SJuraj Linkeš self._logger.info("Copying DPDK tarball to SUT.") 204b8bdc4c5SJuraj Linkeš self.main_session.copy_to(SETTINGS.dpdk_tarball_path, self._remote_tmp_dir) 205680d8a24SJuraj Linkeš 206680d8a24SJuraj Linkeš # construct remote tarball path 207680d8a24SJuraj Linkeš # the basename is the same on local host and on remote Node 208680d8a24SJuraj Linkeš remote_tarball_path = self.main_session.join_remote_path( 209680d8a24SJuraj Linkeš self._remote_tmp_dir, os.path.basename(SETTINGS.dpdk_tarball_path) 210680d8a24SJuraj Linkeš ) 211680d8a24SJuraj Linkeš 212680d8a24SJuraj Linkeš # construct remote path after extracting 213680d8a24SJuraj Linkeš with tarfile.open(SETTINGS.dpdk_tarball_path) as dpdk_tar: 214680d8a24SJuraj Linkeš dpdk_top_dir = dpdk_tar.getnames()[0] 215680d8a24SJuraj Linkeš self._remote_dpdk_dir = self.main_session.join_remote_path( 216680d8a24SJuraj Linkeš self._remote_tmp_dir, dpdk_top_dir 217680d8a24SJuraj Linkeš ) 218680d8a24SJuraj Linkeš 219680d8a24SJuraj Linkeš self._logger.info( 220680d8a24SJuraj Linkeš f"Extracting DPDK tarball on SUT: " 221680d8a24SJuraj Linkeš f"'{remote_tarball_path}' into '{self._remote_dpdk_dir}'." 222680d8a24SJuraj Linkeš ) 223680d8a24SJuraj Linkeš # clean remote path where we're extracting 224680d8a24SJuraj Linkeš self.main_session.remove_remote_dir(self._remote_dpdk_dir) 225680d8a24SJuraj Linkeš 226680d8a24SJuraj Linkeš # then extract to remote path 227680d8a24SJuraj Linkeš self.main_session.extract_remote_tarball( 228680d8a24SJuraj Linkeš remote_tarball_path, self._remote_dpdk_dir 229680d8a24SJuraj Linkeš ) 230680d8a24SJuraj Linkeš 231680d8a24SJuraj Linkeš @Node.skip_setup 232680d8a24SJuraj Linkeš def _build_dpdk(self) -> None: 233680d8a24SJuraj Linkeš """ 234680d8a24SJuraj Linkeš Build DPDK. Uses the already configured target. Assumes that the tarball has 235680d8a24SJuraj Linkeš already been copied to and extracted on the SUT node. 236680d8a24SJuraj Linkeš """ 237680d8a24SJuraj Linkeš self.main_session.build_dpdk( 238680d8a24SJuraj Linkeš self._env_vars, 239680d8a24SJuraj Linkeš MesonArgs(default_library="static", enable_kmods=True, libdir="lib"), 240680d8a24SJuraj Linkeš self._remote_dpdk_dir, 241680d8a24SJuraj Linkeš self.remote_dpdk_build_dir, 242680d8a24SJuraj Linkeš ) 243680d8a24SJuraj Linkeš 244680d8a24SJuraj Linkeš def build_dpdk_app(self, app_name: str, **meson_dpdk_args: str | bool) -> PurePath: 245680d8a24SJuraj Linkeš """ 246680d8a24SJuraj Linkeš Build one or all DPDK apps. Requires DPDK to be already built on the SUT node. 247680d8a24SJuraj Linkeš When app_name is 'all', build all example apps. 248680d8a24SJuraj Linkeš When app_name is any other string, tries to build that example app. 249680d8a24SJuraj Linkeš Return the directory path of the built app. If building all apps, return 250680d8a24SJuraj Linkeš the path to the examples directory (where all apps reside). 251680d8a24SJuraj Linkeš The meson_dpdk_args are keyword arguments 252680d8a24SJuraj Linkeš found in meson_option.txt in root DPDK directory. Do not use -D with them, 253680d8a24SJuraj Linkeš for example: enable_kmods=True. 254680d8a24SJuraj Linkeš """ 255680d8a24SJuraj Linkeš self.main_session.build_dpdk( 256680d8a24SJuraj Linkeš self._env_vars, 257680d8a24SJuraj Linkeš MesonArgs(examples=app_name, **meson_dpdk_args), # type: ignore [arg-type] 258680d8a24SJuraj Linkeš # ^^ https://github.com/python/mypy/issues/11583 259680d8a24SJuraj Linkeš self._remote_dpdk_dir, 260680d8a24SJuraj Linkeš self.remote_dpdk_build_dir, 261680d8a24SJuraj Linkeš rebuild=True, 262680d8a24SJuraj Linkeš timeout=self._app_compile_timeout, 263680d8a24SJuraj Linkeš ) 264680d8a24SJuraj Linkeš 265680d8a24SJuraj Linkeš if app_name == "all": 266680d8a24SJuraj Linkeš return self.main_session.join_remote_path( 267680d8a24SJuraj Linkeš self.remote_dpdk_build_dir, "examples" 268680d8a24SJuraj Linkeš ) 269680d8a24SJuraj Linkeš return self.main_session.join_remote_path( 270680d8a24SJuraj Linkeš self.remote_dpdk_build_dir, "examples", f"dpdk-{app_name}" 271680d8a24SJuraj Linkeš ) 272c020b7ceSJuraj Linkeš 273c020b7ceSJuraj Linkeš def kill_cleanup_dpdk_apps(self) -> None: 274c020b7ceSJuraj Linkeš """ 275c020b7ceSJuraj Linkeš Kill all dpdk applications on the SUT. Cleanup hugepages. 276c020b7ceSJuraj Linkeš """ 277c020b7ceSJuraj Linkeš if self._dpdk_kill_session and self._dpdk_kill_session.is_alive(): 278c020b7ceSJuraj Linkeš # we can use the session if it exists and responds 279c020b7ceSJuraj Linkeš self._dpdk_kill_session.kill_cleanup_dpdk_apps(self._dpdk_prefix_list) 280c020b7ceSJuraj Linkeš else: 281c020b7ceSJuraj Linkeš # otherwise, we need to (re)create it 282c020b7ceSJuraj Linkeš self._dpdk_kill_session = self.create_session("dpdk_kill") 283c020b7ceSJuraj Linkeš self._dpdk_prefix_list = [] 284c020b7ceSJuraj Linkeš 285c020b7ceSJuraj Linkeš def create_eal_parameters( 286c020b7ceSJuraj Linkeš self, 287c020b7ceSJuraj Linkeš lcore_filter_specifier: LogicalCoreCount | LogicalCoreList = LogicalCoreCount(), 288c020b7ceSJuraj Linkeš ascending_cores: bool = True, 289c020b7ceSJuraj Linkeš prefix: str = "dpdk", 290c020b7ceSJuraj Linkeš append_prefix_timestamp: bool = True, 291c020b7ceSJuraj Linkeš no_pci: bool = False, 292c020b7ceSJuraj Linkeš vdevs: list[VirtualDevice] = None, 293c020b7ceSJuraj Linkeš other_eal_param: str = "", 294c020b7ceSJuraj Linkeš ) -> "EalParameters": 295c020b7ceSJuraj Linkeš """ 296c020b7ceSJuraj Linkeš Generate eal parameters character string; 297c020b7ceSJuraj Linkeš :param lcore_filter_specifier: a number of lcores/cores/sockets to use 298c020b7ceSJuraj Linkeš or a list of lcore ids to use. 299c020b7ceSJuraj Linkeš The default will select one lcore for each of two cores 300c020b7ceSJuraj Linkeš on one socket, in ascending order of core ids. 301c020b7ceSJuraj Linkeš :param ascending_cores: True, use cores with the lowest numerical id first 302c020b7ceSJuraj Linkeš and continue in ascending order. If False, start with the 303c020b7ceSJuraj Linkeš highest id and continue in descending order. This ordering 304c020b7ceSJuraj Linkeš affects which sockets to consider first as well. 305c020b7ceSJuraj Linkeš :param prefix: set file prefix string, eg: 306c020b7ceSJuraj Linkeš prefix='vf' 307c020b7ceSJuraj Linkeš :param append_prefix_timestamp: if True, will append a timestamp to 308c020b7ceSJuraj Linkeš DPDK file prefix. 309c020b7ceSJuraj Linkeš :param no_pci: switch of disable PCI bus eg: 310c020b7ceSJuraj Linkeš no_pci=True 311c020b7ceSJuraj Linkeš :param vdevs: virtual device list, eg: 312c020b7ceSJuraj Linkeš vdevs=[ 313c020b7ceSJuraj Linkeš VirtualDevice('net_ring0'), 314c020b7ceSJuraj Linkeš VirtualDevice('net_ring1') 315c020b7ceSJuraj Linkeš ] 316c020b7ceSJuraj Linkeš :param other_eal_param: user defined DPDK eal parameters, eg: 317c020b7ceSJuraj Linkeš other_eal_param='--single-file-segments' 318c020b7ceSJuraj Linkeš :return: eal param string, eg: 319c020b7ceSJuraj Linkeš '-c 0xf -a 0000:88:00.0 --file-prefix=dpdk_1112_20190809143420'; 320c020b7ceSJuraj Linkeš """ 321c020b7ceSJuraj Linkeš 322c020b7ceSJuraj Linkeš lcore_list = LogicalCoreList( 323c020b7ceSJuraj Linkeš self.filter_lcores(lcore_filter_specifier, ascending_cores) 324c020b7ceSJuraj Linkeš ) 325c020b7ceSJuraj Linkeš 326c020b7ceSJuraj Linkeš if append_prefix_timestamp: 327c020b7ceSJuraj Linkeš prefix = f"{prefix}_{self._dpdk_timestamp}" 328c020b7ceSJuraj Linkeš prefix = self.main_session.get_dpdk_file_prefix(prefix) 329c020b7ceSJuraj Linkeš if prefix: 330c020b7ceSJuraj Linkeš self._dpdk_prefix_list.append(prefix) 331c020b7ceSJuraj Linkeš 332c020b7ceSJuraj Linkeš if vdevs is None: 333c020b7ceSJuraj Linkeš vdevs = [] 334c020b7ceSJuraj Linkeš 335c020b7ceSJuraj Linkeš return EalParameters( 336c020b7ceSJuraj Linkeš lcore_list=lcore_list, 337c020b7ceSJuraj Linkeš memory_channels=self.config.memory_channels, 338c020b7ceSJuraj Linkeš prefix=prefix, 339c020b7ceSJuraj Linkeš no_pci=no_pci, 340c020b7ceSJuraj Linkeš vdevs=vdevs, 341c020b7ceSJuraj Linkeš other_eal_param=other_eal_param, 342c020b7ceSJuraj Linkeš ) 343c020b7ceSJuraj Linkeš 344444833c0SJuraj Linkeš def run_dpdk_app( 345444833c0SJuraj Linkeš self, app_path: PurePath, eal_args: "EalParameters", timeout: float = 30 346444833c0SJuraj Linkeš ) -> CommandResult: 347444833c0SJuraj Linkeš """ 348444833c0SJuraj Linkeš Run DPDK application on the remote node. 349444833c0SJuraj Linkeš """ 350444833c0SJuraj Linkeš return self.main_session.send_command( 351b8bdc4c5SJuraj Linkeš f"{app_path} {eal_args}", timeout, privileged=True, verify=True 352444833c0SJuraj Linkeš ) 353444833c0SJuraj Linkeš 35488489c05SJeremy Spewock def create_interactive_shell( 355c020b7ceSJuraj Linkeš self, 35688489c05SJeremy Spewock shell_cls: Type[InteractiveShellType], 35788489c05SJeremy Spewock timeout: float = SETTINGS.timeout, 35888489c05SJeremy Spewock privileged: bool = False, 35988489c05SJeremy Spewock eal_parameters: EalParameters | str | None = None, 36088489c05SJeremy Spewock ) -> InteractiveShellType: 36188489c05SJeremy Spewock """Factory method for creating a handler for an interactive session. 362c020b7ceSJuraj Linkeš 36388489c05SJeremy Spewock Instantiate shell_cls according to the remote OS specifics. 36488489c05SJeremy Spewock 36588489c05SJeremy Spewock Args: 36688489c05SJeremy Spewock shell_cls: The class of the shell. 36788489c05SJeremy Spewock timeout: Timeout for reading output from the SSH channel. If you are 36888489c05SJeremy Spewock reading from the buffer and don't receive any data within the timeout 36988489c05SJeremy Spewock it will throw an error. 37088489c05SJeremy Spewock privileged: Whether to run the shell with administrative privileges. 37188489c05SJeremy Spewock eal_parameters: List of EAL parameters to use to launch the app. If this 37288489c05SJeremy Spewock isn't provided or an empty string is passed, it will default to calling 37388489c05SJeremy Spewock create_eal_parameters(). 37488489c05SJeremy Spewock Returns: 37588489c05SJeremy Spewock Instance of the desired interactive application. 37688489c05SJeremy Spewock """ 37788489c05SJeremy Spewock if not eal_parameters: 37888489c05SJeremy Spewock eal_parameters = self.create_eal_parameters() 37988489c05SJeremy Spewock 38088489c05SJeremy Spewock # We need to append the build directory for DPDK apps 38188489c05SJeremy Spewock if shell_cls.dpdk_app: 38288489c05SJeremy Spewock shell_cls.path = self.main_session.join_remote_path( 38388489c05SJeremy Spewock self.remote_dpdk_build_dir, shell_cls.path 38488489c05SJeremy Spewock ) 38588489c05SJeremy Spewock 38688489c05SJeremy Spewock return super().create_interactive_shell( 38788489c05SJeremy Spewock shell_cls, timeout, privileged, str(eal_parameters) 388c020b7ceSJuraj Linkeš ) 389