From patchwork Tue Jul 23 02:44:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142652 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: 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]) by inbox.dpdk.org (Postfix) with ESMTP id 1F0584568C; Tue, 23 Jul 2024 04:45:54 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 1413740E19; Tue, 23 Jul 2024 04:45:52 +0200 (CEST) Received: from mail-pf1-f182.google.com (mail-pf1-f182.google.com [209.85.210.182]) by mails.dpdk.org (Postfix) with ESMTP id 770A9402C3 for ; Tue, 23 Jul 2024 04:45:48 +0200 (CEST) Received: by mail-pf1-f182.google.com with SMTP id d2e1a72fcca58-70d333d5890so938146b3a.0 for ; Mon, 22 Jul 2024 19:45:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1721702747; x=1722307547; darn=dpdk.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZPu4kQpUd8pQ+k1qAFRK8Pv39JcFz7fB9PNdBSTl444=; b=jf3NlNRmbd5btmX0oLrUmbYdjkLYVQ31s/NsAiP5RE3uOg45mjrzIc98Bc/fAPxG9J gfWUVbcYjYwRDRKxhUoKVuYK8oa51YwYw2WS3kPg1l8RDrAOIcunh4FsIxxKFvTP87NJ ezoLqg9FdyV1Xv6Ut9Vlxathtql/1gcIDzB6HJ4tIoogy2hQcj4Q8vUSg1VPxPG4KO/z Xn7lc6kXj4bONA62RaRFAQ5voTn/MpoSChghNbgMXfT8EsZEFvqFX7a/JHrdeBZErXyb G2ecYSpLTwshbEp6viGO7fOsz5d+Rka76rk/1lHa51qjrqx6AVfgpO111Z5UHTmbkHKt cTCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721702747; x=1722307547; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZPu4kQpUd8pQ+k1qAFRK8Pv39JcFz7fB9PNdBSTl444=; b=kqPLucp4F+lzW1ob+FVNy8RsQL3XMEJiuAau1574GiAPr9Wsko2spDNh4Fa7Zd5v8Z iG+kAwojzKV0LOYZ4QKWo9lO3OJNu/TKutKWHMHxiEk/zBp0ucx7A9AzcrxaOPFPfxMg rc0zLCYfWhcnGeZNbjhWWa1FR+EK1W2Jvsb3nQnvBTTHCaBUfRT6qd61vpqAiLnmdNKH Dig48d7PSspxwqCgnmoJY6m7jfiz+OI42ZbFEFrXd1TNuXlRrhmL3htwuCcEtHGMfyJd DelLjfRHXy1EaQVn9m6ZSVYHAALcf5x1TIT1CIz6u7JVWr8tcwawJ+10uHNZPWUs/sXA KfXA== X-Gm-Message-State: AOJu0YzPlEHFs1rB53pRe+txIg1R2cCESfA576Qh+aL41BI6mGVrrPKM XmsW3YU3klhd5dvce/iAWLZZ+26O6Ul6sp9wtLHf77Z19ESPPwl041vb5o17DHfCqiNMBNeqUgz 2hac= X-Google-Smtp-Source: AGHT+IHrbpmJNn3OXOZM//+RXvcgo3mwLeTFa5npbg/BlTJ+EIB+ABntw7Q6W5qJP5w1Tw6cGpVuqQ== X-Received: by 2002:a05:6a20:a113:b0:1c0:eba5:e187 with SMTP id adf61e73a8af0-1c422847e65mr14326625637.6.1721702747453; Mon, 22 Jul 2024 19:45:47 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2ccf808f05bsm7838924a91.40.2024.07.22.19.45.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Jul 2024 19:45:47 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v2 1/3] net: add new packet dissector Date: Mon, 22 Jul 2024 19:44:10 -0700 Message-ID: <20240723024537.980016-2-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240723024537.980016-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240723024537.980016-1-stephen@networkplumber.org> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org The function rte_dissect_mbuf is used to decode the contents of an mbuf and print them in human readable format similar to what tshark uses. For now, handles IP, IPv6, TCP, UDP, ICMP and ARP. The intention is to extend this to be able to handle more nested tunnel types as well as higher level protocols such as DNS and HTTP. Signed-off-by: Stephen Hemminger --- lib/net/meson.build | 2 + lib/net/rte_dissect.c | 357 ++++++++++++++++++++++++++++++++++++++++++ lib/net/rte_dissect.h | 40 +++++ lib/net/version.map | 7 + 4 files changed, 406 insertions(+) create mode 100644 lib/net/rte_dissect.c create mode 100644 lib/net/rte_dissect.h diff --git a/lib/net/meson.build b/lib/net/meson.build index 0b69138949..48edf17ea3 100644 --- a/lib/net/meson.build +++ b/lib/net/meson.build @@ -2,6 +2,7 @@ # Copyright(c) 2017-2020 Intel Corporation headers = files( + 'rte_dissect.h', 'rte_ip.h', 'rte_tcp.h', 'rte_udp.h', @@ -30,6 +31,7 @@ headers = files( sources = files( 'rte_arp.c', + 'rte_dissect.c', 'rte_ether.c', 'rte_net.c', 'rte_net_crc.c', diff --git a/lib/net/rte_dissect.c b/lib/net/rte_dissect.c new file mode 100644 index 0000000000..40376a8842 --- /dev/null +++ b/lib/net/rte_dissect.c @@ -0,0 +1,357 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Stephen Hemminger + * + * Print packets in format similar to tshark. + * Output should be one line per mbuf + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct dissect_ctx { + jmp_buf jmpenv; /* unwind when dump_len is reached */ + uint32_t offset; /* current offset */ + uint32_t dump_len; /* maximum depth in packet to look at */ +} dissect_ctx_t; + +static void +dissect_eth(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb); + +/* Read data from segmented mbuf, but stop if would go past max length */ +static const void * +dissect_read(dissect_ctx_t *ctx, const struct rte_mbuf *m, + void *buf, size_t len) +{ + /* If this header would be past the requested length + * then unwind back to end the string. + */ + if (ctx->dump_len != 0 && ctx->offset + len > ctx->dump_len) + longjmp(ctx->jmpenv, 1); + + return rte_pktmbuf_read(m, ctx->offset, len, buf); +} + +static void +dissect_arp(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_arp_hdr *arp; + struct rte_arp_hdr _arp; + uint16_t ar_op; + char buf[128]; + + arp = dissect_read(ctx, mb, &_arp, sizeof(_arp)); + if (unlikely(arp == NULL)) { + fprintf(f, "truncated ARP! "); + return; + } + + ar_op = rte_be_to_cpu_16(arp->arp_opcode); + switch (ar_op) { + case RTE_ARP_OP_REQUEST: + inet_ntop(AF_INET, &arp->arp_data.arp_tip, buf, sizeof(buf)); + fprintf(f, "Who has %s? ", buf); + + rte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha); + fprintf(f, "Tell %s ", buf); + break; + case RTE_ARP_OP_REPLY: + inet_ntop(AF_INET, &arp->arp_data.arp_sip, buf, sizeof(buf)); + fprintf(f, "%s is at", buf); + + rte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha); + fprintf(f, "%s ", buf); + break; + case RTE_ARP_OP_INVREQUEST: + rte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_tha); + fprintf(f, "Who is %s? ", buf); + + rte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha); + fprintf(f, "Tell %s ", buf); + break; + + case RTE_ARP_OP_INVREPLY: + rte_ether_format_addr(buf, sizeof(buf), &arp->arp_data.arp_sha); + fprintf(f, "%s is at ", buf); + + inet_ntop(AF_INET, &arp->arp_data.arp_sip, buf, sizeof(buf)); + fprintf(f, "%s ", buf); + break; + default: + fprintf(f, "Unknown ARP %#x ", ar_op); + break; + } +} + +static void +dissect_vxlan(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_vxlan_hdr *vxlan; + struct rte_vxlan_hdr _vxlan; + + vxlan = dissect_read(ctx, mb, &_vxlan, sizeof(_vxlan)); + fprintf(f, "VXLAN "); + if (vxlan->flag_i) { + uint32_t vni = rte_be_to_cpu_32(vxlan->vx_vni); + + fprintf(f, "%#x ", vni >> 8); + } + dissect_eth(ctx, f, mb); +} + +static void +dissect_udp(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_udp_hdr *udph; + struct rte_udp_hdr _udp; + uint16_t src_port, dst_port; + + udph = dissect_read(ctx, mb, &_udp, sizeof(_udp)); + if (unlikely(udph == NULL)) { + fprintf(f, "truncated UDP! "); + return; + } + + src_port = rte_be_to_cpu_16(udph->src_port); + dst_port = rte_be_to_cpu_16(udph->dst_port); + + switch (dst_port) { + case RTE_VXLAN_DEFAULT_PORT: + dissect_vxlan(ctx, f, mb); + break; + default: + fprintf(f, "UDP %u %u → %u ", rte_be_to_cpu_16(udph->dgram_len), src_port, dst_port); + } +} + +static void +dissect_tcp(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_tcp_hdr *tcph; + struct rte_tcp_hdr _tcp; + uint16_t src_port, dst_port; + + tcph = dissect_read(ctx, mb, &_tcp, sizeof(_tcp)); + if (unlikely(tcph == NULL)) { + fprintf(f, "truncated TCP! "); + return; + } + + src_port = rte_be_to_cpu_16(tcph->src_port); + dst_port = rte_be_to_cpu_16(tcph->dst_port); + + fprintf(f, "TCP %u → %u", + src_port, dst_port); +#define PRINT_TCP_FLAG(flag) \ + if (tcph->tcp_flags & RTE_TCP_ ## flag ## _FLAG) \ + fprintf(f, " [" #flag" ]") + + PRINT_TCP_FLAG(URG); + PRINT_TCP_FLAG(ACK); + PRINT_TCP_FLAG(RST); + PRINT_TCP_FLAG(SYN); + PRINT_TCP_FLAG(FIN); +#undef PRINT_TCP_FLAG + + fprintf(f, "Seq=%u Ack=%u Win=%u ", + rte_be_to_cpu_16(tcph->sent_seq), + rte_be_to_cpu_16(tcph->recv_ack), + rte_be_to_cpu_16(tcph->rx_win)); +} + +static void +dissect_icmp(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_icmp_hdr *icmp; + struct rte_icmp_hdr _icmp; + static const char * const icmp_types[256] = { + [RTE_IP_ICMP_ECHO_REPLY] = "ICMP Reply", + [RTE_IP_ICMP_ECHO_REQUEST] = "ICMP Request", + [RTE_ICMP6_ECHO_REPLY] = "ICMPv6 Reply", + [RTE_ICMP6_ECHO_REQUEST] = "ICMPv6 Request", + [133] = "ICMPv6 Router Solicitation", + [134] = "ICMPv6 Router Solicitation", + }; + + icmp = dissect_read(ctx, mb, &_icmp, sizeof(_icmp)); + if (unlikely(icmp == NULL)) { + fprintf(f, "truncated ICMP! "); + } else { + const char *name = icmp_types[icmp->icmp_type]; + + if (name != NULL) + fprintf(f, "%s ", name); + else + fprintf(f, "ICMP type %u ", icmp->icmp_type); + } +} + +static void +dissect_ipv4(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_ipv4_hdr *ip_hdr; + struct rte_ipv4_hdr _ip_hdr; + char sbuf[INET_ADDRSTRLEN], dbuf[INET_ADDRSTRLEN]; + + ip_hdr = dissect_read(ctx, mb, &_ip_hdr, sizeof(_ip_hdr)); + if (unlikely(ip_hdr == NULL)) { + fprintf(f, "truncated IP! "); + return; + } + + inet_ntop(AF_INET, &ip_hdr->src_addr, sbuf, sizeof(sbuf)); + inet_ntop(AF_INET, &ip_hdr->dst_addr, dbuf, sizeof(dbuf)); + fprintf(f, "%s → %s ", sbuf, dbuf); + + ctx->offset += ip_hdr->ihl * 4; + switch (ip_hdr->next_proto_id) { + case IPPROTO_UDP: + return dissect_udp(ctx, f, mb); + case IPPROTO_TCP: + return dissect_tcp(ctx, f, mb); + case IPPROTO_ICMP: + return dissect_icmp(ctx, f, mb); + default: + /* TODO dissect tunnels */ + fprintf(f, "IP proto %#x ", ip_hdr->next_proto_id); + } +} + +static void +dissect_ipv6(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_ipv6_hdr *ip6_hdr; + struct rte_ipv6_hdr _ip6_hdr; + char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN]; + uint16_t proto; + unsigned int i; + + ip6_hdr = dissect_read(ctx, mb, &_ip6_hdr, sizeof(_ip6_hdr)); + if (unlikely(ip6_hdr == NULL)) { + fprintf(f, "truncated IPv6! "); + return; + } + ctx->offset += sizeof(*ip6_hdr); + + inet_ntop(AF_INET6, ip6_hdr->src_addr, sbuf, sizeof(sbuf)); + inet_ntop(AF_INET6, ip6_hdr->dst_addr, dbuf, sizeof(dbuf)); + fprintf(f, "%s → %s ", sbuf, dbuf); + +#define MAX_EXT_HDRS 5 + proto = ip6_hdr->proto; + for (i = 0; i < MAX_EXT_HDRS; i++) { + switch (proto) { + case IPPROTO_UDP: + return dissect_udp(ctx, f, mb); + case IPPROTO_TCP: + return dissect_tcp(ctx, f, mb); + case IPPROTO_ICMPV6: + return dissect_icmp(ctx, f, mb); + + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + { + const struct rte_ipv6_routing_ext *xh; + struct rte_ipv6_routing_ext _xh; + + xh = dissect_read(ctx, mb, &_xh, sizeof(xh)); + if (unlikely(xh == NULL)) { + fprintf(f, "truncated IPV6 option! "); + return; + } + ctx->offset += (xh->hdr_len + 1) * 8; + proto = xh->next_hdr; + continue; + } + + case IPPROTO_FRAGMENT: + fprintf(f, "FRAG "); + return; + + case IPPROTO_NONE: + fprintf(f, "NONE "); + return; + + default: + fprintf(f, "IPv6 proto %u ", proto); + return; + } + } + + fprintf(f, "Too many extensions!"); +} + +static void +dissect_eth(dissect_ctx_t *ctx, FILE *f, const struct rte_mbuf *mb) +{ + const struct rte_ether_hdr *eth_hdr; + struct rte_ether_hdr _eth_hdr; + uint16_t eth_type; + char sbuf[RTE_ETHER_ADDR_FMT_SIZE], dbuf[RTE_ETHER_ADDR_FMT_SIZE]; + + eth_hdr = dissect_read(ctx, mb, &_eth_hdr, sizeof(_eth_hdr)); + if (unlikely(eth_hdr == NULL)) { + fprintf(f, "missing Eth header!"); + return; + } + + ctx->offset += sizeof(*eth_hdr); + eth_type = rte_be_to_cpu_16(eth_hdr->ether_type); + if (eth_type == RTE_ETHER_TYPE_VLAN || eth_type == RTE_ETHER_TYPE_QINQ) { + const struct rte_vlan_hdr *vh + = (const struct rte_vlan_hdr *)(eth_hdr + 1); + eth_type = vh->eth_proto; + ctx->offset += sizeof(*vh); + + fprintf(f, "%s %#x ", eth_type == RTE_ETHER_TYPE_VLAN ? "VLAN" : "QINQ", + rte_be_to_cpu_16(vh->vlan_tci)); + } + + switch (eth_type) { + case RTE_ETHER_TYPE_ARP: + rte_ether_format_addr(sbuf, sizeof(sbuf), ð_hdr->src_addr); + rte_ether_format_addr(sbuf, sizeof(dbuf), ð_hdr->dst_addr); + fprintf(f, "%s → %s ARP ", sbuf, dbuf); + + dissect_arp(ctx, f, mb); + break; + case RTE_ETHER_TYPE_IPV4: + dissect_ipv4(ctx, f, mb); + break; + + case RTE_ETHER_TYPE_IPV6: + dissect_ipv6(ctx, f, mb); + break; + default: + fprintf(f, "Ethernet proto %#x ", eth_type); + } +} + +void +rte_dissect_mbuf(FILE *f, const struct rte_mbuf *m, uint32_t dump_len) +{ + dissect_ctx_t ctx = { + .dump_len = dump_len, + }; + + if (setjmp(ctx.jmpenv) == 0) + dissect_eth(&ctx, f, m); + + putc('\n', f); +} diff --git a/lib/net/rte_dissect.h b/lib/net/rte_dissect.h new file mode 100644 index 0000000000..de14eeeb02 --- /dev/null +++ b/lib/net/rte_dissect.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Stephen Hemminger + */ + +#ifndef _RTE_NET_DISSECT_H_ +#define _RTE_NET_DISSECT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +struct rte_mbuf; + +/** + * + * Print packets in format (single line) similar to tshark to a file. + * + * @param f + * A pointer to a file for output + * @param m + * The packet mbuf. + * @param dump_len + * Maximum offset in packet to examine. + * If is zero then dump the whole packet. + */ +__rte_experimental +void +rte_dissect_mbuf(FILE *f, const struct rte_mbuf *m, uint32_t dump_len); + +#ifdef __cplusplus +} +#endif + + +#endif /* _RTE_NET_DISSECT_H_ */ diff --git a/lib/net/version.map b/lib/net/version.map index 3e293c4715..d7b9e9c0e7 100644 --- a/lib/net/version.map +++ b/lib/net/version.map @@ -12,3 +12,10 @@ DPDK_24 { local: *; }; + +EXPERIMENTAL { + global: + + # added in 24.11 + rte_dissect_mbuf; +}; From patchwork Tue Jul 23 02:44:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142653 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: 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]) by inbox.dpdk.org (Postfix) with ESMTP id 00CC54568C; Tue, 23 Jul 2024 04:46:01 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6C45440E22; Tue, 23 Jul 2024 04:45:53 +0200 (CEST) Received: from mail-pg1-f170.google.com (mail-pg1-f170.google.com [209.85.215.170]) by mails.dpdk.org (Postfix) with ESMTP id 389CD40E17 for ; Tue, 23 Jul 2024 04:45:49 +0200 (CEST) Received: by mail-pg1-f170.google.com with SMTP id 41be03b00d2f7-7a103ac7be3so113168a12.3 for ; Mon, 22 Jul 2024 19:45:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1721702748; x=1722307548; darn=dpdk.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=MzL0HOPwQ2pfOUWocOCZAFjyrEDAky5eHNlBbux7IUI=; b=jkcNnPMseLd9HCJhUAelSztnUnifu6ngRwKkrLu7cj1c4Er5YjqqVijZUgy91wyP8z Ire/F12Nlavx9/WjVYa+WUow41XUGyKeLSfHH3jNb6SRXZxmcWvaHAFd2uE7tajWs4sQ +r/Vv05fi+plGp8cB+olIZSJFrZwFhqazVwYxGGQPInf6YJ7RbojFMSqXyTXAbcS3BP5 DyjzN+tmlU0AuTsDhDh8z4H2B2svBiJOSH7vEZU17WdLk3j6KI/GyoAJYvWTRiQVtq7/ 4fKnEbh76lfWBx+vkM3+CU9cBp6ut0//LifQZjr33CQL7g7Sx93JXr40RrF8HCs3tY9V cDmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721702748; x=1722307548; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MzL0HOPwQ2pfOUWocOCZAFjyrEDAky5eHNlBbux7IUI=; b=KYsY03/6NzuGiAXLyOP04fVfk/pWUPukQt2w1ssbjC/a4hv1ZP2yEFJjH4ZecnPclf IOyEy6+zTciuuRqrzN+z37MYye8cQG4urhzcbXhl7VuhAZF+alQcOqcpk+QxC6pIBa// ow8kNQC+hQL4xMEPpsllKyqYbgRW2wrlo8vKHHF0f1Krz/bTI7bCNSLg5kQ1Obc6xTsg CEo1pE3bKRA9c4eUfOqdtlyb6K7giou4enalHGMpejmifSkyl9t+KqqPf9GTKmlm/Qwp /3PZsmhrRZS8KDZQb5VuMznSL+l+f4zMHVWWH3iakOErIIpZdbGwZGUYmBRq+AoG9aC0 DvrA== X-Gm-Message-State: AOJu0YyAJBEM2h0+xsCTnk9xabyfZC9Z9SrvlRXRteiRWu0tcgoP4baG EwIf3tWdFKKiRi+OPnQTvLwZBrsdDP931hEcQed2Hkb6jjZvpV4SSmGRmiYWF5rUhxCmd0OmEX1 GW3s= X-Google-Smtp-Source: AGHT+IF/tSwcxAvpCGPBQ9yklpaxH0mitHQhqb3Zu8AodEzzvjaUyQmeMZiI+EoqmdO9qUNYwUd/ow== X-Received: by 2002:a05:6a20:4321:b0:1c4:2134:dd52 with SMTP id adf61e73a8af0-1c422866ecdmr9636426637.3.1721702748220; Mon, 22 Jul 2024 19:45:48 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2ccf808f05bsm7838924a91.40.2024.07.22.19.45.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Jul 2024 19:45:47 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v2 2/3] test: add test for packet dissector Date: Mon, 22 Jul 2024 19:44:11 -0700 Message-ID: <20240723024537.980016-3-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240723024537.980016-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240723024537.980016-1-stephen@networkplumber.org> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Some tests for new packet dissector. Signed-off-by: Stephen Hemminger --- app/test/meson.build | 1 + app/test/test_dissect.c | 289 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 app/test/test_dissect.c diff --git a/app/test/meson.build b/app/test/meson.build index e29258e6ec..9cd2051320 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -62,6 +62,7 @@ source_file_deps = { 'test_debug.c': [], 'test_devargs.c': ['kvargs'], 'test_dispatcher.c': ['dispatcher'], + 'test_dissect.c': ['net'], 'test_distributor.c': ['distributor'], 'test_distributor_perf.c': ['distributor'], 'test_dmadev.c': ['dmadev', 'bus_vdev'], diff --git a/app/test/test_dissect.c b/app/test/test_dissect.c new file mode 100644 index 0000000000..a5e5c310aa --- /dev/null +++ b/app/test/test_dissect.c @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2024 Stephen Hemminger + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" + +#define TOTAL_PACKETS 100 +#define PACKET_LEN 1000 +#define ETH_IP_UDP_VXLAN_SIZE (sizeof(struct rte_ether_hdr) + \ + sizeof(struct rte_ipv4_hdr) + \ + sizeof(struct rte_udp_hdr) + \ + sizeof(struct rte_vxlan_hdr)) + + +static uint16_t port_id; +static const char null_dev[] = "net_null0"; + +static void +add_header(struct rte_mbuf *mb, uint32_t plen, + rte_be16_t src_port, rte_be16_t dst_port) +{ + struct { + struct rte_ether_hdr eth; + struct rte_ipv4_hdr ip; + struct rte_udp_hdr udp; + } pkt = { + .eth = { + .dst_addr.addr_bytes = "\xff\xff\xff\xff\xff\xff", + .ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4), + }, + .ip = { + .version_ihl = RTE_IPV4_VHL_DEF, + .time_to_live = 1, + .next_proto_id = IPPROTO_UDP, + .src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK), + .dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST), + }, + .udp = { + .dst_port = dst_port, + .src_port = src_port, + }, + }; + + rte_eth_random_addr(pkt.eth.src_addr.addr_bytes); + + plen -= sizeof(struct rte_ether_hdr); + pkt.ip.total_length = rte_cpu_to_be_16(plen); + pkt.ip.hdr_checksum = rte_ipv4_cksum(&pkt.ip); + + plen -= sizeof(struct rte_ipv4_hdr); + pkt.udp.src_port = rte_rand(); + pkt.udp.dgram_len = rte_cpu_to_be_16(plen); + + /* Copy header into mbuf */ + memcpy(rte_pktmbuf_append(mb, sizeof(pkt)), &pkt, sizeof(pkt)); +} + +static void +add_vxlan(struct rte_mbuf *mb, rte_be32_t vni) +{ + struct rte_vxlan_hdr *vxlan; + + vxlan = (struct rte_vxlan_hdr *)rte_pktmbuf_append(mb, sizeof(*vxlan)); + memset(vxlan, 0, sizeof(*vxlan)); + vxlan->flag_i = 1; + vxlan->vx_vni = vni; +} + + +static void +fill_data(struct rte_mbuf *mb, uint32_t len) +{ + uint32_t i; + char *ptr = rte_pktmbuf_append(mb, len); + char c = '!'; + + /* traditional barber pole pattern */ + for (i = 0; i < len; i++) { + ptr[i] = c++; + if (c == 0x7f) c = '!'; + } +} + +static void +mbuf_prep(struct rte_mbuf *mb, uint8_t buf[], uint32_t buf_len) +{ + mb->buf_addr = buf; + rte_mbuf_iova_set(mb, (uintptr_t)buf); + mb->buf_len = buf_len; + rte_mbuf_refcnt_set(mb, 1); + + /* set pool pointer to dummy value, test doesn't use it */ + mb->pool = (void *)buf; + + rte_pktmbuf_reset(mb); +} + +static int +test_setup(void) +{ + port_id = rte_eth_dev_count_avail(); + + /* Make a dummy null device to snoop on */ + if (rte_vdev_init(null_dev, NULL) != 0) { + fprintf(stderr, "Failed to create vdev '%s'\n", null_dev); + goto fail; + } + return 0; + +fail: + rte_vdev_uninit(null_dev); + return -1; +} + +static void +test_cleanup(void) +{ + rte_vdev_uninit(null_dev); +} + +static int +count_lines(FILE *f) +{ + char line[LINE_MAX]; + int count = 0; + + while (fgets(line, sizeof(line), f) != NULL) + ++count; + + return count; +} + +static int +test_simple(void) +{ + struct rte_mbuf mb; + uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE]; + uint32_t data_len = PACKET_LEN; + int lines; + FILE *tmp; + uint16_t src_port = rte_rand(); + const uint16_t dst_port = rte_cpu_to_be_16(9); /* Discard port */ + + tmp = tmpfile(); + TEST_ASSERT(tmp != NULL, "Tmpfile() failed!"); + + /* make a dummy packet */ + mbuf_prep(&mb, buf, sizeof(buf)); + add_header(&mb, data_len, src_port, dst_port); + fill_data(&mb, data_len - mb.data_off); + + for (unsigned int i = 0; i < TOTAL_PACKETS; i++) + rte_dissect_mbuf(tmp, &mb, 0); + + rewind(tmp); + lines = count_lines(tmp); + + TEST_ASSERT_EQUAL(lines, TOTAL_PACKETS, + "Expected %d lines but got %d", + TOTAL_PACKETS, lines); + + fclose(tmp); + + return TEST_SUCCESS; +} + +static int +test_truncated(void) +{ + struct rte_mbuf mb; + uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE]; + uint32_t pkt_len, data_len = PACKET_LEN; + uint16_t dst_port = rte_cpu_to_be_16(RTE_VXLAN_DEFAULT_PORT); + int lines; + FILE *tmp; + + tmp = tmpfile(); + TEST_ASSERT(tmp != NULL, "Tmpfile() failed!"); + + /* make a vxlan packet */ + mbuf_prep(&mb, buf, sizeof(buf)); + pkt_len = data_len; + do { + uint16_t src_port = rte_rand(); + uint32_t vni = rte_rand_max(1ul << 24); + + add_header(&mb, data_len, src_port, dst_port); + add_vxlan(&mb, vni); + pkt_len -= ETH_IP_UDP_VXLAN_SIZE; + } while (pkt_len > ETH_IP_UDP_VXLAN_SIZE); + + fill_data(&mb, pkt_len); + + for (unsigned int i = 0; i < TOTAL_PACKETS; i++) { + uint32_t snaplen = rte_rand_max(pkt_len); + + rte_dissect_mbuf(tmp, &mb, snaplen); + } + + rewind(tmp); + lines = count_lines(tmp); + + TEST_ASSERT_EQUAL(lines, TOTAL_PACKETS, + "Expected %d lines but got %d", + TOTAL_PACKETS, lines); + + fclose(tmp); + + return TEST_SUCCESS; +} + +static int +test_fuzz(void) +{ + struct rte_mbuf mb; + uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE]; + uint32_t data_len = PACKET_LEN; + const uint16_t dst_port = rte_cpu_to_be_16(rte_rand_max(1024)); + const uint16_t src_port = rte_cpu_to_be_16(rte_rand()); + int lines; + FILE *tmp; + + tmp = tmpfile(); + TEST_ASSERT(tmp != NULL, "Tmpfile() failed!"); + + /* make a dummy packet */ + mbuf_prep(&mb, buf, sizeof(buf)); + add_header(&mb, data_len, src_port, dst_port); + fill_data(&mb, data_len - mb.data_off); + + for (unsigned int i = 0; i < TOTAL_PACKETS; i++) { + uint32_t bit = rte_rand_max(data_len) * 8; + uint8_t *bp = buf + bit / 8; + uint8_t mask = 1u << (bit % 8); + + /* twiddle one bit */ + *bp ^= mask; + rte_dissect_mbuf(tmp, &mb, 0); + *bp ^= mask; + } + + rewind(tmp); + lines = count_lines(tmp); + + TEST_ASSERT_EQUAL(lines, TOTAL_PACKETS, + "Expected %d lines but got %d", + TOTAL_PACKETS, lines); + + fclose(tmp); + + return TEST_SUCCESS; +} + +static struct +unit_test_suite test_dissect_suite = { + .setup = test_setup, + .teardown = test_cleanup, + .suite_name = "Test Dissect Unit Test Suite", + .unit_test_cases = { + TEST_CASE(test_simple), + TEST_CASE(test_truncated), + TEST_CASE(test_fuzz), + TEST_CASES_END() + } +}; + +static int +test_dissect(void) +{ + return unit_test_suite_runner(&test_dissect_suite); +} + +REGISTER_FAST_TEST(dissect_autotest, true, true, test_dissect); From patchwork Tue Jul 23 02:44:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142654 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: 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]) by inbox.dpdk.org (Postfix) with ESMTP id 11E6F4568C; Tue, 23 Jul 2024 04:46:07 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D304C40E2D; Tue, 23 Jul 2024 04:45:54 +0200 (CEST) Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) by mails.dpdk.org (Postfix) with ESMTP id EC9E540E18 for ; Tue, 23 Jul 2024 04:45:49 +0200 (CEST) Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-70d24d0a8d4so1030424b3a.0 for ; Mon, 22 Jul 2024 19:45:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1721702749; x=1722307549; darn=dpdk.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JBOMz4nzLz4LyTiYaCD4cXSF+LDtqV4ypha6V7cDd/o=; b=C++kGkOdVkmUV9b7wjDhHS7K+2tfpGVArk4CzCQt8utZbU3tnemRflGyB8zeWel14g HDdxt4BsWd9iuo9SEMaNgPr4o6VRWvTuVlLIppwZIcl6n0Jz1AsBQ4qugx11Un1MeUNF ZkV/WGW0U9jbrAjLqs3Q1+nF8UenDP5lfgqMlxuw89cV1CF2Mxu5mj2veCU9dHlu9WbT xSYrrckKMTfarpKp+75X29SnX//tBVdkvbPB+cUh0Be0TUFwSJzobdMQswDot40QX1+B fQ9nboa7oSCkzKzysuTvjIt+bZ6m12HuhOxTG4pdbsoq/yrgjcq+d6n8vLHe/XgLc1rM 8Png== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721702749; x=1722307549; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JBOMz4nzLz4LyTiYaCD4cXSF+LDtqV4ypha6V7cDd/o=; b=gHH0nXDBwqeEtw4bRD4ey2lyFFCLBZbTRpolSZej0YujkKOU7jMa4gD8y/XUbRex9O YRewFqaSb7sxeuFI2ZMJ2WGqf45FRHA9O3QlT4HI6aDJKd3NLLZb7OK1NTyPIEpEzI1z weqGt/6Ur443ZVRKrxDLh4F119fPk5ezwRTszSB05HAFsb+GFq1UJSGiRNpY4XEJp6Ye LohfJFvgrzUOukQpfATRMfhwgp4wHHC7TPS4EZCDNgH4ECFXqzftttKBnYyrRr37PEI3 xOOo1VSWtdc0WNUBR6eYtFcf13Od3wjea1lWnf/jH6kaXxTSSP47cm7n1z1gtj0slRpF vLcQ== X-Gm-Message-State: AOJu0YwVawKc7JaAjhXaYJfCHVLE8fpmvXygboPAnhzSvd1oYQOkfQGz +djQchRmrMKZ8zDi9az890XwwC1hQYJ83+grB53+0F8qRarpxQBV7ruDyreEfQPraWuBMlCM5/8 LnNA= X-Google-Smtp-Source: AGHT+IG4VnH3CC17oDAJOsx5c1Wif6IZjA34XWQ4YMvo89yb2iDBNYgIxtr9k3+0MM4xAL1izFJvSw== X-Received: by 2002:a05:6a20:3d87:b0:1c2:8d72:67ce with SMTP id adf61e73a8af0-1c4228963c3mr9230696637.15.1721702749017; Mon, 22 Jul 2024 19:45:49 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2ccf808f05bsm7838924a91.40.2024.07.22.19.45.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Jul 2024 19:45:48 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Ori Kam , Aman Singh Subject: [PATCH v2 3/3] test-pmd: add more packet verbose decode options Date: Mon, 22 Jul 2024 19:44:12 -0700 Message-ID: <20240723024537.980016-4-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240723024537.980016-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240723024537.980016-1-stephen@networkplumber.org> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org The existing verbose levels 1..3 provide a messy multi-line output per packet. I found this unhelpful when diagnosing many types of problems like packet flow. This patch keeps the previous levels and adds two new levels: 4: one line per packet is printed in a format resembling tshark output. With addresses and protocol info. 5: dump packet in hex. Useful if the driver is messing up the data. Signed-off-by: Stephen Hemminger --- app/test-pmd/cmdline_flow.c | 3 +- app/test-pmd/config.c | 33 ++++++---- app/test-pmd/testpmd.h | 11 ++++ app/test-pmd/util.c | 71 +++++++++++++++++++-- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 5 +- 5 files changed, 105 insertions(+), 18 deletions(-) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index a76b44bf39..f553828755 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -14076,7 +14076,8 @@ cmd_set_raw_parsed(const struct buffer *in) upper_layer = proto; } } - if (verbose_level & 0x1) + + if (verbose_level > 0) printf("total data size is %zu\n", (*total_size)); RTE_ASSERT((*total_size) <= ACTION_RAW_ENCAP_MAX_DATA); memmove(data, (data_tail - (*total_size)), *total_size); diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 66c3a68c1d..5f01e70875 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -6246,26 +6246,37 @@ configure_rxtx_dump_callbacks(uint16_t verbose) return; #endif - RTE_ETH_FOREACH_DEV(portid) - { - if (verbose == 1 || verbose > 2) + RTE_ETH_FOREACH_DEV(portid) { + switch (verbose) { + case VERBOSE_OFF: + remove_rx_dump_callbacks(portid); + remove_tx_dump_callbacks(portid); + break; + case VERBOSE_RX: add_rx_dump_callbacks(portid); - else + remove_tx_dump_callbacks(portid); + break; + case VERBOSE_TX: + add_tx_dump_callbacks(portid); remove_rx_dump_callbacks(portid); - if (verbose >= 2) + break; + default: + add_rx_dump_callbacks(portid); add_tx_dump_callbacks(portid); - else - remove_tx_dump_callbacks(portid); + } } } void set_verbose_level(uint16_t vb_level) { - printf("Change verbose level from %u to %u\n", - (unsigned int) verbose_level, (unsigned int) vb_level); - verbose_level = vb_level; - configure_rxtx_dump_callbacks(verbose_level); + if (vb_level < VERBOSE_MAX) { + printf("Change verbose level from %u to %u\n", verbose_level, vb_level); + verbose_level = vb_level; + configure_rxtx_dump_callbacks(verbose_level); + } else { + fprintf(stderr, "Verbose level %u is out of range\n", vb_level); + } } void diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 9facd7f281..3d7a2b6dac 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -489,6 +489,17 @@ enum dcb_mode_enable extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */ +enum verbose_mode { + VERBOSE_OFF = 0, + VERBOSE_RX, + VERBOSE_TX, + VERBOSE_BOTH, + VERBOSE_DISSECT, + VERBOSE_HEX, + VERBOSE_MAX +}; + + /* globals used for configuration */ extern uint8_t record_core_cycles; /**< Enables measurement of CPU cycles */ extern uint8_t record_burst_stats; /**< Enables display of RX and TX bursts */ diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index bf9b639d95..209c46b10d 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include "testpmd.h" #define MAX_STRING_LEN 8192 +#define MAX_DUMP_LEN 1024 #define MKDUMPSTR(buf, buf_size, cur_len, ...) \ do { \ @@ -67,9 +69,10 @@ get_timestamp(const struct rte_mbuf *mbuf) timestamp_dynfield_offset, rte_mbuf_timestamp_t *); } -static inline void -dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], - uint16_t nb_pkts, int is_rx) +/* More verbose older style packet decode */ +static void +dump_pkt_verbose(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], + uint16_t nb_pkts, int is_rx) { struct rte_mbuf *mb; const struct rte_ether_hdr *eth_hdr; @@ -90,8 +93,6 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], size_t cur_len = 0; uint64_t restore_info_dynflag; - if (!nb_pkts) - return; restore_info_dynflag = rte_flow_restore_info_dynflag(); MKDUMPSTR(print_buf, buf_size, cur_len, "port %u/queue %u: %s %u packets\n", port_id, queue, @@ -299,6 +300,66 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], } } +/* Brief tshark style one line output which is + * number time_delta Source Destination Protocol len info + */ +static void +dump_pkt_brief(uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts) +{ + static uint64_t start_cycles; + static uint64_t packet_count; + uint64_t now; + uint64_t count; + double interval; + uint16_t i; + + now = rte_rdtsc(); + if (start_cycles == 0) + start_cycles = now; + interval = (double)(now - start_cycles) / (double)rte_get_tsc_hz(); + + count = __atomic_fetch_add(&packet_count, nb_pkts, __ATOMIC_RELAXED); + + for (i = 0; i < nb_pkts; i++) { + const struct rte_mbuf *mb = pkts[i]; + + printf("%6"PRIu64" %11.9f %4u:%-3u ", count + i, interval, mb->port, queue); + rte_dissect_mbuf(stdout, mb, 0); + } +} + +/* Hex dump of packet data */ +static void +dump_pkt_hex(struct rte_mbuf *pkts[], uint16_t nb_pkts) +{ + uint16_t i; + + for (i = 0; i < nb_pkts; i++) + rte_pktmbuf_dump(stdout, pkts[i], MAX_DUMP_LEN); + +} + +static uint16_t +dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], + uint16_t nb_pkts, int is_rx) +{ + if (unlikely(nb_pkts == 0)) + return 0; + + switch (verbose_level) { + case VERBOSE_RX ... VERBOSE_BOTH: + dump_pkt_verbose(port_id, queue, pkts, nb_pkts, is_rx); + break; + case VERBOSE_DISSECT: + dump_pkt_brief(queue, pkts, nb_pkts); + break; + case VERBOSE_HEX: + dump_pkt_hex(pkts, nb_pkts); + } + fflush(stdout); + return nb_pkts; +} + uint16_t dump_rx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, __rte_unused uint16_t max_pkts, diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index c19b4f8958..688806754a 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -676,7 +676,10 @@ Available levels are as following: * ``0`` silent except for error. * ``1`` fully verbose except for Tx packets. * ``2`` fully verbose except for Rx packets. -* ``> 2`` fully verbose. +* ``3`` fully verbose except for Tx and Rx packets. +* ``4`` dissected protocol information for Tx and Rx packets. +* ``5`` hex dump of packets + set log ~~~~~~~