get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 138283,
    "url": "http://patchwork.dpdk.org/api/patches/138283/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20240312220129.70667-1-stephen@networkplumber.org/",
    "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": "<20240312220129.70667-1-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240312220129.70667-1-stephen@networkplumber.org",
    "date": "2024-03-12T22:01:27",
    "name": "test-pmd: add more packet decode options (verbose)",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "50b56661296ceb791d0e7dc91f8196b75c8ad69e",
    "submitter": {
        "id": 27,
        "url": "http://patchwork.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "delegate": {
        "id": 319,
        "url": "http://patchwork.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20240312220129.70667-1-stephen@networkplumber.org/mbox/",
    "series": [
        {
            "id": 31489,
            "url": "http://patchwork.dpdk.org/api/series/31489/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=31489",
            "date": "2024-03-12T22:01:27",
            "name": "test-pmd: add more packet decode options (verbose)",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/31489/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/138283/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/138283/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 900DE43C96;\n\tTue, 12 Mar 2024 23:01:42 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 52395402CD;\n\tTue, 12 Mar 2024 23:01:42 +0100 (CET)",
            "from mail-pl1-f169.google.com (mail-pl1-f169.google.com\n [209.85.214.169])\n by mails.dpdk.org (Postfix) with ESMTP id 7BA9040272\n for <dev@dpdk.org>; Tue, 12 Mar 2024 23:01:40 +0100 (CET)",
            "by mail-pl1-f169.google.com with SMTP id\n d9443c01a7336-1dd9066b7c3so3222055ad.2\n for <dev@dpdk.org>; Tue, 12 Mar 2024 15:01:40 -0700 (PDT)",
            "from hermes.local (204-195-123-141.wavecable.com. [204.195.123.141])\n by smtp.gmail.com with ESMTPSA id\n e4-20020a170902b78400b001dcc3a46a6bsm7129493pls.262.2024.03.12.15.01.38\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 12 Mar 2024 15:01:38 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1710280899;\n x=1710885699; darn=dpdk.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=UMzgGRxzZjstoBRxMy5fKJ2zdcVH0tHjwiq8oZHSjJc=;\n b=McZlNl/IfBgwQM9x0J1/HWfX2pqF1CBHNl3f39OpXkZ3nSLV9ch1TV75hUv85cGTjG\n de0kXpVRL9HVBPJefgpEDbEqPKhPJFCyLDdNLyWt2agzMbLuhyP+8kZ7gFmQXUpSHZt5\n NPjMJ3LiI3ROCnR5jK9Cgponq9+l5qGbiVolZsJoN0u5zZSf/RhZyTZGQfjHRF6TcoY7\n n2j4UklG8Jcs1uZe69H7Fh/ZaPc/0zE+SgRDDKJZn72HFg+RTeo3izJSyalqAQ1aXZ5e\n UYdfEksOHbbj6usEJwg0bn5dEtD/NFXIkIsDAi2r5gBsJeyJrCH8eEeUtSNMt86ZFPOF\n 6+Vg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1710280899; x=1710885699;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-message-state:from:to:cc:subject:date:message-id\n :reply-to;\n bh=UMzgGRxzZjstoBRxMy5fKJ2zdcVH0tHjwiq8oZHSjJc=;\n b=FJEaojPP8qMaNtz6M3/R4fLPG8UoPz0Hmc9jcW+BG6SSx84srKjJR8+qno3qouSEhO\n YwN7gQzJwbBpeKCjn9Bc/PPf+DOEHWCGa0E2eAAJMisYMo/6xypfJ5p8bbIlyMOPh1mi\n Av7OJXTZk3O69CaAYVWxPEqikMSduAK9r6/fVhS79ct0WVMMrZLR/43yVMvmWX21QWRR\n mGin8czCQDSvNX5uNTn0z4FGnMN30c/aCi7Hl2f2J0KXAKUzteqIy/yZOdPF3aKBxSY+\n mKvGXJ8I1PWJb6wzWlU+ICm7l8mKi/8Bzzxb2CT/DgLwHzikLLR+LQPJ0+GXz/IAvjI1\n bHZA==",
        "X-Gm-Message-State": "AOJu0Yxi94z52+ZcFL26ZYQjDFSbFi0aqZE3mmpKO5dsUceIifpOziYg\n hLu5a146kiLyZ5p8SUJ5y1TvMOKsFXlpI7G81amXnMK5Mz647EUWFfzi6SgiS3n9N6+5h3yJz6R\n i",
        "X-Google-Smtp-Source": "\n AGHT+IFRMScKLwuicQYX26NbP46DhDPAaH5Eh03SuCzIx8tsaIFQVATm+4vXNi9I78QqbWzCHPWEIA==",
        "X-Received": "by 2002:a17:902:d581:b0:1dd:a134:5699 with SMTP id\n k1-20020a170902d58100b001dda1345699mr5859654plh.28.1710280899338;\n Tue, 12 Mar 2024 15:01:39 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>,\n Ori Kam <orika@nvidia.com>,\n Aman Singh <aman.deep.singh@intel.com>,\n Yuying Zhang <yuying.zhang@intel.com>",
        "Subject": "[PATCH] test-pmd: add more packet decode options (verbose)",
        "Date": "Tue, 12 Mar 2024 15:01:27 -0700",
        "Message-ID": "<20240312220129.70667-1-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.43.0",
        "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": "The existing verbose levels 1..3 provide a messy multi-line\noutput per packet. This is unhelpful when diagnosing many\ntypes of problems like packet flow.\n\nThis patch adds two new levels:\n4: one line per packet is printed in a format resembling\n   tshark output. With addresses and protocol info.\n5: dump packet in hex.\n   Useful if the driver is messing up the data.\n\nSigned-off-by: Stephen Hemminger <stephen@networkplumber.org>\n---\n app/test-pmd/cmdline_flow.c                 |   3 +-\n app/test-pmd/config.c                       |  33 +-\n app/test-pmd/testpmd.h                      |  11 +\n app/test-pmd/util.c                         | 355 +++++++++++++++++++-\n doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-\n 5 files changed, 391 insertions(+), 16 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c\nindex 5f761903c1d1..03141c04cae5 100644\n--- a/app/test-pmd/cmdline_flow.c\n+++ b/app/test-pmd/cmdline_flow.c\n@@ -14002,7 +14002,8 @@ cmd_set_raw_parsed(const struct buffer *in)\n \t\t\tupper_layer = proto;\n \t\t}\n \t}\n-\tif (verbose_level & 0x1)\n+\n+\tif (verbose_level > 0)\n \t\tprintf(\"total data size is %zu\\n\", (*total_size));\n \tRTE_ASSERT((*total_size) <= ACTION_RAW_ENCAP_MAX_DATA);\n \tmemmove(data, (data_tail - (*total_size)), *total_size);\ndiff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 968d2164ab35..8e83b78721fc 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -6250,26 +6250,37 @@ configure_rxtx_dump_callbacks(uint16_t verbose)\n \t\treturn;\n #endif\n \n-\tRTE_ETH_FOREACH_DEV(portid)\n-\t{\n-\t\tif (verbose == 1 || verbose > 2)\n+\tRTE_ETH_FOREACH_DEV(portid) {\n+\t\tswitch (verbose) {\n+\t\tcase VERBOSE_OFF:\n+\t\t\tremove_rx_dump_callbacks(portid);\n+\t\t\tremove_tx_dump_callbacks(portid);\n+\t\t\tbreak;\n+\t\tcase VERBOSE_RX:\n \t\t\tadd_rx_dump_callbacks(portid);\n-\t\telse\n+\t\t\tremove_tx_dump_callbacks(portid);\n+\t\t\tbreak;\n+\t\tcase VERBOSE_TX:\n+\t\t\tadd_tx_dump_callbacks(portid);\n \t\t\tremove_rx_dump_callbacks(portid);\n-\t\tif (verbose >= 2)\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tadd_rx_dump_callbacks(portid);\n \t\t\tadd_tx_dump_callbacks(portid);\n-\t\telse\n-\t\t\tremove_tx_dump_callbacks(portid);\n+\t\t}\n \t}\n }\n \n void\n set_verbose_level(uint16_t vb_level)\n {\n-\tprintf(\"Change verbose level from %u to %u\\n\",\n-\t       (unsigned int) verbose_level, (unsigned int) vb_level);\n-\tverbose_level = vb_level;\n-\tconfigure_rxtx_dump_callbacks(verbose_level);\n+\tif (vb_level < VERBOSE_MAX) {\n+\t\tprintf(\"Change verbose level from %u to %u\\n\", verbose_level, vb_level);\n+\t\tverbose_level = vb_level;\n+\t\tconfigure_rxtx_dump_callbacks(verbose_level);\n+\t} else {\n+\t\tfprintf(stderr, \"Verbose level %u is out of range\\n\", vb_level);\n+\t}\n }\n \n void\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex 55df12033a39..26801226bb47 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -489,6 +489,17 @@ enum dcb_mode_enable\n \n extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */\n \n+enum verbose_mode {\n+\tVERBOSE_OFF = 0,\n+\tVERBOSE_RX,\n+\tVERBOSE_TX,\n+\tVERBOSE_BOTH,\n+\tVERBOSE_DISSECT,\n+\tVERBOSE_HEX,\n+\tVERBOSE_MAX\n+};\n+\n+\n /* globals used for configuration */\n extern uint8_t record_core_cycles; /**< Enables measurement of CPU cycles */\n extern uint8_t record_burst_stats; /**< Enables display of RX and TX bursts */\ndiff --git a/app/test-pmd/util.c b/app/test-pmd/util.c\nindex 5aa69ed545af..f9dfa4d7ec07 100644\n--- a/app/test-pmd/util.c\n+++ b/app/test-pmd/util.c\n@@ -9,6 +9,11 @@\n #include <rte_net.h>\n #include <rte_mbuf.h>\n #include <rte_ether.h>\n+#include <rte_arp.h>\n+#include <rte_icmp.h>\n+#include <rte_ip.h>\n+#include <rte_tcp.h>\n+#include <rte_udp.h>\n #include <rte_vxlan.h>\n #include <rte_ethdev.h>\n #include <rte_flow.h>\n@@ -16,6 +21,7 @@\n #include \"testpmd.h\"\n \n #define MAX_STRING_LEN 8192\n+#define MAX_DUMP_LEN   1024\n \n #define MKDUMPSTR(buf, buf_size, cur_len, ...) \\\n do { \\\n@@ -67,9 +73,10 @@ get_timestamp(const struct rte_mbuf *mbuf)\n \t\t\ttimestamp_dynfield_offset, rte_mbuf_timestamp_t *);\n }\n \n-static inline void\n-dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n-\t      uint16_t nb_pkts, int is_rx)\n+/* More verbose older style packet decode */\n+static void\n+dump_pkt_verbose(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n+\t\t uint16_t nb_pkts, int is_rx)\n {\n \tstruct rte_mbuf  *mb;\n \tconst struct rte_ether_hdr *eth_hdr;\n@@ -297,6 +304,348 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n \t}\n }\n \n+static void\n+dissect_arp(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_arp_hdr *arp;\n+\tstruct rte_arp_hdr _arp;\n+\tuint16_t ar_op;\n+\tchar buf[128];\n+\n+\tarp = rte_pktmbuf_read(mb, offset, sizeof(*arp), &_arp);\n+\tif (unlikely(arp == NULL)) {\n+\t\tprintf(\"truncated ARP! \");\n+\t\treturn;\n+\t}\n+\n+\tar_op = RTE_BE_TO_CPU_16(arp->arp_opcode);\n+\tswitch (ar_op) {\n+\tcase RTE_ARP_OP_REQUEST:\n+\t\tinet_ntop(AF_INET, &arp->arp_data.arp_tip, buf, sizeof(buf));\n+\t\tprintf(\"Who has %s? \", buf);\n+\n+\t\trte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha);\n+\t\tprintf(\"Tell %s \", buf);\n+\t\tbreak;\n+\tcase RTE_ARP_OP_REPLY:\n+\t\tinet_ntop(AF_INET, &arp->arp_data.arp_sip, buf, sizeof(buf));\n+\t\tprintf(\"%s is at\", buf);\n+\n+\t\trte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha);\n+\t\tprintf(\"%s \", buf);\n+\t\tbreak;\n+\tcase RTE_ARP_OP_INVREQUEST:\n+\t\trte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_tha);\n+\t\tprintf(\"Who is %s? \", buf);\n+\n+\t\trte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha);\n+\t\tprintf(\"Tell %s \", buf);\n+\t\tbreak;\n+\n+\tcase RTE_ARP_OP_INVREPLY:\n+\t\trte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha);\n+\t\tprintf(\"%s is at \", buf);\n+\n+\t\tinet_ntop(AF_INET, &arp->arp_data.arp_sip, buf, sizeof(buf));\n+\t\tprintf(\"%s \", buf);\n+\t\tbreak;\n+\tdefault:\n+\t\tprintf(\"Unknown ARP %#x \", ar_op);\n+\t\tbreak;\n+\t}\n+}\n+\n+static void\n+dissect_udp(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_udp_hdr *udph;\n+\tstruct rte_udp_hdr _udp;\n+\tuint16_t src_port, dst_port;\n+\n+\tudph = rte_pktmbuf_read(mb, offset, sizeof(*udph), &_udp);\n+\tif (unlikely(udph == NULL)) {\n+\t\tprintf(\"truncated UDP! \");\n+\t\treturn;\n+\t}\n+\n+\tsrc_port = RTE_BE_TO_CPU_16(udph->src_port);\n+\tdst_port = RTE_BE_TO_CPU_16(udph->dst_port);\n+\n+\t/* TODO handle vxlan */\n+\n+\tprintf(\"UDP %u %u → %u \",\n+\t\t  RTE_BE_TO_CPU_16(udph->dgram_len),\n+\t\t  src_port, dst_port);\n+\n+}\n+\n+static void\n+dissect_tcp(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_tcp_hdr *tcph;\n+\tstruct rte_tcp_hdr _tcp;\n+\tuint16_t src_port, dst_port;\n+\n+\ttcph = rte_pktmbuf_read(mb, offset, sizeof(*tcph), &_tcp);\n+\tif (unlikely(tcph == NULL)) {\n+\t\tprintf(\"truncated TCP! \");\n+\t\treturn;\n+\t}\n+\n+\tsrc_port = RTE_BE_TO_CPU_16(tcph->src_port);\n+\tdst_port = RTE_BE_TO_CPU_16(tcph->dst_port);\n+\n+\tprintf(\"TCP %u → %u\",\n+\t\t  src_port, dst_port);\n+#define PRINT_TCP_FLAG(flag) \\\n+\tif (tcph->tcp_flags & RTE_TCP_ ## flag ## _FLAG) \\\n+\t\tprintf(\" [\" #flag\" ]\")\n+\n+\tPRINT_TCP_FLAG(URG);\n+\tPRINT_TCP_FLAG(ACK);\n+\tPRINT_TCP_FLAG(RST);\n+\tPRINT_TCP_FLAG(SYN);\n+\tPRINT_TCP_FLAG(FIN);\n+#undef PRINT_TCP_FLAG\n+\n+\tprintf(\"Seq=%u Ack=%u Win=%u \",\n+\t\t  RTE_BE_TO_CPU_16(tcph->sent_seq),\n+\t\t  RTE_BE_TO_CPU_16(tcph->recv_ack),\n+\t\t  RTE_BE_TO_CPU_16(tcph->rx_win));\n+}\n+\n+static void\n+dissect_icmp(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_icmp_hdr *icmp;\n+\tstruct rte_icmp_hdr _icmp;\n+\tstatic const char * const icmp_types[256] = {\n+\t\t[RTE_IP_ICMP_ECHO_REPLY]   = \"ICMP Reply\",\n+\t\t[RTE_IP_ICMP_ECHO_REQUEST] = \"ICMP Request\",\n+\t\t[RTE_ICMP6_ECHO_REPLY]     = \"ICMPv6 Reply\",\n+\t\t[RTE_ICMP6_ECHO_REQUEST]   = \"ICMPv6 Request\",\n+\t\t[133]                      = \"ICMPv6 Router Solicitation\",\n+\t\t[134]                      = \"ICMPv6 Router Solicitation\",\n+\t};\n+\n+\n+\ticmp = rte_pktmbuf_read(mb, offset, sizeof(*icmp), &_icmp);\n+\tif (unlikely(icmp == NULL)) {\n+\t\tprintf(\"truncated ICMP! \");\n+\t} else {\n+\t\tconst char *name = icmp_types[icmp->icmp_type];\n+\n+\t\tif (name != NULL)\n+\t\t\tprintf(\"%s \", name);\n+\t\telse\n+\t\t\tprintf(\"ICMP type %u \", icmp->icmp_type);\n+\t}\n+}\n+\n+static void\n+dissect_ipv4(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_ipv4_hdr *ip_hdr;\n+\tstruct rte_ipv4_hdr _ip_hdr;\n+\tchar sbuf[INET_ADDRSTRLEN], dbuf[INET_ADDRSTRLEN];\n+\n+\tip_hdr = rte_pktmbuf_read(mb, offset, sizeof(*ip_hdr), &_ip_hdr);\n+\tif (unlikely(ip_hdr == NULL)) {\n+\t\tprintf(\"truncated IP! \");\n+\t\treturn;\n+\t}\n+\n+\tinet_ntop(AF_INET, &ip_hdr->src_addr, sbuf, sizeof(sbuf));\n+\tinet_ntop(AF_INET, &ip_hdr->dst_addr, dbuf, sizeof(dbuf));\n+\tprintf(\"%s → %s \", sbuf, dbuf);\n+\n+\toffset += ip_hdr->ihl * 4;\n+\tswitch (ip_hdr->next_proto_id) {\n+\tcase IPPROTO_UDP:\n+\t\treturn dissect_udp(mb, offset);\n+\tcase IPPROTO_TCP:\n+\t\treturn dissect_tcp(mb, offset);\n+\tcase IPPROTO_ICMP:\n+\t\treturn dissect_icmp(mb, offset);\n+\tdefault:\n+\t\t/* TODO dissect tunnels */\n+\t\tprintf(\"IP proto %#x \", ip_hdr->next_proto_id);\n+\t}\n+}\n+\n+static void\n+dissect_ipv6(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_ipv6_hdr *ip6_hdr;\n+\tstruct rte_ipv6_hdr _ip6_hdr;\n+\tchar sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];\n+\tuint16_t proto;\n+\tunsigned int i;\n+\n+\tip6_hdr = rte_pktmbuf_read(mb, offset, sizeof(*ip6_hdr), &_ip6_hdr);\n+\tif (unlikely(ip6_hdr == NULL)) {\n+\t\tprintf(\"truncated IPv6! \");\n+\t\treturn;\n+\t}\n+\toffset += sizeof(*ip6_hdr);\n+\n+\tinet_ntop(AF_INET6, ip6_hdr->src_addr, sbuf, sizeof(sbuf));\n+\tinet_ntop(AF_INET6, ip6_hdr->dst_addr, dbuf, sizeof(dbuf));\n+\tprintf(\"%s → %s \", sbuf, dbuf);\n+\n+#define MAX_EXT_HDRS 5\n+\tproto = ip6_hdr->proto;\n+\tfor (i = 0; i < MAX_EXT_HDRS; i++) {\n+\t\tswitch (proto) {\n+\t\tcase IPPROTO_UDP:\n+\t\t\treturn dissect_udp(mb, offset);\n+\t\tcase IPPROTO_TCP:\n+\t\t\treturn dissect_tcp(mb, offset);\n+\t\tcase IPPROTO_ICMPV6:\n+\t\t\treturn dissect_icmp(mb, offset);\n+\n+\t\tcase IPPROTO_HOPOPTS:\n+\t\tcase IPPROTO_ROUTING:\n+\t\tcase IPPROTO_DSTOPTS:\n+\t\t{\n+\t\t\tconst struct rte_ipv6_routing_ext *xh;\n+\t\t\tstruct rte_ipv6_routing_ext _xh;\n+\n+\t\t\txh = rte_pktmbuf_read(mb, offset, sizeof(*xh), &_xh);\n+\t\t\tif (unlikely(xh == NULL)) {\n+\t\t\t\tprintf(\"truncated IPV6 option! \");\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t\toffset += (xh->hdr_len + 1) * 8;\n+\t\t\tproto = xh->next_hdr;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tcase IPPROTO_FRAGMENT:\n+\t\t\tprintf(\"FRAG \");\n+\t\t\treturn;\n+\n+\t\tcase IPPROTO_NONE:\n+\t\t\tprintf(\"NONE \");\n+\t\t\treturn;\n+\n+\t\tdefault:\n+\t\t\tprintf(\"IPv6 proto %u \", proto);\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\n+\tprintf(\"Too many extensions! \");\n+}\n+\n+static void\n+dissect_eth(const struct rte_mbuf *mb, uint16_t offset)\n+{\n+\tconst struct rte_ether_hdr *eth_hdr;\n+\tstruct rte_ether_hdr _eth_hdr;\n+\tuint16_t eth_type;\n+\tchar sbuf[RTE_ETHER_ADDR_FMT_SIZE], dbuf[RTE_ETHER_ADDR_FMT_SIZE];\n+\n+\teth_hdr = rte_pktmbuf_read(mb, offset, sizeof(struct rte_ether_hdr), &_eth_hdr);\n+\tif (unlikely(eth_hdr == NULL)) {\n+\t\tprintf(\"missing Eth header! offset=%u\", offset);\n+\t\treturn;\n+\t}\n+\n+\toffset += sizeof(*eth_hdr);\n+\teth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);\n+\tif (eth_type == RTE_ETHER_TYPE_VLAN || eth_type == RTE_ETHER_TYPE_QINQ) {\n+\t\tconst struct rte_vlan_hdr *vh\n+\t\t\t= (const struct rte_vlan_hdr *)(eth_hdr + 1);\n+\t\teth_type = vh->eth_proto;\n+\t\toffset += sizeof(*vh);\n+\n+\t\tprintf(\"%s %#x \", eth_type == RTE_ETHER_TYPE_VLAN ? \"VLAN\" : \"QINQ\",\n+\t\t       RTE_BE_TO_CPU_16(vh->vlan_tci));\n+\t}\n+\n+\tswitch (eth_type) {\n+\tcase RTE_ETHER_TYPE_ARP:\n+\t\trte_ether_format_addr(sbuf, sizeof(sbuf), &eth_hdr->src_addr);\n+\t\trte_ether_format_addr(sbuf, sizeof(dbuf), &eth_hdr->dst_addr);\n+\t\tprintf(\"%s → %s ARP \", sbuf, dbuf);\n+\n+\t\tdissect_arp(mb, offset);\n+\t\tbreak;\n+\tcase RTE_ETHER_TYPE_IPV4:\n+\t\tdissect_ipv4(mb, offset);\n+\t\tbreak;\n+\n+\tcase RTE_ETHER_TYPE_IPV6:\n+\t\tdissect_ipv6(mb, offset);\n+\t\tbreak;\n+\tdefault:\n+\t\tprintf(\"Ethernet proto %#x \", eth_type);\n+\t}\n+}\n+\n+/* Brief tshark style one line output which is\n+ * number time_delta Source Destination Protocol len info\n+ */\n+static void\n+dump_pkt_brief(uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts)\n+{\n+\tstatic uint64_t start_cycles;\n+\tstatic uint64_t packet_count;\n+\tuint64_t now;\n+\tuint64_t count;\n+\tdouble interval;\n+\tuint16_t i;\n+\n+\tif (!nb_pkts)\n+\t\treturn;\n+\n+\tnow = rte_rdtsc();\n+\tif (start_cycles == 0)\n+\t\tstart_cycles = now;\n+\tinterval = (double)(now - start_cycles) / (double)rte_get_tsc_hz();\n+\n+\tcount = __atomic_fetch_add(&packet_count, nb_pkts, __ATOMIC_RELAXED);\n+\n+\tfor (i = 0; i < nb_pkts; i++) {\n+\t\tconst struct rte_mbuf *mb = pkts[i];\n+\n+\t\tprintf(\"%6\"PRIu64\" %11.9f %4u:%-3u \", count + i, interval, mb->port, queue);\n+\t\tdissect_eth(mb, 0);\n+\t\tputchar('\\n');\n+\t}\n+\tfflush(stdout);\n+}\n+\n+/* Hex dump of packet data */\n+static void\n+dump_pkt_hex(struct rte_mbuf *pkts[], uint16_t nb_pkts)\n+{\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < nb_pkts; i++)\n+\t\trte_pktmbuf_dump(stdout, pkts[i], MAX_DUMP_LEN);\n+\n+\tfflush(stdout);\n+}\n+\n+static uint16_t\n+dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n+\t      uint16_t nb_pkts, int is_rx)\n+{\n+\tswitch (verbose_level) {\n+\tcase VERBOSE_RX ... VERBOSE_BOTH:\n+\t\tdump_pkt_verbose(port_id, queue, pkts, nb_pkts, is_rx);\n+\t\tbreak;\n+\tcase VERBOSE_DISSECT:\n+\t\tdump_pkt_brief(queue, pkts, nb_pkts);\n+\t\tbreak;\n+\tcase VERBOSE_HEX:\n+\t\tdump_pkt_hex(pkts, nb_pkts);\n+\t}\n+\treturn nb_pkts;\n+}\n+\n uint16_t\n dump_rx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n \t     uint16_t nb_pkts, __rte_unused uint16_t max_pkts,\ndiff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\nindex 2fbf9220d8a9..f8b75b09afd0 100644\n--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n@@ -677,7 +677,10 @@ Available levels are as following:\n * ``0`` silent except for error.\n * ``1`` fully verbose except for Tx packets.\n * ``2`` fully verbose except for Rx packets.\n-* ``> 2`` fully verbose.\n+* ``3`` fully verbose except for Tx and Rx packets.\n+* ``4`` dissected protocol information for Tx and Rx packets.\n+* ``5`` hex dump of packets\n+\n \n set log\n ~~~~~~~\n",
    "prefixes": []
}