get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/138159/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 138159,
    "url": "http://patchwork.dpdk.org/api/patches/138159/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20240311154405.13269-2-jspewock@iol.unh.edu/",
    "project": {
        "id": 1,
        "url": "http://patchwork.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": "<20240311154405.13269-2-jspewock@iol.unh.edu>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240311154405.13269-2-jspewock@iol.unh.edu",
    "date": "2024-03-11T15:43:59",
    "name": "[v9,1/7] dts: add startup verification and forwarding modes to testpmd shell",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "f1efa2bd0fd8f96ad372aa588731c64ec97c08a7",
    "submitter": {
        "id": 2772,
        "url": "http://patchwork.dpdk.org/api/people/2772/?format=api",
        "name": "Jeremy Spewock",
        "email": "jspewock@iol.unh.edu"
    },
    "delegate": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20240311154405.13269-2-jspewock@iol.unh.edu/mbox/",
    "series": [
        {
            "id": 31463,
            "url": "http://patchwork.dpdk.org/api/series/31463/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=31463",
            "date": "2024-03-11T15:43:58",
            "name": "dts: Port scatter suite over",
            "version": 9,
            "mbox": "http://patchwork.dpdk.org/series/31463/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/138159/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/138159/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 89B1543C89;\n\tMon, 11 Mar 2024 16:44:56 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 46D5740A87;\n\tMon, 11 Mar 2024 16:44:54 +0100 (CET)",
            "from mail-pj1-f100.google.com (mail-pj1-f100.google.com\n [209.85.216.100])\n by mails.dpdk.org (Postfix) with ESMTP id 6381040A87\n for <dev@dpdk.org>; Mon, 11 Mar 2024 16:44:53 +0100 (CET)",
            "by mail-pj1-f100.google.com with SMTP id\n 98e67ed59e1d1-29bbff1505dso1341254a91.0\n for <dev@dpdk.org>; Mon, 11 Mar 2024 08:44:53 -0700 (PDT)",
            "from postal.iol.unh.edu (postal.iol.unh.edu.\n [2606:4100:3880:1234::84]) by smtp-relay.gmail.com with ESMTPS id\n w12-20020a17090ad60c00b0029b47c6149csm458647pju.6.2024.03.11.08.44.52\n (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);\n Mon, 11 Mar 2024 08:44:52 -0700 (PDT)",
            "from iol.unh.edu (unknown\n [IPv6:2606:4100:3880:1271:90f9:1b64:f6e6:867f])\n by postal.iol.unh.edu (Postfix) with ESMTP id A32876052471;\n Mon, 11 Mar 2024 11:44:51 -0400 (EDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=iol.unh.edu; s=unh-iol; t=1710171892; x=1710776692; 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=azS1COg8qyO8b0ezY6bm30EXaPEL2CnFBabHOARvho4=;\n b=EUVYXhZm0e3q9InBlVdBwNKAbKyqnHUvcceQClyzTbdIlocaj/RO0uyNo5KO/hEI87\n I3sw6o2fyfwamYe4qBEDmhKZookszcIT8NMooXQ0/+2mbOLP76v/ajJY3/5mj2AE/Zjh\n 4zVZom8BiA7lXbQwTZtmRQ++lR0UwBSgN2J7I=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1710171892; x=1710776692;\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=azS1COg8qyO8b0ezY6bm30EXaPEL2CnFBabHOARvho4=;\n b=rlRDk5r3mjw3AeTkI1taMBzGg1+FEmLssueFCJ893CKLKQJOAoE+mSCX5PH9QQaFxU\n fONRFEyR6WcNuVms3FkpVO0smM/2xm3sJgM6H5SN5VX6sARWXuYBEWIA5Ie2/CnQRkF2\n ga7VSq+hQsSDmWRIz/3U4UbDJuMBFFTtA6QKIqnzphze2bdxbbZbj+pLs1eQCAf9fW/k\n CGPtN+o4YT4Nhb0eyc8MaHZQyQRVh9r7hXfiqeYfPXJ4YuAIhzaGNjYA7Olg3n4b8Dn1\n JrIXaxPEHk/EWzJlNeUlx5cp16wHdFmoEX22GgjUA3MNRgFOBoDGYsPCxKQugsAyjsAP\n x0jA==",
        "X-Gm-Message-State": "AOJu0YyE1viU+a2HnX/JsUWEKuhZedaO+oPv9iXX/Walw8bzgX3SQbO5\n PZqNsR551R73Pu8C58sR5axkgQU26i4NBTCk8FBGLQfHI78bE0JRgnHCqNMHLn9WbyKV80KKYSO\n qgD6bu0GKqOd1Y96OZ9Vhryd9u3RVMieeiEQRmB7b+OemFr8h",
        "X-Google-Smtp-Source": "\n AGHT+IFq6SIPzx938h5YwR9GcH1Pux9Or8rMbBUBMw4K9Lx1nUnvVbPiFOSsIuWtjgW30f6zr9OqEojql4+5",
        "X-Received": "by 2002:a17:90a:f417:b0:299:a69:1f8b with SMTP id\n ch23-20020a17090af41700b002990a691f8bmr4884355pjb.23.1710171892577;\n Mon, 11 Mar 2024 08:44:52 -0700 (PDT)",
        "X-Relaying-Domain": "iol.unh.edu",
        "From": "jspewock@iol.unh.edu",
        "To": "Honnappa.Nagarahalli@arm.com, juraj.linkes@pantheon.tech,\n thomas@monjalon.net, wathsala.vithanage@arm.com, probb@iol.unh.edu,\n paul.szczepanek@arm.com, yoan.picchi@foss.arm.com, ferruh.yigit@amd.com,\n andrew.rybchenko@oktetlabs.ru",
        "Cc": "dev@dpdk.org,\n\tJeremy Spewock <jspewock@iol.unh.edu>",
        "Subject": "[PATCH v9 1/7] dts: add startup verification and forwarding modes to\n testpmd shell",
        "Date": "Mon, 11 Mar 2024 11:43:59 -0400",
        "Message-ID": "<20240311154405.13269-2-jspewock@iol.unh.edu>",
        "X-Mailer": "git-send-email 2.43.2",
        "In-Reply-To": "<20240311154405.13269-1-jspewock@iol.unh.edu>",
        "References": "<20240110144249.20719-1-jspewock@iol.unh.edu>\n <20240311154405.13269-1-jspewock@iol.unh.edu>",
        "MIME-Version": "1.0",
        "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": "From: Jeremy Spewock <jspewock@iol.unh.edu>\n\nAdded commonly used methods in testpmd such as starting and stopping\npacket forwarding, changing forward modes, and verifying link status of\nports so that developers can configure testpmd and start forwarding\nthrough the provided class rather than sending commands to the testpmd\nsession directly.\n\nSigned-off-by: Jeremy Spewock <jspewock@iol.unh.edu>\n---\n dts/framework/exception.py                    |   7 +\n dts/framework/remote_session/testpmd_shell.py | 149 +++++++++++++++++-\n 2 files changed, 155 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/dts/framework/exception.py b/dts/framework/exception.py\nindex 658eee2c38..cce1e0231a 100644\n--- a/dts/framework/exception.py\n+++ b/dts/framework/exception.py\n@@ -146,6 +146,13 @@ def __str__(self) -> str:\n         return f\"Command {self.command} returned a non-zero exit code: {self._command_return_code}\"\n \n \n+class InteractiveCommandExecutionError(DTSError):\n+    \"\"\"An unsuccessful execution of a remote command in an interactive environment.\"\"\"\n+\n+    #:\n+    severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR\n+\n+\n class RemoteDirectoryExistsError(DTSError):\n     \"\"\"A directory that exists on a remote node.\"\"\"\n \ndiff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py\nindex 0184cc2e71..3a66907394 100644\n--- a/dts/framework/remote_session/testpmd_shell.py\n+++ b/dts/framework/remote_session/testpmd_shell.py\n@@ -15,9 +15,15 @@\n     testpmd_shell.close()\n \"\"\"\n \n+import time\n+from enum import auto\n from pathlib import PurePath\n from typing import Callable, ClassVar\n \n+from framework.exception import InteractiveCommandExecutionError\n+from framework.settings import SETTINGS\n+from framework.utils import StrEnum\n+\n from .interactive_shell import InteractiveShell\n \n \n@@ -43,14 +49,51 @@ def __str__(self) -> str:\n         return self.pci_address\n \n \n+class TestPmdForwardingModes(StrEnum):\n+    r\"\"\"The supported packet forwarding modes for :class:`~TestPmdShell`\\s.\"\"\"\n+\n+    #:\n+    io = auto()\n+    #:\n+    mac = auto()\n+    #:\n+    macswap = auto()\n+    #:\n+    flowgen = auto()\n+    #:\n+    rxonly = auto()\n+    #:\n+    txonly = auto()\n+    #:\n+    csum = auto()\n+    #:\n+    icmpecho = auto()\n+    #:\n+    ieee1588 = auto()\n+    #:\n+    noisy = auto()\n+    #:\n+    fivetswap = \"5tswap\"\n+    #:\n+    shared_rxq = \"shared-rxq\"\n+    #:\n+    recycle_mbufs = auto()\n+\n+\n class TestPmdShell(InteractiveShell):\n     \"\"\"Testpmd interactive shell.\n \n     The testpmd shell users should never use\n     the :meth:`~.interactive_shell.InteractiveShell.send_command` method directly, but rather\n     call specialized methods. If there isn't one that satisfies a need, it should be added.\n+\n+    Attributes:\n+        number_of_ports: The number of ports which were allowed on the command-line when testpmd\n+            was started.\n     \"\"\"\n \n+    number_of_ports: int\n+\n     #: The path to the testpmd executable.\n     path: ClassVar[PurePath] = PurePath(\"app\", \"dpdk-testpmd\")\n \n@@ -65,9 +108,66 @@ class TestPmdShell(InteractiveShell):\n     _command_extra_chars: ClassVar[str] = \"\\n\"\n \n     def _start_application(self, get_privileged_command: Callable[[str], str] | None) -> None:\n-        self._app_args += \" -- -i\"\n+        \"\"\"Overrides :meth:`~.interactive_shell._start_application`.\n+\n+        Add flags for starting testpmd in interactive mode and disabling messages for link state\n+        change events before starting the application. Link state is verified before starting\n+        packet forwarding and the messages create unexpected newlines in the terminal which\n+        complicates output collection.\n+\n+        Also find the number of pci addresses which were allowed on the command line when the app\n+        was started.\n+        \"\"\"\n+        self._app_args += \" -- -i --mask-event intr_lsc\"\n+        self.number_of_ports = self._app_args.count(\"-a \")\n         super()._start_application(get_privileged_command)\n \n+    def start(self, verify: bool = True) -> None:\n+        \"\"\"Start packet forwarding with the current configuration.\n+\n+        Args:\n+            verify: If :data:`True` , a second start command will be sent in an attempt to verify\n+                packet forwarding started as expected.\n+\n+        Raises:\n+            InteractiveCommandExecutionError: If `verify` is :data:`True` and forwarding fails to\n+                start or ports fail to come up.\n+        \"\"\"\n+        self.send_command(\"start\")\n+        if verify:\n+            # If forwarding was already started, sending \"start\" again should tell us\n+            start_cmd_output = self.send_command(\"start\")\n+            if \"Packet forwarding already started\" not in start_cmd_output:\n+                self._logger.debug(f\"Failed to start packet forwarding: \\n{start_cmd_output}\")\n+                raise InteractiveCommandExecutionError(\"Testpmd failed to start packet forwarding.\")\n+\n+            for port_id in range(self.number_of_ports):\n+                if not self.wait_link_status_up(port_id):\n+                    raise InteractiveCommandExecutionError(\n+                        \"Not all ports came up after starting packet forwarding in testpmd.\"\n+                    )\n+\n+    def stop(self, verify: bool = True) -> None:\n+        \"\"\"Stop packet forwarding.\n+\n+        Args:\n+            verify: If :data:`True` , the output of the stop command is scanned to verify that\n+                forwarding was stopped successfully or not started. If neither is found, it is\n+                considered an error.\n+\n+        Raises:\n+            InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop\n+                forwarding results in an error.\n+        \"\"\"\n+        stop_cmd_output = self.send_command(\"stop\")\n+        if verify:\n+            if (\n+                \"Done.\" not in stop_cmd_output\n+                and \"Packet forwarding not started\" not in stop_cmd_output\n+            ):\n+                self._logger.debug(f\"Failed to stop packet forwarding: \\n{stop_cmd_output}\")\n+                raise InteractiveCommandExecutionError(\"Testpmd failed to stop packet forwarding.\")\n+\n     def get_devices(self) -> list[TestPmdDevice]:\n         \"\"\"Get a list of device names that are known to testpmd.\n \n@@ -82,3 +182,50 @@ def get_devices(self) -> list[TestPmdDevice]:\n             if \"device name:\" in line.lower():\n                 dev_list.append(TestPmdDevice(line))\n         return dev_list\n+\n+    def wait_link_status_up(self, port_id: int, timeout=SETTINGS.timeout) -> bool:\n+        \"\"\"Wait until the link status on the given port is \"up\".\n+\n+        Arguments:\n+            port_id: Port to check the link status on.\n+            timeout: Time to wait for the link to come up. The default value for this\n+                argument may be modified using the :option:`--timeout` command-line argument\n+                or the :envvar:`DTS_TIMEOUT` environment variable.\n+\n+        Returns:\n+            Whether the link came up in time or not.\n+        \"\"\"\n+        time_to_stop = time.time() + timeout\n+        port_info: str = \"\"\n+        while time.time() < time_to_stop:\n+            port_info = self.send_command(f\"show port info {port_id}\")\n+            if \"Link status: up\" in port_info:\n+                break\n+            time.sleep(0.5)\n+        else:\n+            self._logger.error(f\"The link for port {port_id} did not come up in the given timeout.\")\n+        return \"Link status: up\" in port_info\n+\n+    def set_forward_mode(self, mode: TestPmdForwardingModes, verify: bool = True):\n+        \"\"\"Set packet forwarding mode.\n+\n+        Args:\n+            mode: The forwarding mode to use.\n+            verify: If :data:`True` the output of the command will be scanned in an attempt to\n+                verify that the forwarding mode was set to `mode` properly.\n+\n+        Raises:\n+            InteractiveCommandExecutionError: If `verify` is :data:`True` and the forwarding mode\n+                fails to update.\n+        \"\"\"\n+        set_fwd_output = self.send_command(f\"set fwd {mode.value}\")\n+        if f\"Set {mode.value} packet forwarding mode\" not in set_fwd_output:\n+            self._logger.debug(f\"Failed to set fwd mode to {mode.value}:\\n{set_fwd_output}\")\n+            raise InteractiveCommandExecutionError(\n+                f\"Test pmd failed to set fwd mode to {mode.value}\"\n+            )\n+\n+    def close(self) -> None:\n+        \"\"\"Overrides :meth:`~.interactive_shell.close`.\"\"\"\n+        self.send_command(\"quit\", \"\")\n+        return super().close()\n",
    "prefixes": [
        "v9",
        "1/7"
    ]
}