get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 97956,
    "url": "http://patches.dpdk.org/api/patches/97956/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20210903220609.41899-4-stephen@networkplumber.org/",
    "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": "<20210903220609.41899-4-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210903220609.41899-4-stephen@networkplumber.org",
    "date": "2021-09-03T22:06:07",
    "name": "[v2,3/5] app/dumpcap: add new packet capture application",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8f925d73bf4c5a897bcab35726b78b4adc859b5b",
    "submitter": {
        "id": 27,
        "url": "http://patches.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "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/20210903220609.41899-4-stephen@networkplumber.org/mbox/",
    "series": [
        {
            "id": 18672,
            "url": "http://patches.dpdk.org/api/series/18672/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=18672",
            "date": "2021-09-03T22:06:04",
            "name": "Packet capture framework enhancements",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/18672/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/97956/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/97956/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 A82F1A0547;\n\tSat,  4 Sep 2021 00:06:36 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 6CE594111E;\n\tSat,  4 Sep 2021 00:06:20 +0200 (CEST)",
            "from mail-pg1-f174.google.com (mail-pg1-f174.google.com\n [209.85.215.174])\n by mails.dpdk.org (Postfix) with ESMTP id 90497410FF\n for <dev@dpdk.org>; Sat,  4 Sep 2021 00:06:17 +0200 (CEST)",
            "by mail-pg1-f174.google.com with SMTP id q68so396870pga.9\n for <dev@dpdk.org>; Fri, 03 Sep 2021 15:06:17 -0700 (PDT)",
            "from hermes.local (204-195-33-123.wavecable.com. [204.195.33.123])\n by smtp.gmail.com with ESMTPSA id s14sm338251pgf.4.2021.09.03.15.06.14\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 03 Sep 2021 15:06:15 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=networkplumber-org.20150623.gappssmtp.com; s=20150623;\n h=from:to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-transfer-encoding;\n bh=atLZ34w5XAxO1NO8aNf5zWUPZvPki/Hb5Ib8napJFQc=;\n b=PTmd75XmE1y0+UROL8AH8ZVP+gTpdSpy9O3gVRRZAqnFkJWTScaTZVvEss5g3rD3dY\n N78N88TkZJnmtNfyF0kaYQSh6vj1+3gkv5NeDR/kpQjgEiUk7HdqGMf4+UVX9KMiQ6yx\n lC8JoKhfU7whBJC5OtiO79is1W8FY6ogi3US6eaB7VxLmSZb6HicWcGhGpuHYw+DpZpC\n Gcrv3YNm6DX3DEV7TUC9patD6FkexblnCM3mPozbJ090eh2vnQF3jIyBGMmM7dEPjA6/\n DoeG265jqs8cVrfUUGbaq+Gm5NCt0CAsoTIBbbaD9UB0sr4CnZC1i78utUI+bC+lW09L\n yI5w==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20161025;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=atLZ34w5XAxO1NO8aNf5zWUPZvPki/Hb5Ib8napJFQc=;\n b=cS9rD4L6SgGxLxQ6+MlwNIzVTbeRLPgzo5xZASP5Ptf2cGYCEWjMx2ybOI+6V1l1wd\n 41rY7yIkNvI264hQAahG7BWyw3VG2nu/kgFrGpnOGDSnNeGHoXmBf0myT8XemuuIsX8q\n jCRaIK7sLT8k6vEfXvhouXVvyET4UzlODbJEzMZT/kl412KiwLenYTa8zn2epZj6Wh1U\n UNKO07OZkWQLbiy9X+VBEBxgKJuTNkYiZ6OVE3rq9ynoaV5mUx15rBciFnuyBeMLCDTi\n WrpoQRHcJi/egiG5Al+5VTuQN1bf6NhA0H6ioH88FCXlz6O+pplt1yqHd5c7LOP2j9L3\n Oxow==",
        "X-Gm-Message-State": "AOAM531Lw1lTbyGhhNtVodW+//pDiR7xVcBA94V+BcabjWUes9MbsZOd\n 7sLcqcQgG5kuOKKqYgF/XpdevZlhv9RVvg==",
        "X-Google-Smtp-Source": "\n ABdhPJwtb+Z43QxbcRu7T3SyohISY46cJnGPDC/MtnzrON6GggZHSiURy3xPl6K7fVexBQTnnfg/hw==",
        "X-Received": "by 2002:a65:408c:: with SMTP id t12mr956880pgp.229.1630706775779;\n Fri, 03 Sep 2021 15:06:15 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>",
        "Date": "Fri,  3 Sep 2021 15:06:07 -0700",
        "Message-Id": "<20210903220609.41899-4-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.30.2",
        "In-Reply-To": "<20210903220609.41899-1-stephen@networkplumber.org>",
        "References": "<20210903004732.109023-1-stephen@networkplumber.org>\n <20210903220609.41899-1-stephen@networkplumber.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v2 3/5] app/dumpcap: add new packet capture\n application",
        "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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This is a new packet capture application to replace existing pdump.\nThe new application works like Wireshark dumpcap program and supports\nthe pdump API features.\n\nIt is not complete yet some features such as filtering are not implemented.\n\nSigned-off-by: Stephen Hemminger <stephen@networkplumber.org>\n---\n app/dumpcap/main.c      | 831 ++++++++++++++++++++++++++++++++++++++++\n app/dumpcap/meson.build |  18 +\n app/meson.build         |   1 +\n 3 files changed, 850 insertions(+)\n create mode 100644 app/dumpcap/main.c\n create mode 100644 app/dumpcap/meson.build",
    "diff": "diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c\nnew file mode 100644\nindex 000000000000..4bf41b10106f\n--- /dev/null\n+++ b/app/dumpcap/main.c\n@@ -0,0 +1,831 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019-2020 Microsoft Corporation\n+ *\n+ * DPDK application to dump network traffic\n+ * This is designed to look and act like the Wireshark\n+ * dumpcap program.\n+ */\n+\n+#include <errno.h>\n+#include <fcntl.h>\n+#include <getopt.h>\n+#include <inttypes.h>\n+#include <signal.h>\n+#include <stdbool.h>\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <string.h>\n+#include <sys/queue.h>\n+#include <sys/stat.h>\n+#include <sys/types.h>\n+#include <sys/utsname.h>\n+#include <time.h>\n+#include <unistd.h>\n+\n+#include <rte_alarm.h>\n+#include <rte_config.h>\n+#include <rte_eal.h>\n+#include <rte_errno.h>\n+#include <rte_ethdev.h>\n+#include <rte_lcore.h>\n+#include <rte_malloc.h>\n+#include <rte_mbuf.h>\n+#include <rte_mempool.h>\n+#include <rte_pcapng.h>\n+#include <rte_pdump.h>\n+#include <rte_ring.h>\n+#include <rte_string_fns.h>\n+#include <rte_time.h>\n+#include <rte_version.h>\n+\n+#include <pcap/pcap.h>\n+\n+#define RING_NAME \"capture-ring\"\n+#define MONITOR_INTERVAL  (500 * 1000)\n+#define MBUF_POOL_CACHE_SIZE 32\n+#define BURST_SIZE 32\n+#define SLEEP_THRESHOLD 1000\n+\n+/* command line flags */\n+static const char *progname;\n+static bool quit_signal;\n+static bool group_read;\n+static bool quiet;\n+static bool promiscuous_mode = true;\n+static bool use_pcapng = true;\n+static bool show_statistics;\n+static char *output_name;\n+static const char *filter_str;\n+static unsigned int ring_size = 2048;\n+static const char *capture_comment;\n+static uint32_t snaplen = RTE_MBUF_DEFAULT_BUF_SIZE;\n+static bool dump_bpf;\n+static struct {\n+\tdouble duration;\n+\tunsigned long packets;\n+\tsize_t size;\n+} stop;\n+\n+/* Running state */\n+static uint64_t start_time, end_time;\n+static uint64_t packets_received;\n+static size_t file_size;\n+\n+struct interface {\n+\tTAILQ_ENTRY(interface) next;\n+\tuint16_t port;\n+\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\n+\tstruct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT];\n+};\n+\n+TAILQ_HEAD(interface_list, interface);\n+static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);\n+static struct interface *port2intf[RTE_MAX_ETHPORTS];\n+\n+static void usage(void)\n+{\n+\tprintf(\"Usage: %s [options] ...\\n\\n\", progname);\n+\tprintf(\"Capture Interface:\\n\"\n+\t       \"  -i <interface>           name or port index of interface\\n\"\n+\t       \"  -f <capture filter>      packet filter in libpcap filter syntax\\n\");\n+\tprintf(\"  -s <snaplen>, --snapshot-length <snaplen>\\n\"\n+\t       \"                           packet snapshot length (def: %u)\\n\",\n+\t       RTE_MBUF_DEFAULT_BUF_SIZE);\n+\tprintf(\"  -p, --no-promiscuous-mode\\n\"\n+\t       \"                           don't capture in promiscuous mode\\n\"\n+\t       \"  -D, --list-interfaces    print list of interfaces and exit\\n\"\n+\t       \"  -d                       print generated BPF code for capture filter\\n\"\n+\t       \"  -S                       print statistics for each interface once per second\\n\"\n+\t       \"\\n\"\n+\t       \"Stop conditions:\\n\"\n+\t       \"  -c <packet count>        stop after n packets (def: infinite)\\n\"\n+\t       \"  -a <autostop cond.> ..., --autostop <autostop cond.> ...\\n\"\n+\t       \"                           duration:NUM - stop after NUM seconds\\n\"\n+\t       \"                           filesize:NUM - stop this file after NUM kB\\n\"\n+\t       \"                            packets:NUM - stop after NUM packets\\n\"\n+\t       \"Output (files):\\n\"\n+\t       \"  -w <filename>            name of file to save (def: tempfile)\\n\"\n+\t       \"  -g                       enable group read access on the output file(s)\\n\"\n+\t       \"  -n                       use pcapng format instead of pcap (default)\\n\"\n+\t       \"  -P                       use libpcap format instead of pcapng\\n\"\n+\t       \"  --capture-comment <comment>\\n\"\n+\t       \"                           add a capture comment to the output file\\n\"\n+\t       \"\\n\"\n+\t       \"Miscellaneous:\\n\"\n+\t       \"  -q                       don't report packet capture counts\\n\"\n+\t       \"  -v, --version            print version information and exit\\n\"\n+\t       \"  -h, --help               display this help and exit\\n\"\n+\t       \"\\n\"\n+\t       \"Use Ctrl-C to stop capturing at any time.\\n\");\n+}\n+\n+static const char *version(void)\n+{\n+\tstatic char str[128];\n+\n+\tsnprintf(str, sizeof(str),\n+\t\t \"%s 1.0 (%s)\\n\", progname, rte_version());\n+\treturn str;\n+}\n+\n+/* Parse numeric argument from command line */\n+static unsigned long get_uint(const char *arg, const char *name,\n+\t\t\t     unsigned int limit)\n+{\n+\tunsigned long u;\n+\tchar *endp;\n+\n+\tu = strtoul(arg, &endp, 0);\n+\tif (*arg == '\\0' || *endp != '\\0')\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"Specified %s \\\"%s\\\" is not a valid number\\n\",\n+\t\t\t name, arg);\n+\tif (limit && u > limit)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"Specified %s \\\"%s\\\" is too large (greater than %u)\\n\",\n+\t\t\t name, arg, limit);\n+\n+\treturn u;\n+}\n+\n+/* Set auto stop values */\n+static void auto_stop(char *opt)\n+{\n+\tchar *value, *endp;\n+\n+\tvalue = strchr(opt, ':');\n+\tif (value == NULL)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"Missing colon in auto stop parameter\\n\");\n+\n+\t*value++ = '\\0';\n+\tif (strcmp(opt, \"duration\") == 0) {\n+\t\tstop.duration = strtod(value, &endp);\n+\t\tif (*value == '\\0' || *endp != '\\0' || stop.duration < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t \"Invalid duration \\\"%s\\\"\\n\", value);\n+\t} else if (strcmp(opt, \"filesize\") == 0) {\n+\t\tstop.size = get_uint(value, \"filesize\", 0) * 1024;\n+\t} else if (strcmp(opt, \"packets\") == 0) {\n+\t\tstop.packets = get_uint(value, \"packets\", 0);\n+\t} else {\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"Unknown autostop parameter \\\"%s\\\"\\n\", opt);\n+\t}\n+}\n+\n+/* Add interface to list of interfaces to capture */\n+static void add_interface(uint16_t port, const char *name)\n+{\n+\tstruct interface *intf;\n+\n+\tintf = malloc(sizeof(*intf));\n+\tif (!intf)\n+\t\trte_exit(EXIT_FAILURE, \"no memory for interface\\n\");\n+\n+\tmemset(intf, 0, sizeof(*intf));\n+\tstrlcpy(intf->name, name, sizeof(intf->name));\n+\n+\tprintf(\"Capturing on '%s'\\n\", name);\n+\n+\tport2intf[port] = intf;\n+\tTAILQ_INSERT_TAIL(&interfaces, intf, next);\n+}\n+\n+/* Select all valid DPDK interfaces */\n+static void select_all_interfaces(void)\n+{\n+\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\tuint16_t p;\n+\n+\tRTE_ETH_FOREACH_DEV(p) {\n+\t\tif (rte_eth_dev_get_name_by_port(p, name) < 0)\n+\t\t\tcontinue;\n+\t\tadd_interface(p, name);\n+\t}\n+}\n+\n+/*\n+ * Choose interface to capture if no -i option given.\n+ * Select the first DPDK port, this matches what dumpcap does.\n+ */\n+static void set_default_interface(void)\n+{\n+\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\tuint16_t p;\n+\n+\tRTE_ETH_FOREACH_DEV(p) {\n+\t\tif (rte_eth_dev_get_name_by_port(p, name) < 0)\n+\t\t\tcontinue;\n+\t\tadd_interface(p, name);\n+\t\treturn;\n+\t}\n+\trte_exit(EXIT_FAILURE, \"No usable interfaces found\\n\");\n+}\n+\n+/* Lookup interface by name or port and add it to the list */\n+static void select_interface(const char *arg)\n+{\n+\tuint16_t port;\n+\n+\tif (strcmp(arg, \"*\"))\n+\t\tselect_all_interfaces();\n+\telse if (rte_eth_dev_get_port_by_name(arg, &port) == 0)\n+\t\tadd_interface(port, arg);\n+\telse {\n+\t\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\n+\t\tport = get_uint(arg, \"port_number\", UINT16_MAX);\n+\t\tif (rte_eth_dev_get_name_by_port(port, name) < 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Invalid port number %u\\n\",\n+\t\t\t\t port);\n+\t\tadd_interface(port, name);\n+\t}\n+}\n+\n+/* Display list of possible interfaces that can be used. */\n+static void show_interfaces(void)\n+{\n+\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\tuint16_t p;\n+\n+\tRTE_ETH_FOREACH_DEV(p) {\n+\t\tif (rte_eth_dev_get_name_by_port(p, name) < 0)\n+\t\t\tcontinue;\n+\t\tprintf(\"%u. %s\\n\", p, name);\n+\t}\n+}\n+\n+static struct rte_bpf *compile_filter(void)\n+{\n+\tstruct bpf_program fcode;\n+\tpcap_t *pcap;\n+\n+\tpcap = pcap_open_dead(DLT_EN10MB, snaplen);\n+\tif (!pcap)\n+\t\trte_exit(EXIT_FAILURE, \"can not open pcap\\n\");\n+\n+\tif (pcap_compile(pcap, &fcode, filter_str,\n+\t\t\t 1, PCAP_NETMASK_UNKNOWN) != 0)\n+\t\trte_exit(EXIT_FAILURE, \"pcap filter string not valid (%s)\\n\",\n+\t\t\t pcap_geterr(pcap));\n+\n+\trte_exit(EXIT_FAILURE, \"filter not implemented yet\\n\");\n+\n+\t/*\n+\t * Need to convert classic BPF to eBPF and put in shared memory\n+\t * be read by primary process.\n+\t */\n+\tpcap_freecode(&fcode);\n+\tpcap_close(pcap);\n+\n+\trte_exit(EXIT_FAILURE, \"not implemented\\n\");\n+\treturn NULL;\n+}\n+\n+/*\n+ * Parse command line options.\n+ * These are chosen to be similar to dumpcap command.\n+ */\n+static void parse_opts(int argc, char **argv)\n+{\n+\tstatic const struct option long_options[] = {\n+\t\t{ \"autostop\",        required_argument, NULL, 'a' },\n+\t\t{ \"capture-comment\", required_argument, NULL, 0 },\n+\t\t{ \"help\",            no_argument,       NULL, 'h' },\n+\t\t{ \"interface\",       required_argument, NULL, 'i' },\n+\t\t{ \"list-interfaces\", no_argument,       NULL, 'D' },\n+\t\t{ \"no-promiscuous-mode\", no_argument,   NULL, 'p' },\n+\t\t{ \"output-file\",     required_argument, NULL, 'w' },\n+\t\t{ \"ring-buffer\",     required_argument, NULL, 'b' },\n+\t\t{ \"snapshot-length\", required_argument, NULL, 's' },\n+\t\t{ \"version\",         no_argument,       NULL, 'v' },\n+\t\t{ NULL },\n+\t};\n+\tint option_index, c;\n+\n+\tfor (;;) {\n+\t\tc = getopt_long(argc, argv, \"a:b:c:dDf:ghi:nN:pPqs:Svw:\",\n+\t\t\t\tlong_options, &option_index);\n+\t\tif (c == -1)\n+\t\t\tbreak;\n+\n+\t\tswitch (c) {\n+\t\tcase 0:\n+\t\t\tswitch (option_index) {\n+\t\t\tcase 0:\n+\t\t\t\tcapture_comment = optarg;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tusage();\n+\t\t\t\texit(1);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase 'a':\n+\t\t\tauto_stop(optarg);\n+\t\t\tbreak;\n+\t\tcase 'b':\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t \"multiple files not implemented\\n\");\n+\t\t\tbreak;\n+\t\tcase 'c':\n+\t\t\tstop.packets = get_uint(optarg, \"packet_count\", 0);\n+\t\t\tbreak;\n+\t\tcase 'd':\n+\t\t\tdump_bpf = true;\n+\t\t\tbreak;\n+\t\tcase 'D':\n+\t\t\tshow_interfaces();\n+\t\t\texit(0);\n+\t\tcase 'f':\n+\t\t\tfilter_str = optarg;\n+\t\t\tbreak;\n+\t\tcase 'g':\n+\t\t\tgroup_read = true;\n+\t\t\tbreak;\n+\t\tcase 'h':\n+\t\t\tprintf(\"%s\\n\\n\", version());\n+\t\t\tusage();\n+\t\t\texit(0);\n+\t\tcase 'i':\n+\t\t\tselect_interface(optarg);\n+\t\t\tbreak;\n+\t\tcase 'n':\n+\t\t\tuse_pcapng = true;\n+\t\t\tbreak;\n+\t\tcase 'N':\n+\t\t\tring_size = get_uint(optarg, \"packet_limit\", 0);\n+\t\t\tbreak;\n+\t\tcase 'p':\n+\t\t\tpromiscuous_mode = false;\n+\t\t\tbreak;\n+\t\tcase 'P':\n+\t\t\tuse_pcapng = false;\n+\t\t\tbreak;\n+\t\tcase 'q':\n+\t\t\tquiet = true;\n+\t\t\tbreak;\n+\t\tcase 's':\n+\t\t\tsnaplen = get_uint(optarg, \"snap_len\", 0);\n+\t\t\tbreak;\n+\t\tcase 'S':\n+\t\t\tshow_statistics = true;\n+\t\t\tbreak;\n+\t\tcase 'w':\n+\t\t\toutput_name = optarg;\n+\t\t\tbreak;\n+\t\tcase 'v':\n+\t\t\tprintf(\"%s\\n\", version());\n+\t\t\texit(0);\n+\t\tdefault:\n+\t\t\tfprintf(stderr, \"Invalid option: %s\\n\",\n+\t\t\t\targv[optind - 1]);\n+\t\t\tusage();\n+\t\t\texit(1);\n+\t\t}\n+\t}\n+}\n+\n+static void\n+signal_handler(int sig_num __rte_unused)\n+{\n+\t__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);\n+}\n+\n+/* Return the time since 1/1/1970 in nanoseconds */\n+static uint64_t create_timestamp(void)\n+{\n+\tstruct timespec now;\n+\n+\tclock_gettime(CLOCK_MONOTONIC, &now);\n+\treturn rte_timespec_to_ns(&now);\n+}\n+\n+/* Return the seconds elapsed since start_time */\n+static double elapsed(void)\n+{\n+\tstruct timespec now;\n+\tint64_t delta;\n+\n+\tclock_gettime(CLOCK_MONOTONIC_COARSE, &now);\n+\tdelta = rte_timespec_to_ns(&now) - start_time;\n+\treturn delta / 1.e9;\n+}\n+\n+static void\n+cleanup_pdump_resources(void)\n+{\n+\tstruct interface *intf;\n+\n+\tTAILQ_FOREACH(intf, &interfaces, next) {\n+\t\trte_pdump_disable(intf->port,\n+\t\t\t\t  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);\n+\t\tif (promiscuous_mode)\n+\t\t\trte_eth_promiscuous_disable(intf->port);\n+\t}\n+}\n+\n+/* Alarm signal handler, used to check that primary process */\n+static void\n+monitor_primary(void *arg __rte_unused)\n+{\n+\tif (__atomic_load_n(&quit_signal, __ATOMIC_RELAXED))\n+\t\treturn;\n+\n+\tif (rte_eal_primary_proc_alive(NULL)) {\n+\t\trte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);\n+\t} else {\n+\t\tfprintf(stderr,\n+\t\t\t\"Primary process is no longer active, exiting...\\n\");\n+\t\t__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);\n+\t}\n+}\n+\n+/* Setup handler to check when primary exits. */\n+static void\n+enable_primary_monitor(void)\n+{\n+\tint ret;\n+\n+\t/* Once primary exits, so will pdump. */\n+\tret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);\n+\tif (ret < 0)\n+\t\tfprintf(stderr, \"Fail to enable monitor:%d\\n\", ret);\n+}\n+\n+static void\n+disable_primary_monitor(void)\n+{\n+\tint ret;\n+\n+\tret = rte_eal_alarm_cancel(monitor_primary, NULL);\n+\tif (ret < 0)\n+\t\tfprintf(stderr, \"Fail to disable monitor:%d\\n\", ret);\n+}\n+\n+static void\n+report_packet_stats(rte_pcapng_t *out)\n+{\n+\tstruct rte_pdump_stats pdump_stats;\n+\tstruct interface *intf;\n+\tuint64_t ifrecv, ifdrop;\n+\tdouble percent;\n+\n+\tfputc('\\n', stderr);\n+\tTAILQ_FOREACH(intf, &interfaces, next) {\n+\t\tif (rte_pdump_stats(intf->port, &pdump_stats) < 0)\n+\t\t\tcontinue;\n+\n+\t\t/* do what Wiretap does */\n+\t\tifrecv = pdump_stats.accepted + pdump_stats.filtered;\n+\t\tifdrop = pdump_stats.nombuf + pdump_stats.ringfull;\n+\n+\t\tif (use_pcapng)\n+\t\t\trte_pcapng_write_stats(out, intf->port, NULL,\n+\t\t\t\t\t       start_time, end_time,\n+\t\t\t\t\t       ifrecv, ifdrop);\n+\n+\t\tif (ifrecv == 0)\n+\t\t\tpercent = 0;\n+\t\telse\n+\t\t\tpercent = 100. * ifrecv / (ifrecv + ifdrop);\n+\n+\t\tfprintf(stderr,\n+\t\t\t\"Packets received/dropped on interface '%s': \"\n+\t\t\t\"%\"PRIu64 \"/%\" PRIu64 \" (%.1f)\\n\",\n+\t\t\tintf->name, ifrecv, ifdrop, percent);\n+\t}\n+}\n+\n+/*\n+ * Start DPDK EAL with arguments.\n+ * Unlike most DPDK programs, this application does not use the\n+ * typical EAL command line arguments.\n+ * We don't want to expose all the DPDK internals to the user.\n+ */\n+static void dpdk_init(void)\n+{\n+\tconst char *args[] = {\n+\t\tprogname, \"--proc-type\", \"secondary\", \"--log-level\", \"error\"\n+\t};\n+\tconst int eal_argc = RTE_DIM(args);\n+\tchar **eal_argv;\n+\tunsigned int i;\n+\n+\t/* DPDK API requires mutable versions of command line arguments. */\n+\teal_argv = calloc(eal_argc + 1, sizeof(char *));\n+\tif (eal_argv == NULL)\n+\t\trte_panic(\"No memory\\n\");\n+\n+\tfor (i = 0; i < RTE_DIM(args); i++)\n+\t\teal_argv[i] = strdup(args[i]);\n+\n+\tif (rte_eal_init(eal_argc, eal_argv) < 0)\n+\t\trte_panic(\"EAL init failed\\n\");\n+\n+\tif (rte_eth_dev_count_avail() == 0)\n+\t\trte_exit(EXIT_FAILURE, \"No Ethernet ports found\\n\");\n+}\n+\n+/* Create packet ring shared between callbacks and process */\n+static struct rte_ring *create_ring(void)\n+{\n+\tstruct rte_ring *ring;\n+\tsize_t size, log2;\n+\n+\t/* Find next power of 2 >= size. */\n+\tsize = ring_size;\n+\tlog2 = sizeof(size) * 8 - __builtin_clzl(size - 1);\n+\tsize = 1u << log2;\n+\n+\tif (size != ring_size) {\n+\t\tfprintf(stderr, \"Ring size %u rounded up to %zu\\n\",\n+\t\t\tring_size, size);\n+\t\tring_size = size;\n+\t}\n+\n+\tring = rte_ring_lookup(RING_NAME);\n+\tif (ring == NULL) {\n+\t\tring = rte_ring_create(RING_NAME, ring_size,\n+\t\t\t\t\trte_socket_id(), 0);\n+\t\tif (ring == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Could not create ring :%s\\n\",\n+\t\t\t\t rte_strerror(rte_errno));\n+\t}\n+\treturn ring;\n+}\n+\n+static struct rte_mempool *create_mempool(void)\n+{\n+\tstatic const char pool_name[] = \"capture_mbufs\";\n+\tsize_t num_mbufs = 2 * ring_size;\n+\tstruct rte_mempool *mp;\n+\n+\tmp = rte_mempool_lookup(pool_name);\n+\tif (mp)\n+\t\treturn mp;\n+\n+\tmp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,\n+\t\t\t\t\t    MBUF_POOL_CACHE_SIZE, 0,\n+\t\t\t\t\t    rte_pcapng_mbuf_size(snaplen),\n+\t\t\t\t\t    rte_socket_id(), \"ring_mp_sc\");\n+\tif (mp == NULL)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"Mempool (%s) creation failed: %s\\n\", pool_name,\n+\t\t\t rte_strerror(rte_errno));\n+\n+\treturn mp;\n+}\n+\n+static void *create_output(void)\n+{\n+\tstruct utsname uts;\n+\tchar os[256];\n+\tint fd;\n+\n+\t/* If no filename specified make a tempfile name */\n+\tif (output_name == NULL) {\n+\t\tstruct interface *intf;\n+\t\tstruct tm *tm;\n+\t\ttime_t now;\n+\t\tchar ts[32];\n+\n+\t\tintf = TAILQ_FIRST(&interfaces);\n+\t\tnow = time(NULL);\n+\t\ttm = localtime(&now);\n+\t\tif (!tm)\n+\t\t\trte_panic(\"localtime failed\\n\");\n+\n+\t\tstrftime(ts, sizeof(ts), \"%Y%m%d%H%M%S\", tm);\n+\t\tif (asprintf(&output_name, \"/tmp/%s_%u_%s_%s.%s\",\n+\t\t\t     progname, intf->port, intf->name, ts,\n+\t\t\t     use_pcapng ? \"pcapng\" : \"pcap\") < 0)\n+\t\t\trte_panic(\"asprintf failed\\n\");\n+\t}\n+\n+\tif (strcmp(output_name, \"-\") == 0)\n+\t\tfd = STDOUT_FILENO;\n+\telse {\n+\t\tmode_t mode = group_read ? 0640 : 0600;\n+\n+\t\tfd = open(output_name, O_WRONLY | O_CREAT, mode);\n+\t\tif (fd < 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Can not open \\\"%s\\\": %s\\n\",\n+\t\t\t\t output_name, strerror(errno));\n+\t}\n+\n+\tif (use_pcapng) {\n+\t\trte_pcapng_t *pcapng;\n+\n+\t\tif (uname(&uts) < 0)\n+\t\t\tstrcpy(os, \"unknown\");\n+\t\telse\n+\t\t\tsnprintf(os, sizeof(os), \"%s %s\",\n+\t\t\t\t uts.sysname, uts.release);\n+\n+\t\tpcapng = rte_pcapng_fdopen(fd, os, NULL, version(), capture_comment);\n+\t\tif (pcapng == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"pcapng_fdopen failed: %s\\n\",\n+\t\t\t\t strerror(rte_errno));\n+\t\treturn pcapng;\n+\t} else {\n+\t\tpcap_dumper_t *dumper;\n+\t\tpcap_t *pcap;\n+\n+\t\tpcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, snaplen,\n+\t\t\t\t\t\t\t    PCAP_TSTAMP_PRECISION_NANO);\n+\t\tif (pcap == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"pcap_open_dead failed\\n\");\n+\n+\t\tdumper = pcap_dump_fopen(pcap, fdopen(fd, \"w\"));\n+\t\tif (dumper == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"pcap_dump_fopen failed: %s\\n\",\n+\t\t\t\t pcap_geterr(pcap));\n+\t\treturn dumper;\n+\t}\n+}\n+\n+static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp,\n+\t\t\t struct rte_bpf *filter)\n+{\n+\tstruct interface *intf;\n+\tuint32_t flags;\n+\tint ret;\n+\n+\tflags = RTE_PDUMP_FLAG_RXTX;\n+\tif (use_pcapng)\n+\t\tflags |= RTE_PDUMP_FLAG_PCAPNG;\n+\n+\tTAILQ_FOREACH(intf, &interfaces, next) {\n+\t\tif (promiscuous_mode)\n+\t\t\trte_eth_promiscuous_enable(intf->port);\n+\n+\t\tret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,\n+\t\t\t\t\t   flags, snaplen,\n+\t\t\t\t\t   r, mp, filter);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t \"Packet dump enable failed: %s\\n\",\n+\t\t\t\t rte_strerror(rte_errno));\n+\t}\n+}\n+\n+/*\n+ * Show current count of captured packets\n+ * with backspaces to overwrite last value.\n+ */\n+static void show_count(uint64_t count)\n+{\n+\tunsigned int i;\n+\tstatic unsigned int bt;\n+\n+\tfor (i = 0; i < bt; i++)\n+\t\tfputc('\\b', stderr);\n+\n+\tbt = fprintf(stderr, \"%\"PRIu64\" \", count);\n+}\n+\n+/* Write multiple packets in older pcap format */\n+static ssize_t\n+pcap_write_packets(pcap_dumper_t *dumper,\n+\t\t   struct rte_mbuf *pkts[], uint16_t n)\n+{\n+\tuint8_t temp_data[snaplen];\n+\tstruct pcap_pkthdr header;\n+\tuint16_t i;\n+\tsize_t total = 0;\n+\n+\tgettimeofday(&header.ts, NULL);\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tstruct rte_mbuf *m = pkts[i];\n+\n+\t\theader.len = rte_pktmbuf_pkt_len(m);\n+\t\theader.caplen = RTE_MIN(header.len, snaplen);\n+\n+\t\tpcap_dump((u_char *)dumper, &header,\n+\t\t\t  rte_pktmbuf_read(m, 0, header.caplen, temp_data));\n+\n+\t\ttotal += sizeof(header) + header.len;\n+\t}\n+\n+\treturn total;\n+}\n+\n+/* Process all packets in ring and dump to capture file */\n+static int process_ring(void *out, struct rte_ring *r)\n+{\n+\tstruct rte_mbuf *pkts[BURST_SIZE];\n+\tunsigned int avail, n;\n+\tstatic unsigned int empty_count;\n+\tssize_t written;\n+\n+\tn = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,\n+\t\t\t\t      &avail);\n+\tif (n == 0) {\n+\t\t/* don't consume endless amounts of cpu if idle */\n+\t\tif (empty_count < SLEEP_THRESHOLD)\n+\t\t\t++empty_count;\n+\t\telse\n+\t\t\tusleep(10);\n+\t\treturn 0;\n+\t}\n+\n+\tempty_count = (avail == 0);\n+\n+\tif (use_pcapng)\n+\t\twritten = rte_pcapng_write_packets(out, pkts, n);\n+\telse\n+\t\twritten = pcap_write_packets(out, pkts, n);\n+\n+\trte_pktmbuf_free_bulk(pkts, n);\n+\n+\tif (written < 0)\n+\t\treturn -1;\n+\n+\tfile_size += written;\n+\tpackets_received += n;\n+\tif (!quiet)\n+\t\tshow_count(packets_received);\n+\n+\treturn 0;\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tstruct rte_bpf *bpf_filter = NULL;\n+\tstruct rte_ring *r;\n+\tstruct rte_mempool *mp;\n+\tvoid *out;\n+\n+\tprogname = basename(argv[0]);\n+\n+\tdpdk_init();\n+\tparse_opts(argc, argv);\n+\n+\tif (filter_str)\n+\t\tbpf_filter = compile_filter();\n+\n+\tif (dump_bpf)\n+\t\tfprintf(stderr, \"dump filter not implemented yet\\n\");\n+\n+\tif (TAILQ_EMPTY(&interfaces))\n+\t\tset_default_interface();\n+\n+\tr = create_ring();\n+\tmp = create_mempool();\n+\tout = create_output();\n+\tif (out == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"can not open output file: %s\\n\",\n+\t\t\t rte_strerror(rte_errno));\n+\n+\tstart_time = create_timestamp();\n+\tenable_pdump(r, mp, bpf_filter);\n+\n+\tsignal(SIGINT, signal_handler);\n+\tsignal(SIGPIPE, SIG_IGN);\n+\n+\tenable_primary_monitor();\n+\n+\tif (!quiet) {\n+\t\tfprintf(stderr, \"Packets captured: \");\n+\t\tshow_count(0);\n+\t}\n+\n+\twhile (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) {\n+\t\tif (process_ring(out, r) < 0) {\n+\t\t\tfprintf(stderr, \"pcapng file write failed; %s\\n\",\n+\t\t\t\tstrerror(errno));\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (stop.size && file_size >= stop.size)\n+\t\t\tbreak;\n+\n+\t\tif (stop.packets && packets_received >= stop.packets)\n+\t\t\tbreak;\n+\n+\t\tif (stop.duration != 0 && elapsed() > stop.duration)\n+\t\t\tbreak;\n+\t}\n+\n+\tend_time = create_timestamp();\n+\tdisable_primary_monitor();\n+\n+\tif (rte_eal_primary_proc_alive(NULL))\n+\t\treport_packet_stats(out);\n+\n+\tif (use_pcapng)\n+\t\trte_pcapng_close(out);\n+\telse\n+\t\tpcap_dump_close(out);\n+\n+\tcleanup_pdump_resources();\n+\trte_free(bpf_filter);\n+\trte_ring_free(r);\n+\trte_mempool_free(mp);\n+\n+\treturn rte_eal_cleanup() ? EXIT_FAILURE : 0;\n+}\ndiff --git a/app/dumpcap/meson.build b/app/dumpcap/meson.build\nnew file mode 100644\nindex 000000000000..206f496fd6b0\n--- /dev/null\n+++ b/app/dumpcap/meson.build\n@@ -0,0 +1,18 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2019 Microsoft Corporation\n+\n+if not dpdk_conf.has('RTE_PORT_PCAP')\n+    build = false\n+    reason = 'missing dependency, \"libpcap\"'\n+endif\n+\n+if is_windows\n+\tbuild = false\n+\treason = 'not supported on Windows'\n+\tsubdir_done()\n+endif\n+\n+ext_deps += pcap_dep\n+\n+sources = files('main.c')\n+deps += ['ethdev', 'pdump', 'pcapng']\ndiff --git a/app/meson.build b/app/meson.build\nindex 4c6049807cc3..e41a2e390236 100644\n--- a/app/meson.build\n+++ b/app/meson.build\n@@ -2,6 +2,7 @@\n # Copyright(c) 2017-2019 Intel Corporation\n \n apps = [\n+        'dumpcap',\n         'pdump',\n         'proc-info',\n         'test-acl',\n",
    "prefixes": [
        "v2",
        "3/5"
    ]
}