Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/134395/?format=api
http://patches.dpdk.org/api/patches/134395/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/patch/20231115130959.39420-19-juraj.linkes@pantheon.tech/", "project": { "id": 1, "url": "http://patches.dpdk.org/api/projects/1/?format=api", "name": "DPDK", "link_name": "dpdk", "list_id": "dev.dpdk.org", "list_email": "dev@dpdk.org", "web_url": "http://core.dpdk.org", "scm_url": "git://dpdk.org/dpdk", "webscm_url": "http://git.dpdk.org/dpdk", "list_archive_url": "https://inbox.dpdk.org/dev", "list_archive_url_format": "https://inbox.dpdk.org/dev/{}", "commit_url_format": "" }, "msgid": "<20231115130959.39420-19-juraj.linkes@pantheon.tech>", "list_archive_url": "https://inbox.dpdk.org/dev/20231115130959.39420-19-juraj.linkes@pantheon.tech", "date": "2023-11-15T13:09:56", "name": "[v7,18/21] dts: sut and tg nodes docstring update", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": true, "hash": "4987c4fe40000842c4e1e7300e8230eb3561c89c", "submitter": { "id": 1626, "url": "http://patches.dpdk.org/api/people/1626/?format=api", "name": "Juraj Linkeš", "email": "juraj.linkes@pantheon.tech" }, "delegate": { "id": 1, "url": "http://patches.dpdk.org/api/users/1/?format=api", "username": "tmonjalo", "first_name": "Thomas", "last_name": "Monjalon", "email": "thomas@monjalon.net" }, "mbox": "http://patches.dpdk.org/project/dpdk/patch/20231115130959.39420-19-juraj.linkes@pantheon.tech/mbox/", "series": [ { "id": 30302, "url": "http://patches.dpdk.org/api/series/30302/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=30302", "date": "2023-11-15T13:09:38", "name": "dts: docstrings update", "version": 7, "mbox": "http://patches.dpdk.org/series/30302/mbox/" } ], "comments": "http://patches.dpdk.org/api/patches/134395/comments/", "check": "success", "checks": "http://patches.dpdk.org/api/patches/134395/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<dev-bounces@dpdk.org>", "X-Original-To": "patchwork@inbox.dpdk.org", "Delivered-To": "patchwork@inbox.dpdk.org", "Received": [ "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id F0EA143339;\n\tWed, 15 Nov 2023 14:14:09 +0100 (CET)", "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id B20F74114B;\n\tWed, 15 Nov 2023 14:12:20 +0100 (CET)", "from mail-ed1-f42.google.com (mail-ed1-f42.google.com\n [209.85.208.42]) by mails.dpdk.org (Postfix) with ESMTP id 94AC6410F6\n for <dev@dpdk.org>; Wed, 15 Nov 2023 14:12:15 +0100 (CET)", "by mail-ed1-f42.google.com with SMTP id\n 4fb4d7f45d1cf-53e3b8f906fso10355924a12.2\n for <dev@dpdk.org>; Wed, 15 Nov 2023 05:12:15 -0800 (PST)", "from jlinkes-PT-Latitude-5530.pantheon.local\n (81.89.53.154.host.vnet.sk. [81.89.53.154])\n by smtp.gmail.com with ESMTPSA id\n tb16-20020a1709078b9000b009f2b7282387sm1011914ejc.46.2023.11.15.05.12.13\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Wed, 15 Nov 2023 05:12:14 -0800 (PST)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=pantheon.tech; s=google; t=1700053935; x=1700658735; darn=dpdk.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=C7ydtWmwUXlZj9C3QriL/vnjaRjG/RxKRJvVTYnZhi4=;\n b=obM8ionti033ySS/zrPseAcGCcPzDzSELUIeYaPJgotS5s2gF7n0ZcnN1R4SKONljz\n FmWjaQ1h9l7RsXBuse/beVsp3POcTev9iMshw4OgN/4PsxFlgq6jWa/daTxRWSxJ4lCG\n qrcTBCaoALpAkfCzw3G7KLzpKsjwk30C5WfGVQLm7QawAOFZ2op0OQhkODLFz330nf43\n P/pewziLbnP5mKK4zDVo4s8trgud04LWe89VymhP89KxS37RA+hCygKeHRtrerVcTCLT\n P2lBTqHFIxNpuRoEeddntVJeZmceVENpCTGQvhSb09VLW5YWx3r7QDS5cL+T33AJIUk+\n C3UA==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1700053935; x=1700658735;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=C7ydtWmwUXlZj9C3QriL/vnjaRjG/RxKRJvVTYnZhi4=;\n b=avRZtoqNGFWUip2JSfgWTcFrMCDt1rqcfXV3ToiIyNVCpp0rSbywjJj1ObS7d4sCeI\n aYrhED+nSha9mEt3jIkPyKtAdGPSFn8cRa4YCoFvi6FIOivKPYzJr1Zg0mL5X3g2s+Iy\n iwVTfECIPxIXe6pLsp8c4zx51RL6cdo58RuExnwoAQWO7byjXc0+FzA/Hd9VptrXVS3Z\n IKgBD5SoyHL0rLvwuRlgf3hN9b9QzSqOiwg25Ksz5HIc95s5Tw+xhVb9Fzru4Ofn/mBe\n KdKd1Kje5rwasry2x4236Fy28Duqk+rMd27WMcG1G4QbbydQqhCYqc9UxUd/GHcCw5xl\n j32w==", "X-Gm-Message-State": "AOJu0YyXlkP2gYqqavYxZ3yb+40cWNklS2VqWbmZdjTRkgjiIVUh4VPG\n 2GsKy/YNlHzDy3FLwz2k8eUvww==", "X-Google-Smtp-Source": "\n AGHT+IEiTEWTKt0YaLD29r3eDfmi/yGetZO4ODCWLeKaP3D8luqs/R8HKtM/Ld70mEsiul+GqOV5JQ==", "X-Received": "by 2002:a17:906:3942:b0:9e3:b88c:d735 with SMTP id\n g2-20020a170906394200b009e3b88cd735mr8911065eje.61.1700053935044;\n Wed, 15 Nov 2023 05:12:15 -0800 (PST)", "From": "=?utf-8?q?Juraj_Linke=C5=A1?= <juraj.linkes@pantheon.tech>", "To": "thomas@monjalon.net, Honnappa.Nagarahalli@arm.com, jspewock@iol.unh.edu,\n probb@iol.unh.edu, paul.szczepanek@arm.com, yoan.picchi@foss.arm.com", "Cc": "dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= <juraj.linkes@pantheon.tech>", "Subject": "[PATCH v7 18/21] dts: sut and tg nodes docstring update", "Date": "Wed, 15 Nov 2023 14:09:56 +0100", "Message-Id": "<20231115130959.39420-19-juraj.linkes@pantheon.tech>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20231115130959.39420-1-juraj.linkes@pantheon.tech>", "References": "<20231108125324.191005-23-juraj.linkes@pantheon.tech>\n <20231115130959.39420-1-juraj.linkes@pantheon.tech>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "dev@dpdk.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "DPDK patches and discussions <dev.dpdk.org>", "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>", "List-Archive": "<http://mails.dpdk.org/archives/dev/>", "List-Post": "<mailto:dev@dpdk.org>", "List-Help": "<mailto:dev-request@dpdk.org?subject=help>", "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>", "Errors-To": "dev-bounces@dpdk.org" }, "content": "Format according to the Google format and PEP257, with slight\ndeviations.\n\nSigned-off-by: Juraj Linkeš <juraj.linkes@pantheon.tech>\n---\n dts/framework/testbed_model/sut_node.py | 224 ++++++++++++++++--------\n dts/framework/testbed_model/tg_node.py | 42 +++--\n 2 files changed, 173 insertions(+), 93 deletions(-)", "diff": "diff --git a/dts/framework/testbed_model/sut_node.py b/dts/framework/testbed_model/sut_node.py\nindex 17deea06e2..123b16fee0 100644\n--- a/dts/framework/testbed_model/sut_node.py\n+++ b/dts/framework/testbed_model/sut_node.py\n@@ -3,6 +3,14 @@\n # Copyright(c) 2023 PANTHEON.tech s.r.o.\n # Copyright(c) 2023 University of New Hampshire\n \n+\"\"\"System under test (DPDK + hardware) node.\n+\n+A system under test (SUT) is the combination of DPDK\n+and the hardware we're testing with DPDK (NICs, crypto and other devices).\n+An SUT node is where this SUT runs.\n+\"\"\"\n+\n+\n import os\n import tarfile\n import time\n@@ -26,6 +34,11 @@\n \n \n class EalParameters(object):\n+ \"\"\"The environment abstraction layer parameters.\n+\n+ The string representation can be created by converting the instance to a string.\n+ \"\"\"\n+\n def __init__(\n self,\n lcore_list: LogicalCoreList,\n@@ -35,21 +48,23 @@ def __init__(\n vdevs: list[VirtualDevice],\n other_eal_param: str,\n ):\n- \"\"\"\n- Generate eal parameters character string;\n- :param lcore_list: the list of logical cores to use.\n- :param memory_channels: the number of memory channels to use.\n- :param prefix: set file prefix string, eg:\n- prefix='vf'\n- :param no_pci: switch of disable PCI bus eg:\n- no_pci=True\n- :param vdevs: virtual device list, eg:\n- vdevs=[\n- VirtualDevice('net_ring0'),\n- VirtualDevice('net_ring1')\n- ]\n- :param other_eal_param: user defined DPDK eal parameters, eg:\n- other_eal_param='--single-file-segments'\n+ \"\"\"Initialize the parameters according to inputs.\n+\n+ Process the parameters into the format used on the command line.\n+\n+ Args:\n+ lcore_list: The list of logical cores to use.\n+ memory_channels: The number of memory channels to use.\n+ prefix: Set the file prefix string with which to start DPDK, e.g.: ``prefix='vf'``.\n+ no_pci: Switch to disable PCI bus e.g.: ``no_pci=True``.\n+ vdevs: Virtual devices, e.g.::\n+\n+ vdevs=[\n+ VirtualDevice('net_ring0'),\n+ VirtualDevice('net_ring1')\n+ ]\n+ other_eal_param: user defined DPDK EAL parameters, e.g.:\n+ ``other_eal_param='--single-file-segments'``\n \"\"\"\n self._lcore_list = f\"-l {lcore_list}\"\n self._memory_channels = f\"-n {memory_channels}\"\n@@ -61,6 +76,7 @@ def __init__(\n self._other_eal_param = other_eal_param\n \n def __str__(self) -> str:\n+ \"\"\"Create the EAL string.\"\"\"\n return (\n f\"{self._lcore_list} \"\n f\"{self._memory_channels} \"\n@@ -72,11 +88,21 @@ def __str__(self) -> str:\n \n \n class SutNode(Node):\n- \"\"\"\n- A class for managing connections to the System under Test, providing\n- methods that retrieve the necessary information about the node (such as\n- CPU, memory and NIC details) and configuration capabilities.\n- Another key capability is building DPDK according to given build target.\n+ \"\"\"The system under test node.\n+\n+ The SUT node extends :class:`Node` with DPDK specific features:\n+\n+ * DPDK build,\n+ * Gathering of DPDK build info,\n+ * The running of DPDK apps, interactively or one-time execution,\n+ * DPDK apps cleanup.\n+\n+ The :option:`--tarball` command line argument and the :envvar:`DTS_DPDK_TARBALL`\n+ environment variable configure the path to the DPDK tarball\n+ or the git commit ID, tag ID or tree ID to test.\n+\n+ Attributes:\n+ config: The SUT node configuration\n \"\"\"\n \n config: SutNodeConfiguration\n@@ -94,6 +120,11 @@ class SutNode(Node):\n _path_to_devbind_script: PurePath | None\n \n def __init__(self, node_config: SutNodeConfiguration):\n+ \"\"\"Extend the constructor with SUT node specifics.\n+\n+ Args:\n+ node_config: The SUT node's test run configuration.\n+ \"\"\"\n super(SutNode, self).__init__(node_config)\n self._dpdk_prefix_list = []\n self._build_target_config = None\n@@ -113,6 +144,12 @@ def __init__(self, node_config: SutNodeConfiguration):\n \n @property\n def _remote_dpdk_dir(self) -> PurePath:\n+ \"\"\"The remote DPDK dir.\n+\n+ This internal property should be set after extracting the DPDK tarball. If it's not set,\n+ that implies the DPDK setup step has been skipped, in which case we can guess where\n+ a previous build was located.\n+ \"\"\"\n if self.__remote_dpdk_dir is None:\n self.__remote_dpdk_dir = self._guess_dpdk_remote_dir()\n return self.__remote_dpdk_dir\n@@ -123,6 +160,11 @@ def _remote_dpdk_dir(self, value: PurePath) -> None:\n \n @property\n def remote_dpdk_build_dir(self) -> PurePath:\n+ \"\"\"The remote DPDK build directory.\n+\n+ This is the directory where DPDK was built.\n+ We assume it was built in a subdirectory of the extracted tarball.\n+ \"\"\"\n if self._build_target_config:\n return self.main_session.join_remote_path(\n self._remote_dpdk_dir, self._build_target_config.name\n@@ -132,6 +174,7 @@ def remote_dpdk_build_dir(self) -> PurePath:\n \n @property\n def dpdk_version(self) -> str:\n+ \"\"\"Last built DPDK version.\"\"\"\n if self._dpdk_version is None:\n self._dpdk_version = self.main_session.get_dpdk_version(\n self._remote_dpdk_dir\n@@ -140,12 +183,14 @@ def dpdk_version(self) -> str:\n \n @property\n def node_info(self) -> NodeInfo:\n+ \"\"\"Additional node information.\"\"\"\n if self._node_info is None:\n self._node_info = self.main_session.get_node_info()\n return self._node_info\n \n @property\n def compiler_version(self) -> str:\n+ \"\"\"The node's compiler version.\"\"\"\n if self._compiler_version is None:\n if self._build_target_config is not None:\n self._compiler_version = self.main_session.get_compiler_version(\n@@ -161,6 +206,7 @@ def compiler_version(self) -> str:\n \n @property\n def path_to_devbind_script(self) -> PurePath:\n+ \"\"\"The path to the dpdk-devbind.py script on the node.\"\"\"\n if self._path_to_devbind_script is None:\n self._path_to_devbind_script = self.main_session.join_remote_path(\n self._remote_dpdk_dir, \"usertools\", \"dpdk-devbind.py\"\n@@ -168,6 +214,11 @@ def path_to_devbind_script(self) -> PurePath:\n return self._path_to_devbind_script\n \n def get_build_target_info(self) -> BuildTargetInfo:\n+ \"\"\"Get additional build target information.\n+\n+ Returns:\n+ The build target information,\n+ \"\"\"\n return BuildTargetInfo(\n dpdk_version=self.dpdk_version, compiler_version=self.compiler_version\n )\n@@ -178,8 +229,9 @@ def _guess_dpdk_remote_dir(self) -> PurePath:\n def _set_up_build_target(\n self, build_target_config: BuildTargetConfiguration\n ) -> None:\n- \"\"\"\n- Setup DPDK on the SUT node.\n+ \"\"\"Setup DPDK on the SUT node.\n+\n+ Additional build target setup steps on top of those in :class:`Node`.\n \"\"\"\n # we want to ensure that dpdk_version and compiler_version is reset for new\n # build targets\n@@ -200,9 +252,7 @@ def _tear_down_build_target(self) -> None:\n def _configure_build_target(\n self, build_target_config: BuildTargetConfiguration\n ) -> None:\n- \"\"\"\n- Populate common environment variables and set build target config.\n- \"\"\"\n+ \"\"\"Populate common environment variables and set build target config.\"\"\"\n self._env_vars = {}\n self._build_target_config = build_target_config\n self._env_vars.update(\n@@ -217,9 +267,7 @@ def _configure_build_target(\n \n @Node.skip_setup\n def _copy_dpdk_tarball(self) -> None:\n- \"\"\"\n- Copy to and extract DPDK tarball on the SUT node.\n- \"\"\"\n+ \"\"\"Copy to and extract DPDK tarball on the SUT node.\"\"\"\n self._logger.info(\"Copying DPDK tarball to SUT.\")\n self.main_session.copy_to(SETTINGS.dpdk_tarball_path, self._remote_tmp_dir)\n \n@@ -250,8 +298,9 @@ def _copy_dpdk_tarball(self) -> None:\n \n @Node.skip_setup\n def _build_dpdk(self) -> None:\n- \"\"\"\n- Build DPDK. Uses the already configured target. Assumes that the tarball has\n+ \"\"\"Build DPDK.\n+\n+ Uses the already configured target. Assumes that the tarball has\n already been copied to and extracted on the SUT node.\n \"\"\"\n self.main_session.build_dpdk(\n@@ -262,15 +311,19 @@ def _build_dpdk(self) -> None:\n )\n \n def build_dpdk_app(self, app_name: str, **meson_dpdk_args: str | bool) -> PurePath:\n- \"\"\"\n- Build one or all DPDK apps. Requires DPDK to be already built on the SUT node.\n- When app_name is 'all', build all example apps.\n- When app_name is any other string, tries to build that example app.\n- Return the directory path of the built app. If building all apps, return\n- the path to the examples directory (where all apps reside).\n- The meson_dpdk_args are keyword arguments\n- found in meson_option.txt in root DPDK directory. Do not use -D with them,\n- for example: enable_kmods=True.\n+ \"\"\"Build one or all DPDK apps.\n+\n+ Requires DPDK to be already built on the SUT node.\n+\n+ Args:\n+ app_name: The name of the DPDK app to build.\n+ When `app_name` is ``all``, build all example apps.\n+ meson_dpdk_args: The arguments found in ``meson_options.txt`` in root DPDK directory.\n+ Do not use ``-D`` with them.\n+\n+ Returns:\n+ The directory path of the built app. If building all apps, return\n+ the path to the examples directory (where all apps reside).\n \"\"\"\n self.main_session.build_dpdk(\n self._env_vars,\n@@ -291,9 +344,7 @@ def build_dpdk_app(self, app_name: str, **meson_dpdk_args: str | bool) -> PurePa\n )\n \n def kill_cleanup_dpdk_apps(self) -> None:\n- \"\"\"\n- Kill all dpdk applications on the SUT. Cleanup hugepages.\n- \"\"\"\n+ \"\"\"Kill all dpdk applications on the SUT, then clean up hugepages.\"\"\"\n if self._dpdk_kill_session and self._dpdk_kill_session.is_alive():\n # we can use the session if it exists and responds\n self._dpdk_kill_session.kill_cleanup_dpdk_apps(self._dpdk_prefix_list)\n@@ -312,33 +363,34 @@ def create_eal_parameters(\n vdevs: list[VirtualDevice] | None = None,\n other_eal_param: str = \"\",\n ) -> \"EalParameters\":\n- \"\"\"\n- Generate eal parameters character string;\n- :param lcore_filter_specifier: a number of lcores/cores/sockets to use\n- or a list of lcore ids to use.\n- The default will select one lcore for each of two cores\n- on one socket, in ascending order of core ids.\n- :param ascending_cores: True, use cores with the lowest numerical id first\n- and continue in ascending order. If False, start with the\n- highest id and continue in descending order. This ordering\n- affects which sockets to consider first as well.\n- :param prefix: set file prefix string, eg:\n- prefix='vf'\n- :param append_prefix_timestamp: if True, will append a timestamp to\n- DPDK file prefix.\n- :param no_pci: switch of disable PCI bus eg:\n- no_pci=True\n- :param vdevs: virtual device list, eg:\n- vdevs=[\n- VirtualDevice('net_ring0'),\n- VirtualDevice('net_ring1')\n- ]\n- :param other_eal_param: user defined DPDK eal parameters, eg:\n- other_eal_param='--single-file-segments'\n- :return: eal param string, eg:\n- '-c 0xf -a 0000:88:00.0 --file-prefix=dpdk_1112_20190809143420';\n- \"\"\"\n+ \"\"\"Compose the EAL parameters.\n+\n+ Process the list of cores and the DPDK prefix and pass that along with\n+ the rest of the arguments.\n \n+ Args:\n+ lcore_filter_specifier: A number of lcores/cores/sockets to use\n+ or a list of lcore ids to use.\n+ The default will select one lcore for each of two cores\n+ on one socket, in ascending order of core ids.\n+ ascending_cores: Sort cores in ascending order (lowest to highest IDs).\n+ If :data:`False`, sort in descending order.\n+ prefix: Set the file prefix string with which to start DPDK, e.g.: ``prefix='vf'``.\n+ append_prefix_timestamp: If :data:`True`, will append a timestamp to DPDK file prefix.\n+ no_pci: Switch to disable PCI bus e.g.: ``no_pci=True``.\n+ vdevs: Virtual devices, e.g.::\n+\n+ vdevs=[\n+ VirtualDevice('net_ring0'),\n+ VirtualDevice('net_ring1')\n+ ]\n+ other_eal_param: user defined DPDK EAL parameters, e.g.:\n+ ``other_eal_param='--single-file-segments'``.\n+\n+ Returns:\n+ An EAL param string, such as\n+ ``-c 0xf -a 0000:88:00.0 --file-prefix=dpdk_1112_20190809143420``.\n+ \"\"\"\n lcore_list = LogicalCoreList(\n self.filter_lcores(lcore_filter_specifier, ascending_cores)\n )\n@@ -364,14 +416,29 @@ def create_eal_parameters(\n def run_dpdk_app(\n self, app_path: PurePath, eal_args: \"EalParameters\", timeout: float = 30\n ) -> CommandResult:\n- \"\"\"\n- Run DPDK application on the remote node.\n+ \"\"\"Run DPDK application on the remote node.\n+\n+ The application is not run interactively - the command that starts the application\n+ is executed and then the call waits for it to finish execution.\n+\n+ Args:\n+ app_path: The remote path to the DPDK application.\n+ eal_args: EAL parameters to run the DPDK application with.\n+ timeout: Wait at most this long in seconds to execute the command.\n+\n+ Returns:\n+ The result of the DPDK app execution.\n \"\"\"\n return self.main_session.send_command(\n f\"{app_path} {eal_args}\", timeout, privileged=True, verify=True\n )\n \n def configure_ipv4_forwarding(self, enable: bool) -> None:\n+ \"\"\"Enable/disable IPv4 forwarding on the node.\n+\n+ Args:\n+ enable: If :data:`True`, enable the forwarding, otherwise disable it.\n+ \"\"\"\n self.main_session.configure_ipv4_forwarding(enable)\n \n def create_interactive_shell(\n@@ -381,9 +448,13 @@ def create_interactive_shell(\n privileged: bool = False,\n eal_parameters: EalParameters | str | None = None,\n ) -> InteractiveShellType:\n- \"\"\"Factory method for creating a handler for an interactive session.\n+ \"\"\"Extend the factory for interactive session handlers.\n+\n+ The extensions are SUT node specific:\n \n- Instantiate shell_cls according to the remote OS specifics.\n+ * The default for `eal_parameters`,\n+ * The interactive shell path `shell_cls.path` is prepended with path to the remote\n+ DPDK build directory for DPDK apps.\n \n Args:\n shell_cls: The class of the shell.\n@@ -393,9 +464,10 @@ def create_interactive_shell(\n privileged: Whether to run the shell with administrative privileges.\n eal_parameters: List of EAL parameters to use to launch the app. If this\n isn't provided or an empty string is passed, it will default to calling\n- create_eal_parameters().\n+ :meth:`create_eal_parameters`.\n+\n Returns:\n- Instance of the desired interactive application.\n+ An instance of the desired interactive application shell.\n \"\"\"\n if not eal_parameters:\n eal_parameters = self.create_eal_parameters()\n@@ -414,8 +486,8 @@ def bind_ports_to_driver(self, for_dpdk: bool = True) -> None:\n \"\"\"Bind all ports on the SUT to a driver.\n \n Args:\n- for_dpdk: Boolean that, when True, binds ports to os_driver_for_dpdk\n- or, when False, binds to os_driver. Defaults to True.\n+ for_dpdk: If :data:`True`, binds ports to os_driver_for_dpdk.\n+ If :data:`False`, binds to os_driver.\n \"\"\"\n for port in self.ports:\n driver = port.os_driver_for_dpdk if for_dpdk else port.os_driver\ndiff --git a/dts/framework/testbed_model/tg_node.py b/dts/framework/testbed_model/tg_node.py\nindex 166eb8430e..69eb33ccb1 100644\n--- a/dts/framework/testbed_model/tg_node.py\n+++ b/dts/framework/testbed_model/tg_node.py\n@@ -5,13 +5,8 @@\n \n \"\"\"Traffic generator node.\n \n-This is the node where the traffic generator resides.\n-The distinction between a node and a traffic generator is as follows:\n-A node is a host that DTS connects to. It could be a baremetal server,\n-a VM or a container.\n-A traffic generator is software running on the node.\n-A traffic generator node is a node running a traffic generator.\n-A node can be a traffic generator node as well as system under test node.\n+A traffic generator (TG) generates traffic that's sent towards the SUT node.\n+A TG node is where the TG runs.\n \"\"\"\n \n from scapy.packet import Packet # type: ignore[import]\n@@ -24,13 +19,16 @@\n \n \n class TGNode(Node):\n- \"\"\"Manage connections to a node with a traffic generator.\n+ \"\"\"The traffic generator node.\n \n- Apart from basic node management capabilities, the Traffic Generator node has\n- specialized methods for handling the traffic generator running on it.\n+ The TG node extends :class:`Node` with TG specific features:\n \n- Arguments:\n- node_config: The user configuration of the traffic generator node.\n+ * Traffic generator initialization,\n+ * The sending of traffic and receiving packets,\n+ * The sending of traffic without receiving packets.\n+\n+ Not all traffic generators are capable of capturing traffic, which is why there\n+ must be a way to send traffic without that.\n \n Attributes:\n traffic_generator: The traffic generator running on the node.\n@@ -39,6 +37,13 @@ class TGNode(Node):\n traffic_generator: CapturingTrafficGenerator\n \n def __init__(self, node_config: TGNodeConfiguration):\n+ \"\"\"Extend the constructor with TG node specifics.\n+\n+ Initialize the traffic generator on the TG node.\n+\n+ Args:\n+ node_config: The TG node's test run configuration.\n+ \"\"\"\n super(TGNode, self).__init__(node_config)\n self.traffic_generator = create_traffic_generator(\n self, node_config.traffic_generator\n@@ -52,17 +57,17 @@ def send_packet_and_capture(\n receive_port: Port,\n duration: float = 1,\n ) -> list[Packet]:\n- \"\"\"Send a packet, return received traffic.\n+ \"\"\"Send `packet`, return received traffic.\n \n- Send a packet on the send_port and then return all traffic captured\n- on the receive_port for the given duration. Also record the captured traffic\n+ Send `packet` on `send_port` and then return all traffic captured\n+ on `receive_port` for the given duration. Also record the captured traffic\n in a pcap file.\n \n Args:\n packet: The packet to send.\n send_port: The egress port on the TG node.\n receive_port: The ingress port in the TG node.\n- duration: Capture traffic for this amount of time after sending the packet.\n+ duration: Capture traffic for this amount of time after sending `packet`.\n \n Returns:\n A list of received packets. May be empty if no packets are captured.\n@@ -72,6 +77,9 @@ def send_packet_and_capture(\n )\n \n def close(self) -> None:\n- \"\"\"Free all resources used by the node\"\"\"\n+ \"\"\"Free all resources used by the node.\n+\n+ This extends the superclass method with TG cleanup.\n+ \"\"\"\n self.traffic_generator.close()\n super(TGNode, self).close()\n", "prefixes": [ "v7", "18/21" ] }{ "id": 134395, "url": "