get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 135716,
    "url": "http://patches.dpdk.org/api/patches/135716/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20240103223206.23129-4-jspewock@iol.unh.edu/",
    "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": "<20240103223206.23129-4-jspewock@iol.unh.edu>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240103223206.23129-4-jspewock@iol.unh.edu",
    "date": "2024-01-03T22:32:02",
    "name": "[v6,3/7] dts: add optional packet filtering to scapy sniffer",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "ebb97db774bd6fa4508d059194c1ba0f8912d60f",
    "submitter": {
        "id": 2772,
        "url": "http://patches.dpdk.org/api/people/2772/?format=api",
        "name": "Jeremy Spewock",
        "email": "jspewock@iol.unh.edu"
    },
    "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/20240103223206.23129-4-jspewock@iol.unh.edu/mbox/",
    "series": [
        {
            "id": 30714,
            "url": "http://patches.dpdk.org/api/series/30714/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=30714",
            "date": "2024-01-03T22:31:59",
            "name": "dts: Port scatter suite over",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/30714/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/135716/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/135716/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 455404380D;\n\tWed,  3 Jan 2024 23:33:15 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 3029E40A73;\n\tWed,  3 Jan 2024 23:33:10 +0100 (CET)",
            "from mail-qt1-f227.google.com (mail-qt1-f227.google.com\n [209.85.160.227])\n by mails.dpdk.org (Postfix) with ESMTP id 3CC1140A77\n for <dev@dpdk.org>; Wed,  3 Jan 2024 23:33:09 +0100 (CET)",
            "by mail-qt1-f227.google.com with SMTP id\n d75a77b69052e-4283cc63c04so2930211cf.1\n for <dev@dpdk.org>; Wed, 03 Jan 2024 14:33:09 -0800 (PST)",
            "from postal.iol.unh.edu (postal.iol.unh.edu.\n [2606:4100:3880:1234::84]) by smtp-relay.gmail.com with ESMTPS id\n t10-20020a05622a180a00b004283ffb8f80sm8395qtc.2.2024.01.03.14.33.08\n (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);\n Wed, 03 Jan 2024 14:33:08 -0800 (PST)",
            "from iol.unh.edu (unknown [IPv6:2606:4100:3880:1257::1083])\n by postal.iol.unh.edu (Postfix) with ESMTP id EAA43605C311;\n Wed,  3 Jan 2024 17:33:07 -0500 (EST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=iol.unh.edu; s=unh-iol; t=1704321188; x=1704925988; 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=G/fFLowcTHNLQrw5ls8IZ2ibWugX+AoKRyJMocHizh4=;\n b=H7XvlgNQebH2FyEYhqpxMlaBgyGJoOy0mfEhsaPmwnI8/734uKF9TR+yCUfK4hqb7v\n RfIwrUt3KS0o/8HVILDaQhLBklEIWN/Y3Q0xlTkiqw265G1ZNeymfs5kEKt8Cis19eBL\n cxjOM7C6FpXJjCuEeqj6sx8N9NAJ+U0vYUaiw=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1704321188; x=1704925988;\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=G/fFLowcTHNLQrw5ls8IZ2ibWugX+AoKRyJMocHizh4=;\n b=PEEMD5NAcOGHSxMhi3FVgdDeePkMtMluqJrPdHZc9xz57L9jI6WjScZqndxk3OptAf\n hCcimfM+6NGlWdcWm1yZwpxxWyY5s+q/EyKPjhR8b/3VaGx/Xl3CYLiCTiiqF0omo/9L\n w7nLIXoXVUNAOSd9q+3UqDWd331IIKOnGdtNaBEfemLXf2gIFs6lyF+UHjLnuaUPjns5\n YzrkBeE4ua/+6G4sC88r/BXI9n1Y8N2P/Fidr5hfLVhnNCAcAUNR7gJhjedZ3qR2ZZfV\n S/8DBV8U01mp/SUXdPIiNrsP3Ucu8SRFkrBcswFpC5t3rk/FFm9Fn1mg579SIA4a/+k5\n djwg==",
        "X-Gm-Message-State": "AOJu0YwfHwPxS9TsfLKMCrOoWq9cguXU9BGF9D5VnW/v8vF0djC8ySR9\n OzW8yhziaUGF8FrtQ/UPVZ5QjvAwkl4Syz7VEu1K/4UHWvuQyps4FJgo5jQdF/34kHtJgX3KnA=\n =",
        "X-Google-Smtp-Source": "\n AGHT+IHFJhlrZwLHqmti4jm6a5sJ63R/GpZZHIlHN0p7ImpePcgwF4O5hVOJkMs9ci2WFjVmnzPWYE8DrEWW",
        "X-Received": "by 2002:a05:622a:2c9:b0:427:8c57:5997 with SMTP id\n a9-20020a05622a02c900b004278c575997mr32402619qtx.65.1704321188686;\n Wed, 03 Jan 2024 14:33:08 -0800 (PST)",
        "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, lylavoie@iol.unh.edu,\n ferruh.yigit@amd.com, andrew.rybchenko@oktetlabs.ru",
        "Cc": "dev@dpdk.org,\n\tJeremy Spewock <jspewock@iol.unh.edu>",
        "Subject": "[PATCH v6 3/7] dts: add optional packet filtering to scapy sniffer",
        "Date": "Wed,  3 Jan 2024 17:32:02 -0500",
        "Message-ID": "<20240103223206.23129-4-jspewock@iol.unh.edu>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20240103223206.23129-1-jspewock@iol.unh.edu>",
        "References": "<20240103221217.18954-1-jspewock@iol.unh.edu>\n <20240103223206.23129-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 the options to filter out LLDP and ARP packets when\nsniffing for packets with scapy. This was done using BPF filters to\nensure that the noise these packets provide does not interfere with test\ncases.\n\nSigned-off-by: Jeremy Spewock <jspewock@iol.unh.edu>\n---\n dts/framework/test_suite.py                   | 15 +++++++++--\n dts/framework/testbed_model/tg_node.py        | 14 ++++++++--\n .../traffic_generator/__init__.py             |  7 ++++-\n .../capturing_traffic_generator.py            | 22 ++++++++++++++-\n .../testbed_model/traffic_generator/scapy.py  | 27 +++++++++++++++++++\n 5 files changed, 79 insertions(+), 6 deletions(-)",
    "diff": "diff --git a/dts/framework/test_suite.py b/dts/framework/test_suite.py\nindex dfb391ffbd..ffea917690 100644\n--- a/dts/framework/test_suite.py\n+++ b/dts/framework/test_suite.py\n@@ -38,6 +38,7 @@\n from .settings import SETTINGS\n from .test_result import BuildTargetResult, Result, TestCaseResult, TestSuiteResult\n from .testbed_model import Port, PortLink, SutNode, TGNode\n+from .testbed_model.traffic_generator import PacketFilteringConfig\n from .utils import get_packet_summaries\n \n \n@@ -208,7 +209,12 @@ def configure_testbed_ipv4(self, restore: bool = False) -> None:\n     def _configure_ipv4_forwarding(self, enable: bool) -> None:\n         self.sut_node.configure_ipv4_forwarding(enable)\n \n-    def send_packet_and_capture(self, packet: Packet, duration: float = 1) -> list[Packet]:\n+    def send_packet_and_capture(\n+        self,\n+        packet: Packet,\n+        filter_config: PacketFilteringConfig = PacketFilteringConfig(),\n+        duration: float = 1,\n+    ) -> list[Packet]:\n         \"\"\"Send and receive `packet` using the associated TG.\n \n         Send `packet` through the appropriate interface and receive on the appropriate interface.\n@@ -216,6 +222,7 @@ def send_packet_and_capture(self, packet: Packet, duration: float = 1) -> list[P\n \n         Args:\n             packet: The packet to send.\n+            filter_config: The filter to use when capturing packets.\n             duration: Capture traffic for this amount of time after sending `packet`.\n \n         Returns:\n@@ -223,7 +230,11 @@ def send_packet_and_capture(self, packet: Packet, duration: float = 1) -> list[P\n         \"\"\"\n         packet = self._adjust_addresses(packet)\n         return self.tg_node.send_packet_and_capture(\n-            packet, self._tg_port_egress, self._tg_port_ingress, duration\n+            packet,\n+            self._tg_port_egress,\n+            self._tg_port_ingress,\n+            filter_config,\n+            duration,\n         )\n \n     def get_expected_packet(self, packet: Packet) -> Packet:\ndiff --git a/dts/framework/testbed_model/tg_node.py b/dts/framework/testbed_model/tg_node.py\nindex f269d4c585..d3206e87e0 100644\n--- a/dts/framework/testbed_model/tg_node.py\n+++ b/dts/framework/testbed_model/tg_node.py\n@@ -15,7 +15,11 @@\n \n from .node import Node\n from .port import Port\n-from .traffic_generator import CapturingTrafficGenerator, create_traffic_generator\n+from .traffic_generator import (\n+    CapturingTrafficGenerator,\n+    PacketFilteringConfig,\n+    create_traffic_generator,\n+)\n \n \n class TGNode(Node):\n@@ -53,6 +57,7 @@ def send_packet_and_capture(\n         packet: Packet,\n         send_port: Port,\n         receive_port: Port,\n+        filter_config: PacketFilteringConfig = PacketFilteringConfig(),\n         duration: float = 1,\n     ) -> list[Packet]:\n         \"\"\"Send `packet`, return received traffic.\n@@ -65,13 +70,18 @@ def send_packet_and_capture(\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+            filter_config: The filter to use when capturing packets.\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         \"\"\"\n         return self.traffic_generator.send_packet_and_capture(\n-            packet, send_port, receive_port, duration\n+            packet,\n+            send_port,\n+            receive_port,\n+            filter_config,\n+            duration,\n         )\n \n     def close(self) -> None:\ndiff --git a/dts/framework/testbed_model/traffic_generator/__init__.py b/dts/framework/testbed_model/traffic_generator/__init__.py\nindex 11e2bd7d97..0eaf0355cd 100644\n--- a/dts/framework/testbed_model/traffic_generator/__init__.py\n+++ b/dts/framework/testbed_model/traffic_generator/__init__.py\n@@ -14,11 +14,16 @@\n and a capturing traffic generator is required.\n \"\"\"\n \n+# pylama:ignore=W0611\n+\n from framework.config import ScapyTrafficGeneratorConfig, TrafficGeneratorType\n from framework.exception import ConfigurationError\n from framework.testbed_model.node import Node\n \n-from .capturing_traffic_generator import CapturingTrafficGenerator\n+from .capturing_traffic_generator import (\n+    CapturingTrafficGenerator,\n+    PacketFilteringConfig,\n+)\n from .scapy import ScapyTrafficGenerator\n \n \ndiff --git a/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py\nindex 0246590333..c1c9facedd 100644\n--- a/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py\n+++ b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py\n@@ -11,6 +11,7 @@\n \n import uuid\n from abc import abstractmethod\n+from dataclasses import dataclass\n \n import scapy.utils  # type: ignore[import]\n from scapy.packet import Packet  # type: ignore[import]\n@@ -26,6 +27,19 @@ def _get_default_capture_name() -> str:\n     return str(uuid.uuid4())\n \n \n+@dataclass(slots=True)\n+class PacketFilteringConfig:\n+    \"\"\"The supported filtering options for :class:`CapturingTrafficGenerator`.\n+\n+    Attributes:\n+        no_lldp: If :data:`True`, LLDP packets will be filtered out when capturing.\n+        no_arp: If :data:`True`, ARP packets will be filtered out when capturing.\n+    \"\"\"\n+\n+    no_lldp: bool = True\n+    no_arp: bool = True\n+\n+\n class CapturingTrafficGenerator(TrafficGenerator):\n     \"\"\"Capture packets after sending traffic.\n \n@@ -54,6 +68,7 @@ def send_packet_and_capture(\n         packet: Packet,\n         send_port: Port,\n         receive_port: Port,\n+        filter_config: PacketFilteringConfig,\n         duration: float,\n         capture_name: str = _get_default_capture_name(),\n     ) -> list[Packet]:\n@@ -68,6 +83,7 @@ def send_packet_and_capture(\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+            filter_config: Filters to apply when capturing packets.\n             duration: Capture traffic for this amount of time after sending the packet.\n             capture_name: The name of the .pcap file where to store the capture.\n \n@@ -75,7 +91,7 @@ def send_packet_and_capture(\n              The received packets. May be empty if no packets are captured.\n         \"\"\"\n         return self.send_packets_and_capture(\n-            [packet], send_port, receive_port, duration, capture_name\n+            [packet], send_port, receive_port, filter_config, duration, capture_name\n         )\n \n     def send_packets_and_capture(\n@@ -83,6 +99,7 @@ def send_packets_and_capture(\n         packets: list[Packet],\n         send_port: Port,\n         receive_port: Port,\n+        filter_config: PacketFilteringConfig,\n         duration: float,\n         capture_name: str = _get_default_capture_name(),\n     ) -> list[Packet]:\n@@ -99,6 +116,7 @@ def send_packets_and_capture(\n             packets: The packets to send.\n             send_port: The egress port on the TG node.\n             receive_port: The ingress port in the TG node.\n+            filter_config: Filters to apply when capturing packets.\n             duration: Capture traffic for this amount of time after sending the packets.\n             capture_name: The name of the .pcap file where to store the capture.\n \n@@ -113,6 +131,7 @@ def send_packets_and_capture(\n             packets,\n             send_port,\n             receive_port,\n+            filter_config,\n             duration,\n         )\n \n@@ -126,6 +145,7 @@ def _send_packets_and_capture(\n         packets: list[Packet],\n         send_port: Port,\n         receive_port: Port,\n+        filter_config: PacketFilteringConfig,\n         duration: float,\n     ) -> list[Packet]:\n         \"\"\"The implementation of :method:`send_packets_and_capture`.\ndiff --git a/dts/framework/testbed_model/traffic_generator/scapy.py b/dts/framework/testbed_model/traffic_generator/scapy.py\nindex 5b60f66237..505de0be94 100644\n--- a/dts/framework/testbed_model/traffic_generator/scapy.py\n+++ b/dts/framework/testbed_model/traffic_generator/scapy.py\n@@ -32,6 +32,7 @@\n \n from .capturing_traffic_generator import (\n     CapturingTrafficGenerator,\n+    PacketFilteringConfig,\n     _get_default_capture_name,\n )\n \n@@ -69,6 +70,7 @@ def scapy_send_packets_and_capture(\n     send_iface: str,\n     recv_iface: str,\n     duration: float,\n+    sniff_filter: str,\n ) -> list[bytes]:\n     \"\"\"The RPC function to send and capture packets.\n \n@@ -90,6 +92,7 @@ def scapy_send_packets_and_capture(\n         iface=recv_iface,\n         store=True,\n         started_callback=lambda *args: scapy.all.sendp(scapy_packets, iface=send_iface),\n+        filter=sniff_filter,\n     )\n     sniffer.start()\n     time.sleep(duration)\n@@ -260,11 +263,34 @@ def _send_packets(self, packets: list[Packet], port: Port) -> None:\n         packets = [packet.build() for packet in packets]\n         self.rpc_server_proxy.scapy_send_packets(packets, port.logical_name)\n \n+    def _create_packet_filter(self, filter_config: PacketFilteringConfig) -> str:\n+        \"\"\"Combines filter settings from `filter_config` into a BPF that scapy can use.\n+\n+        Scapy allows for the use of Berkeley Packet Filters (BPFs) to filter what packets are\n+        collected based on various attributes of the packet.\n+\n+        Args:\n+            filter_config: Config class that specifies which filters should be applied.\n+\n+        Returns:\n+            A string representing the combination of BPF filters to be passed to scapy. For\n+            example:\n+\n+            \"ether[12:2] != 0x88cc && ether[12:2] != 0x0806\"\n+        \"\"\"\n+        bpf_filter: list[str] = []\n+        if filter_config.no_arp:\n+            bpf_filter.append(\"ether[12:2] != 0x0806\")\n+        if filter_config.no_lldp:\n+            bpf_filter.append(\"ether[12:2] != 0x88cc\")\n+        return \" && \".join(bpf_filter)\n+\n     def _send_packets_and_capture(\n         self,\n         packets: list[Packet],\n         send_port: Port,\n         receive_port: Port,\n+        filter_config: PacketFilteringConfig,\n         duration: float,\n         capture_name: str = _get_default_capture_name(),\n     ) -> list[Packet]:\n@@ -277,6 +303,7 @@ def _send_packets_and_capture(\n             send_port.logical_name,\n             receive_port.logical_name,\n             duration,\n+            self._create_packet_filter(filter_config),\n         )  # type: ignore[assignment]\n \n         scapy_packets = [Ether(packet.data) for packet in xmlrpc_packets]\n",
    "prefixes": [
        "v6",
        "3/7"
    ]
}