From patchwork Thu Aug 1 19:04:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142854 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 94BA245716; Thu, 1 Aug 2024 21:06:34 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 36AB840E38; Thu, 1 Aug 2024 21:06:30 +0200 (CEST) Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) by mails.dpdk.org (Postfix) with ESMTP id 8986640668 for ; Thu, 1 Aug 2024 21:06:28 +0200 (CEST) Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-1ff4568676eso19887495ad.0 for ; Thu, 01 Aug 2024 12:06:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722539188; x=1723143988; 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=LPoPMuWjjrTWYXAFqW4Fi54RT23qllLTTIghqYDZ7iE=; b=PFPSQ3WwtyUPr/OzbkYeClz64Q6pblEM6oQ3byknZaG7rYnGhICbCXbBncqZDMDPy4 0S9NcCdm0OajPyZyFlgv7ghO6SE7guWO2ew5GauYPV2Haoz6zy4V8eCxnTFmHjp0VY6q LCJ8J9xcIBlVHVjZtA9Xc1t6wexQvOnBL46UIEZHi/i8RCOLZqxYpV0R2t3UbTHdHfte Cq66lpdtFPJ2Sq5SgHnPJgVs+yum4BMUGqmzlK/Uhh1MLKQU99FvvsaNu1w2G7aSe2Ps 0qPjTZyOyejUTA2gP9mGhHVG1mgkKyR7YB0+dXlOapobEDudUvD5zjzVd7DvLpD52rvJ RIMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722539188; x=1723143988; 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=LPoPMuWjjrTWYXAFqW4Fi54RT23qllLTTIghqYDZ7iE=; b=C8vp6V6EXVrQQFk5Tywwbd2nPsQHuZMb4Q6p4VXQUGA3UpJn6r9Vc493KX6aUR67qh sglOT7fX8u5TcODr0koKO+EaH/HBww1RVxE/LwkI376CYR49/Nb1unKdf2ej0MTnvhUB g9sxHRkk4zBLldAnrfNd+1xNWhhpUhqLiKy4dWBiL5iYDIZd3Q2MTw0y/CKTfUo1gWc/ pIy63zIDMj7YLy5zC3SttQ98PL8p/C0j0uYv2rQaLr/mv12CIAdmyHn42zynvXI26d9G +5bPvA3SRFRm7/flPLL1gj7GKfWAp0bt3204u1UnuWi0j0BsW/LksugNd2ZoOdJJ6ezi 4k5w== X-Gm-Message-State: AOJu0YzPkQGtK4YqwCsFo5MmGeSEi1Iu6P+gFD47Y+e2NWId/ICnRzAk LYIrYEwtNb8TvNT+kw0sAeUsaqaOA563JNne/wddZz8+L/wc+4V5Y5qTGhxTL/7PTU9HSIBIdcj i X-Google-Smtp-Source: AGHT+IFyeyeQBMAe6ErbG2FotnERUtWa2r8PaXRHa/Atac0JuaIsk9EW3WO5XICj7C5/amf3VzhJEw== X-Received: by 2002:a17:902:da83:b0:1fd:9b96:32f5 with SMTP id d9443c01a7336-1ff572b9a30mr15667135ad.31.1722539187669; Thu, 01 Aug 2024 12:06:27 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f5a222sm2371955ad.112.2024.08.01.12.06.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Aug 2024 12:06:27 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v5 1/4] net: add more icmp types Date: Thu, 1 Aug 2024 12:04:40 -0700 Message-ID: <20240801190617.201574-2-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240801190617.201574-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240801190617.201574-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 Add more defines for additional defined ICMP types. Signed-off-by: Stephen Hemminger --- lib/net/rte_icmp.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/net/rte_icmp.h b/lib/net/rte_icmp.h index 4bf64d70ad..b51b60a6d2 100644 --- a/lib/net/rte_icmp.h +++ b/lib/net/rte_icmp.h @@ -54,10 +54,24 @@ struct rte_icmp_hdr { } __rte_packed; /* ICMP packet types */ -#define RTE_IP_ICMP_ECHO_REPLY 0 -#define RTE_IP_ICMP_ECHO_REQUEST 8 -#define RTE_ICMP6_ECHO_REQUEST 128 -#define RTE_ICMP6_ECHO_REPLY 129 +#define RTE_IP_ICMP_ECHO_REPLY 0 +#define RTE_IP_ICMP_DEST_UNREACH 3 +#define RTE_IP_ICMP_SOURCE_QUENCH 4 +#define RTE_IP_ICMP_REDIRECT 5 +#define RTE_IP_ICMP_ECHO_REQUEST 8 +#define RTE_IP_ICMP_TIME_EXCEEDED 11 +#define RTE_IP_ICMP_PARAMETERPROB 12 +#define RTE_IP_ICMP_TIMESTAMP 13 +#define RTE_IP_ICMP_TIMESTAMPREPLY 14 +#define RTE_IP_ICMP_INFO_REQUEST 15 +#define RTE_IP_ICMP_INFO_REPLY 16 + +#define RTE_ICMP6_ECHO_REQUEST 128 +#define RTE_ICMP6_ECHO_REPLY 129 +#define RTE_ND_ROUTER_SOLICIT 133 +#define RTE_ND_ROUTER_ADVERT 134 +#define RTE_ND_NEIGHBOR_SOLICIT 135 +#define RTE_ND_NEIGHBOR_ADVERT 136 #ifdef __cplusplus } From patchwork Thu Aug 1 19:04:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142855 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 6609C45716; Thu, 1 Aug 2024 21:06:40 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5502F40E49; Thu, 1 Aug 2024 21:06:31 +0200 (CEST) Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) by mails.dpdk.org (Postfix) with ESMTP id 740FD40A8B for ; Thu, 1 Aug 2024 21:06:29 +0200 (CEST) Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-1ff4fa918afso8293165ad.1 for ; Thu, 01 Aug 2024 12:06:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722539188; x=1723143988; 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=Yx5Tgbg6/2PFLpMNXCkNcK13vymVXcjykMyX0Evo730=; b=kJSsFP3gIMFLxbGnESTjx7FIWmhPsE3qTg51geL2f0HHNJ1+LFXCVWzOqpc6suuy81 eyiEbj8OZKVs9QOYEUg3g/SPhp9xtpYPY7OAfAWrCxmAx5F/H8JxLLBLudolTXG44i3l Q0oJp8BJlZCWEhDqpOPpc6I1aPMakwQaArOXAFyzPhQXarfLFBRjVswVkz9z+QTxGZlZ gGkus4uBe8gfbLPEJus4exOU9NlvjootrJnsGd2qG24f0iMmMbh0W0GsVkwKeMECuRYE JqUW+8njsGJQ9JvU8h6dWmLydjBHkO2qpbXa6X904ck93/9ZN/BhUMOjxcz4qA+OPRbq Yk8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722539188; x=1723143988; 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=Yx5Tgbg6/2PFLpMNXCkNcK13vymVXcjykMyX0Evo730=; b=aAgxcWTbEDeFP0c3caHHqARrF6BJfMOYrRx6Jp+HFNNj69SKd7TLQpuYFIIHlgiPi2 blf3c5s/6AHsGE1rSJh/9r70Yg62VI1ZUsoZNpRmNZgqQMbtjZ9VMzytsy/4o2J/GIbJ 6WBLcFF6vqY4XNmz2Pw+dzrUwoeopojPnWuheTvCZy6XQ+wrtDvXtTUcqjpviPNewvLk 3AgKL8vVnHsD1dbOgc1MJF9kS31RHsahuuu7mNAH017lfzdvY/a3+vtr6hO5MBGTeM76 vRdS4nqSpexCqVtjyHfDSAWglkCcq/w7BwHr1bxh1fw0T62aXcNSxco4++lEYid8lvYr yy+A== X-Gm-Message-State: AOJu0YxNCX2hfKO/Rlz8vA0UDR70itZS7YL9q0/ktcqHLq3D0cvdaRrN ZTSr3qq/2OFqy1GIVoReorAkzEB+gnijtFw2L6JHN19pg0VUHbRKKun/5nurn9zc2OasTmucngM 4 X-Google-Smtp-Source: AGHT+IG2jCif8L7l4VJmOCAbbuEMKYwUbzpJkpHkVt9VSwlh8/ERI2b5atgqIe+bsrzBwnt2TJlFvg== X-Received: by 2002:a17:903:24f:b0:1fa:8f64:8afd with SMTP id d9443c01a7336-1ff5722eb62mr16344205ad.11.1722539188438; Thu, 01 Aug 2024 12:06:28 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f5a222sm2371955ad.112.2024.08.01.12.06.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Aug 2024 12:06:28 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v5 2/4] net: add new packet dissector Date: Thu, 1 Aug 2024 12:04:41 -0700 Message-ID: <20240801190617.201574-3-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240801190617.201574-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240801190617.201574-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 into ah uman readable format similar to what tshark uses. For now, handles IP, IPv6, TCP, UDP, ICMP and ARP. Signed-off-by: Stephen Hemminger --- lib/net/meson.build | 2 + lib/net/rte_dissect.c | 416 ++++++++++++++++++++++++++++++++++++++++++ lib/net/rte_dissect.h | 42 +++++ lib/net/version.map | 7 + 4 files changed, 467 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..ae86f7591e --- /dev/null +++ b/lib/net/rte_dissect.c @@ -0,0 +1,416 @@ +/* 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 + +/* Forward declaration - Ethernet can be nested */ +static void +dissect_eth(char *buf, size_t size, const struct rte_mbuf *mb, + uint32_t offset, uint32_t dump_len); + +/* + * Read data from segmented mbuf and put it into buf , but stop if would go past max length + * See rte_pktmbuf_read() + */ +static const void * +dissect_read(const struct rte_mbuf *m, uint32_t offset, uint32_t len, + void *buf, uint32_t dump_len) +{ + /* If this header would be past the requested length + * then unwind back to end the string. + */ + if (dump_len > 0 && offset + len > dump_len) + return NULL; + + return rte_pktmbuf_read(m, offset, len, buf); +} + +/* + * Print to string buffer and adjust result + * Returns true on success, false if buffer is exhausted. + */ +static __rte_format_printf(3, 4) bool +dissect_print(char **buf, size_t *sz, const char *fmt, ...) +{ + va_list ap; + int cnt; + + va_start(ap, fmt); + cnt = vsnprintf(*buf, *sz, fmt, ap); + va_end(ap); + + /* error or string is full */ + if (cnt < 0 || cnt >= (int)*sz) { + *sz = 0; + return false; + } + + *buf += cnt; + *sz -= cnt; + return true; +} + +static void +dissect_arp(char *buf, size_t size, const struct rte_mbuf *mb, uint32_t offset, uint32_t dump_len) +{ + const struct rte_arp_hdr *arp; + struct rte_arp_hdr _arp; + char abuf[64]; + + arp = dissect_read(mb, offset, sizeof(_arp), &_arp, dump_len); + if (arp == NULL) + return; + offset += sizeof(_arp); + + uint16_t 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, abuf, sizeof(abuf)); + if (!dissect_print(&buf, &size, "Who has %s? ", abuf)) + return; + + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_sha); + if (!dissect_print(&buf, &size, "Tell %s ", abuf)) + return; + + break; + case RTE_ARP_OP_REPLY: + inet_ntop(AF_INET, &arp->arp_data.arp_sip, abuf, sizeof(abuf)); + if (!dissect_print(&buf, &size, "%s is at", abuf)) + return; + + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_sha); + if (!dissect_print(&buf, &size, "%s ", abuf)) + return; + break; + case RTE_ARP_OP_INVREQUEST: + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_tha); + if (!dissect_print(&buf, &size, "Who is %s? ", abuf)) + return; + + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_sha); + if (!dissect_print(&buf, &size, "Tell %s ", abuf)) + return; + break; + + case RTE_ARP_OP_INVREPLY: + rte_ether_format_addr(abuf, sizeof(buf), &arp->arp_data.arp_sha); + if (!dissect_print(&buf, &size, "%s is at ", abuf)) + return; + + inet_ntop(AF_INET, &arp->arp_data.arp_sip, abuf, sizeof(abuf)); + if (!dissect_print(&buf, &size, "%s ", abuf)) + return; + break; + default: + if (!dissect_print(&buf, &size, "Unknown ARP %#x ", ar_op)) + return; + break; + } +} + +static void +dissect_vxlan(char *buf, size_t size, const struct rte_mbuf *mb, uint32_t offset, uint32_t dump_len) +{ + const struct rte_vxlan_hdr *vxlan; + struct rte_vxlan_hdr _vxlan; + + vxlan = dissect_read(mb, offset, sizeof(_vxlan), &_vxlan, dump_len); + if (vxlan == NULL) + return; + offset += sizeof(_vxlan); + + if (!dissect_print(&buf, &size, "VXLAN ")) + return; + + if (vxlan->flag_i) { + uint32_t vni = rte_be_to_cpu_32(vxlan->vx_vni); + + if (!dissect_print(&buf, &size, "%#x ", vni >> 8)) + return; + } + + dissect_eth(buf, size, mb, offset, dump_len); +} + +static void +dissect_udp(char *buf, size_t size, const struct rte_mbuf *mb, uint32_t offset, uint32_t dump_len) +{ + const struct rte_udp_hdr *udph; + struct rte_udp_hdr _udp; + uint16_t src_port, dst_port, len; + + udph = dissect_read(mb, offset, sizeof(_udp), &_udp, dump_len); + if (udph == NULL) + return; + offset += sizeof(_udp); + + src_port = rte_be_to_cpu_16(udph->src_port); + dst_port = rte_be_to_cpu_16(udph->dst_port); + len = rte_be_to_cpu_16(udph->dgram_len); + + switch (dst_port) { + case RTE_VXLAN_DEFAULT_PORT: + dissect_vxlan(buf, size, mb, offset, dump_len); + break; + default: + if (!dissect_print(&buf, &size, "UDP %u %u → %u ", len, src_port, dst_port)) + return; + } +} + +static void +dissect_tcp(char *buf, size_t size, const struct rte_mbuf *mb, uint32_t offset, uint32_t dump_len) +{ + const struct rte_tcp_hdr *tcph; + struct rte_tcp_hdr _tcp; + uint16_t src_port, dst_port; + + tcph = dissect_read(mb, offset, sizeof(_tcp), &_tcp, dump_len); + if (tcph == NULL) + return; + offset += sizeof(_tcp); + + src_port = rte_be_to_cpu_16(tcph->src_port); + dst_port = rte_be_to_cpu_16(tcph->dst_port); + + if (!dissect_print(&buf, &size, "TCP %u → %u", src_port, dst_port)) + return; + +#define PRINT_TCP_FLAG(flag) { \ + if (tcph->tcp_flags & RTE_TCP_ ## flag ## _FLAG) \ + if (!dissect_print(&buf, &size, " [ " #flag " ]")) \ + return; \ + } + + PRINT_TCP_FLAG(URG); + PRINT_TCP_FLAG(ACK); + PRINT_TCP_FLAG(RST); + PRINT_TCP_FLAG(SYN); + PRINT_TCP_FLAG(FIN); +#undef PRINT_TCP_FLAG + + dissect_print(&buf, &size, "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(char *buf, size_t size, const struct rte_mbuf *mb, uint32_t offset, uint32_t dump_len) +{ + const struct rte_icmp_hdr *icmp; + struct rte_icmp_hdr _icmp; + static const char * const icmp_types[256] = { + [RTE_IP_ICMP_ECHO_REPLY] = "ICMP Echo Reply", + [RTE_IP_ICMP_DEST_UNREACH] = "ICMP Destination Unreachable", + [RTE_IP_ICMP_SOURCE_QUENCH] = "ICMP Source Quench", + [RTE_IP_ICMP_REDIRECT] = "ICMP Redirect", + [RTE_IP_ICMP_ECHO_REQUEST] = "ICMP Echo Request", + [RTE_IP_ICMP_TIME_EXCEEDED] = "ICMP Time Exceeded", + [RTE_IP_ICMP_PARAMETERPROB] = "ICMP Parameter Problem", + [RTE_IP_ICMP_TIMESTAMP] = "ICMP Timestamp Request", + [RTE_IP_ICMP_TIMESTAMPREPLY] = "ICMP Timestamp Reply", + [RTE_IP_ICMP_INFO_REQUEST] = "ICMP Info Request", + [RTE_IP_ICMP_INFO_REPLY] = "ICMP Info Reply", + + [RTE_ICMP6_ECHO_REPLY] = "ICMPv6 Echo Reply", + [RTE_ICMP6_ECHO_REQUEST] = "ICMPv6 Echo Request", + [RTE_ND_ROUTER_SOLICIT] = "ICMPv6 Router Solicitation", + [RTE_ND_ROUTER_ADVERT] = "ICMPv6 Router Advertisement", + [RTE_ND_NEIGHBOR_SOLICIT] = "ICMPv6 Neighbor Solicitation", + [RTE_ND_NEIGHBOR_ADVERT] = "ICMPv6 Neighbor Advertisement", + }; + + icmp = dissect_read(mb, offset, sizeof(_icmp), &_icmp, dump_len); + if (icmp == NULL) + return; + offset += sizeof(_icmp); + + const char *name = icmp_types[icmp->icmp_type]; + if (name != NULL) + dissect_print(&buf, &size, "%s ", name); + else + dissect_print(&buf, &size, "ICMP %u ", icmp->icmp_type); +} + +static void +dissect_ipv4(char *buf, size_t size, const struct rte_mbuf *mb, + uint32_t offset, uint32_t dump_len) +{ + const struct rte_ipv4_hdr *ip_hdr; + struct rte_ipv4_hdr _ip_hdr; + char sbuf[INET_ADDRSTRLEN], dbuf[INET_ADDRSTRLEN]; + + ip_hdr = dissect_read(mb, offset, sizeof(_ip_hdr), &_ip_hdr, dump_len); + if (ip_hdr == NULL) + return; + + inet_ntop(AF_INET, &ip_hdr->src_addr, sbuf, sizeof(sbuf)); + inet_ntop(AF_INET, &ip_hdr->dst_addr, dbuf, sizeof(dbuf)); + if (!dissect_print(&buf, &size, "%s → %s ", sbuf, dbuf)) + return; + + offset += ip_hdr->ihl * 4; + switch (ip_hdr->next_proto_id) { + case IPPROTO_UDP: + return dissect_udp(buf, size, mb, offset, dump_len); + case IPPROTO_TCP: + return dissect_tcp(buf, size, mb, offset, dump_len); + case IPPROTO_ICMP: + return dissect_icmp(buf, size, mb, offset, dump_len); + default: + /* TODO dissect tunnels */ + dissect_print(&buf, &size, "IP %#x ", ip_hdr->next_proto_id); + } +} + +static void +dissect_ipv6(char *buf, size_t size, const struct rte_mbuf *mb, + uint32_t offset, uint32_t dump_len) +{ + 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(mb, offset, sizeof(_ip6_hdr), &_ip6_hdr, dump_len); + if (ip6_hdr == NULL) + return; + + 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)); + if (!dissect_print(&buf, &size, "%s → %s ", sbuf, dbuf)) + return; + +#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(buf, size, mb, offset, dump_len); + case IPPROTO_TCP: + return dissect_tcp(buf, size, mb, offset, dump_len); + case IPPROTO_ICMPV6: + return dissect_icmp(buf, size, mb, offset, dump_len); + + 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(mb, offset, sizeof(xh), &_xh, dump_len); + if (xh == NULL) + return; + + offset += (xh->hdr_len + 1) * 8; + proto = xh->next_hdr; + continue; + } + + case IPPROTO_FRAGMENT: + dissect_print(&buf, &size, "%s", "FRAG "); + return; + + case IPPROTO_NONE: + dissect_print(&buf, &size, "%s", "NONE "); + return; + + default: + dissect_print(&buf, &size, "IPv6 %#x ", proto); + return; + } + } +} + +/* + * Format up a string describing contents of packet in tshark like style. + */ +static void +dissect_eth(char *buf, size_t size, const struct rte_mbuf *mb, + uint32_t offset, uint32_t dump_len) +{ + 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(mb, offset, sizeof(_eth_hdr), &_eth_hdr, dump_len); + if (unlikely(eth_hdr == NULL)) + return; + + 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; + offset += sizeof(*vh); + + const char *vs = (eth_type == RTE_ETHER_TYPE_VLAN) ? "VLAN" : "QINQ"; + uint16_t tci = rte_be_to_cpu_16(vh->vlan_tci); + + if (!dissect_print(&buf, &size, "%s %#x ", vs, tci)) + return; + } + + switch (eth_type) { + case RTE_ETHER_TYPE_ARP: + rte_ether_format_addr(sbuf, sizeof(sbuf), ð_hdr->src_addr); + rte_ether_format_addr(dbuf, sizeof(dbuf), ð_hdr->dst_addr); + if (!dissect_print(&buf, &size, "%s → %s ARP ", sbuf, dbuf)) + return; + + dissect_arp(buf, size, mb, offset, dump_len); + break; + + case RTE_ETHER_TYPE_IPV4: + dissect_ipv4(buf, size, mb, offset, dump_len); + break; + + case RTE_ETHER_TYPE_IPV6: + dissect_ipv6(buf, size, mb, offset, dump_len); + break; + + default: + dissect_print(&buf, &size, "ETH %#x ", eth_type); + } +} + +void +rte_dissect_mbuf(char *buf, size_t size, const struct rte_mbuf *m, uint32_t dump_len) +{ + dissect_eth(buf, size, m, 0, dump_len); + + /* trim off trailing spaces */ + char *cp; + while ((cp = strrchr(buf, ' ')) != NULL) { + if (cp[1] != '\0') + break; + *cp = '\0'; + } +} diff --git a/lib/net/rte_dissect.h b/lib/net/rte_dissect.h new file mode 100644 index 0000000000..26af265029 --- /dev/null +++ b/lib/net/rte_dissect.h @@ -0,0 +1,42 @@ +/* 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; + +/** + * + * Format description of packet to a string buffer + * + * @param buf + * A pointer to buffer for the resulting line. + * @param size + * The format buffer size. + * @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(char *buf, size_t size, 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 Thu Aug 1 19:04:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142856 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 398DC45716; Thu, 1 Aug 2024 21:06:46 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9840840ED9; Thu, 1 Aug 2024 21:06:32 +0200 (CEST) Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) by mails.dpdk.org (Postfix) with ESMTP id 5D56540E41 for ; Thu, 1 Aug 2024 21:06:30 +0200 (CEST) Received: by mail-pf1-f177.google.com with SMTP id d2e1a72fcca58-7106cf5771bso446270b3a.2 for ; Thu, 01 Aug 2024 12:06:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722539189; x=1723143989; 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=iFpt4EEj2m4AprPHT2Fs1F2/T3+OAl5IK3KUHY5OpjU=; b=2itrVZoQRvUTCtDWyhM93hNZDJN74ilzJZbmcLvzYeAgocIV5OB0yUc2Z0pSLuWDoy rBS6E5phYE2OXLEQonz44Cy1dsfpoekPiGTvE11pVeoHhlr60iYDME5rgoNE96v0V8m9 5JOGLfWVEoue4M4lrzcjOZ3AjZ9w0PyNNH+D1GshE8EaLQJYjuJCVywMcAZjHfAuEQ93 l+/ThfD+g7tyvmDjGCzCh6Sxv96AEf7jk9+bsA1x74uxR3zkGxuxkJ/yombAHDZ8JFdc j7Xhzjc41Y/lOJ9OAtzpYg1VIZgCUeF4nhTzleV+StEGwejr2OfGSGNyC+mUOiIFyroV cFRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722539189; x=1723143989; 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=iFpt4EEj2m4AprPHT2Fs1F2/T3+OAl5IK3KUHY5OpjU=; b=MImZI09loJh5l8ApStRH9fMQhozo45EIo3FseC5T+ZkuupVhIDNCD6rh0wPGhcfWWy qskcUPF37SKEPJjiDeCQ8BpG1wYmyM91ntkDiRQKxTRF1vjUXWWiOCbHg0tuBIH4Klv2 GI8EDsRlUWkMflCMAn+Sy+lFXAIgjMPZGHw/pC8ktnbBapFnkEqMkdTAKKLMEPng7ySP WrPqitrOLhI2UhtBh7ot82qdzW/Mt0iP8fVSX8+ryd/++cHWfLcnApuNBflsj0upB9QY vJXyM9niYexJfjxxSkS9Lr504p9hc/HnwzHIzTal3pAH6wTWvDZx2p0QyZILdEjTSLXC fJJg== X-Gm-Message-State: AOJu0YxkmjXAPAJSJfPPAL3rYM43SrycUG3/lBZIu97UERVR+OKCYHfA oI3XHMsKLXL1JnlmcZdlHt034eUd5dmjY8eNpEOMyae32qb2ZGWDod4h/BanbYOpUUYXO2bM6tU N X-Google-Smtp-Source: AGHT+IHnKChfCTT1k8O31OYexXpQt8poYDLA9XCGnc0inUeIAsuLf+LraCpGYVbzefkkf2eMDyHFKQ== X-Received: by 2002:a17:902:d48d:b0:1fd:64ef:da17 with SMTP id d9443c01a7336-1ff573b4dbfmr14507885ad.41.1722539189209; Thu, 01 Aug 2024 12:06:29 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f5a222sm2371955ad.112.2024.08.01.12.06.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Aug 2024 12:06:28 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v5 3/4] test: add test for packet dissector Date: Thu, 1 Aug 2024 12:04:42 -0700 Message-ID: <20240801190617.201574-4-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240801190617.201574-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240801190617.201574-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 | 245 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 246 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..2c79acf766 --- /dev/null +++ b/app/test/test_dissect.c @@ -0,0 +1,245 @@ +/* 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" + +#ifndef LINE_MAX +#define LINE_MAX 2048 +#endif + +#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 +test_simple(void) +{ + struct rte_mbuf mb; + uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE]; + uint32_t data_len = PACKET_LEN; + uint16_t src_port = rte_rand(); + const uint16_t dst_port = rte_cpu_to_be_16(9); /* Discard port */ + char obuf[LINE_MAX]; + + /* 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); + + rte_dissect_mbuf(obuf, sizeof(obuf), &mb, 0); + + 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); + char obuf[LINE_MAX]; + + /* make a really nested 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); + + /* dissect it but snip off some amount of data */ + for (unsigned int i = 0; i < TOTAL_PACKETS; i++) { + uint32_t snaplen = rte_rand_max(pkt_len); + + rte_dissect_mbuf(obuf, sizeof(obuf), &mb, snaplen); + } + + 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()); + char obuf[LINE_MAX]; + + /* 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); + + /* randomly flip bits in it */ + 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(obuf, sizeof(obuf), &mb, 0); + *bp ^= mask; + } + + 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 Thu Aug 1 19:04:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142857 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 B024145716; Thu, 1 Aug 2024 21:06:51 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id C9D8B410D5; Thu, 1 Aug 2024 21:06:33 +0200 (CEST) Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) by mails.dpdk.org (Postfix) with ESMTP id 0E44F40E49 for ; Thu, 1 Aug 2024 21:06:31 +0200 (CEST) Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-1ff4fa918afso8293475ad.1 for ; Thu, 01 Aug 2024 12:06:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722539190; x=1723143990; 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=J1R1odZ0oHOJF5vgnVEzIvFRm7WKvcbCRzqOKQsMEMY=; b=WzPoSGxJSkfobL/QESVY9fFl8E4NHA+P013+6wYUB+BGSb4BuAAFyICaCO4mewbs/F DtyI+v7JLmFpLL+01KyeehVQUBL/dwZG6U+YB+8iC7PLAu7ArO9zkS7NF09PLnR0/wH5 9zQDED778WN/pGlSpRreVPiTlGjDycisKAkisVMPcGguO9Wk7IMObQHUermgbB3ZC083 /onINgfNhGOs1J1lxTUNzjkvzil26DuKrT/oasOdoLxXCQGwzvuKKpf+d+4x/sj5SGwX Jbs5pRgkse4xWgrtLWN+eaoucBMEvYprO8t8yUFkPklMJSMgsQIJmE8XfEn+PUgVF3+t hWGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722539190; x=1723143990; 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=J1R1odZ0oHOJF5vgnVEzIvFRm7WKvcbCRzqOKQsMEMY=; b=Uo3Yo9vnkMszlzxodnS/e0bKvF+SFxrQUylt/Ayu6kB9pB7z4GybRmzDP6ybFXYPdM /WFO+jA4cjb/k5xMCbkEl/s3DhENgUzFF81xolYT+ciPBt+GJy1f7h0wsytuQddyk0B/ HvFKi37zTVUqy8spUjAjEckKZOkJBCuej0SKZXzA8L7p2i47+tvX8Qr9kWBPtkCvTnZn +WmJEpHJmDY5q40Rmf6RNWbR7jrjXBLR2cqVrqdvQAnU+0YrSawax9X5T8E/b8ehw5Hs jV7rhKF0k22UUsYJFPhnzD3TIjiG7Vbi02x5ya6u6yMAsidOpqRxF/BFpI3k4b1OpjyP CXBA== X-Gm-Message-State: AOJu0YyfCC/OAOMJXky4YmTEEMIVPULk4pZo7dX+i0zraIra71SBSP11 hwLjeh8x9k0e1iLyNbsyLzUa7+yUIWzTq4y1N/SwQ2WZBHLOy3wmkI3XvQNJSsJNXjKxZmpUudc O X-Google-Smtp-Source: AGHT+IENF2Q/xPJ2/YMbm8GjCJUDFVa3YgZsoVEzDWX9M9RxGKhosgK7ubZmyE3WLcBrb1YGOqrtJg== X-Received: by 2002:a17:903:41d2:b0:1fb:973f:87f with SMTP id d9443c01a7336-1ff573c01cfmr14164335ad.45.1722539190088; Thu, 01 Aug 2024 12:06:30 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f5a222sm2371955ad.112.2024.08.01.12.06.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Aug 2024 12:06:29 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Ori Kam , Aman Singh Subject: [PATCH v5 4/4] test-pmd: add more packet verbose decode options Date: Thu, 1 Aug 2024 12:04:43 -0700 Message-ID: <20240801190617.201574-5-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240801190617.201574-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240801190617.201574-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 | 77 +++++++++++++++++++-- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 5 +- 5 files changed, 111 insertions(+), 18 deletions(-) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index d04280eb3e..a010fcf61a 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -14143,7 +14143,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 6f0beafa27..b5b5f3b464 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..f277e7f035 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -5,9 +5,11 @@ #include +#include #include #include #include +#include #include #include #include @@ -16,6 +18,7 @@ #include "testpmd.h" #define MAX_STRING_LEN 8192 +#define MAX_DUMP_LEN 1024 #define MKDUMPSTR(buf, buf_size, cur_len, ...) \ do { \ @@ -67,9 +70,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 +94,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 +301,71 @@ 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 port, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, int is_rx) +{ + static uint64_t start_cycles; + static RTE_ATOMIC(uint64_t) packet_count = 1; + uint64_t now; + uint64_t count; + double interval; + uint16_t i; + + now = rte_rdtsc(); + if (start_cycles == 0) { + start_cycles = now; + printf("Seq# Time Port:Que R Description\n"); + } + + interval = (double)(now - start_cycles) / (double)rte_get_tsc_hz(); + + count = rte_atomic_fetch_add_explicit(&packet_count, nb_pkts, rte_memory_order_relaxed); + + for (i = 0; i < nb_pkts; i++) { + const struct rte_mbuf *mb = pkts[i]; + char str[256]; + + rte_dissect_mbuf(str, sizeof(str), mb, 0); + printf("%6"PRIu64" %11.9f %4u:%-3u %c %s\n", + count + i, interval, port, queue, is_rx ? 'R' : 'T', str); + } +} + +/* 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(port_id, queue, pkts, nb_pkts, is_rx); + 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 f00ab07605..b9ce7698db 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -677,7 +677,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 ~~~~~~~