From patchwork Fri Aug 2 18:07:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142875 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 C5BB74571E; Fri, 2 Aug 2024 20:08:56 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id F2A7F427A7; Fri, 2 Aug 2024 20:08:52 +0200 (CEST) Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) by mails.dpdk.org (Postfix) with ESMTP id BBFE340E22 for ; Fri, 2 Aug 2024 20:08:50 +0200 (CEST) Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-1fda7fa60a9so77136965ad.3 for ; Fri, 02 Aug 2024 11:08:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722622130; x=1723226930; 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=qiHL/s2m9HRGEp1RcGyUhUv2gaRQz40DlDTYDyk4BuUxkk9PssVq8fvNqqry1riMou EhlzcqI7N/odIKJq+FcWcOvb+/AWErKvlKsIYxa9yN+nnPovJ5pf/sYbAmyOh6iSgpXA HX2YByxFh7TNMEUwq4zQj12mfoBUi4jljaK4NejwdLfUEOsvTSItvBfPxyOqqslu40AG BsxFcAKIllvGhw6dDFexyA1vbibXJ1K4njvphq3+BNcV3Et9cYlfFiCzYN9wDw6bONI3 ifZ1Vv/2lVwKMhOXad3e0zeQeSBjEGKDDmRJ0xzREtnFFpU2h+WSAvwMPi0yoyQ+cP5b l5pA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722622130; x=1723226930; 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=UfG6YuFRAp+hLP1KLWZU5Y+s32by/bBHYpMSrILHd+pqVkhKyvrhoUtg9NZxo1ENin ms9XQjZ0LxTnp3eUBwop/ebG/Cpf3eEdizEMo2MwS66tTOYmWKiubFIz6QXlta5PZbNB CoOQ2YyZUabc1QO1UoxUyyhDo1sTGyZnwK9lA9rijn8Yus0ydyle7vGWHM7S7KyYdkzh tI0HP7szrUPiLHc+34Hkc7hVrMuJ++A4GbF7nRJCkC1E0eEDWTC1qB0rJCZa145iYeyn n+ty3TN+XLzfFeKxHDJDkSlfGVp36fwVimpnX5/XxI8LJ1/e4GdNpReS65sPUSj1zSCu iq0Q== X-Gm-Message-State: AOJu0YwH70pHAr8B9kTk09nsvDIR0CMD9A7ylJIcg0BxBwm9pcHEfdo0 FPMoEj+sXMABYV90NfiET+lnwUnOCb58ds3MTm5fihB9Olwcy+91RO8gq7GMyEPscqIFLbTbmYd z X-Google-Smtp-Source: AGHT+IGrhJXhvsQYpx7SOBlALnKx6HP2+iKs2/LAx56+qk0w4Lfn0e+E+b9qGIpmrCD/woXfktqSJg== X-Received: by 2002:a17:902:e5c4:b0:1fb:451a:449b with SMTP id d9443c01a7336-1ff5749b5c9mr53928725ad.60.1722622129849; Fri, 02 Aug 2024 11:08:49 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f6a540sm20228195ad.118.2024.08.02.11.08.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Aug 2024 11:08:49 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v6 1/4] net: add more icmp types Date: Fri, 2 Aug 2024 11:07:44 -0700 Message-ID: <20240802180838.862858-2-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240802180838.862858-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240802180838.862858-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 Fri Aug 2 18:07:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142876 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 A0DC44571E; Fri, 2 Aug 2024 20:09:02 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 256BE427AE; Fri, 2 Aug 2024 20:08:54 +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 AC7A840E22 for ; Fri, 2 Aug 2024 20:08:51 +0200 (CEST) Received: by mail-pg1-f170.google.com with SMTP id 41be03b00d2f7-6e7e23b42c3so5400011a12.1 for ; Fri, 02 Aug 2024 11:08:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722622131; x=1723226931; 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=T3aQsUdW0QXMwtEzMoYBOSNwFEDUAB33V0iYRhrGOp9Kkob7HgU8sB6G8wW6lj7ik6 8RI5IEQLL2b+SZ0dVCyIyv7N1cDC2aIIhIkAor6qW+QErx/rUDL7/t1gRj8rwdAynRKZ dDeyMC++4N09lU+lvMTo6+gUtDTDOAhH7u0GuO91IA0rWfgn+Tm/y9hR4hWcsFbPurQ9 GvsjuYV7s6X8rw3JaIRZbN00xrBZGkKyd1htbbLuOHI8zP8a3r+hQ3ZQx54OfVH4fIkx 8q4dhD9ivwIeEfXMtof6olsbm11YJG72bl4LGntGcmg44NEvSbr0n6CJvVJ4ypTUQw2d lk1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722622131; x=1723226931; 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=UyelO5CtOlcLS+ZeuxxhAXtQkdFq9/4fYgy2ZqEx1b9gVx18uz+FBw0oxIHeYgir8v MMVIiKFQbKIPheqbtD8g96N7MCRly5e4HrS+S7ab08aRkrtmMCUR3N24SrqvJsE1/L5A FvpavUlUSZH/11FyWFlbGyPsEmnDkkkO3jhqfldZfodYeFnddzOHMglucUuClUvFqRco iw68swtrTM6euNjzykvrOjkWFiAmv7Be6eh8Nb0hqbbkLNr+Q4DY/wfB0FQu46TPgHyy 2Sk94LQm10j+eBlmgvN0ch40+wdFAOHNKT7BusD79RTSfa34ZvkYqWrXSfABd8OOU68H mKLg== X-Gm-Message-State: AOJu0YyJTGrK1OQbAwmAcGzpCpMZWGp40dq28C9zTA9wxWu1rywOWRV9 QDFfehg4iXEJhrZfo4n6WyewlLsX9eMHo+yjenusWBUYaQj0lBexkteDItuVXp5F8/YiOajiC7J w X-Google-Smtp-Source: AGHT+IG5oKThV/EjxKS2ho7CjSVzPEhpqXbjqEwOBuggR6Azt2qJYJZrSf3jBtohFgmD67jwzrKfvg== X-Received: by 2002:a05:6a20:3942:b0:1c3:ea28:3c0e with SMTP id adf61e73a8af0-1c69960e196mr5984694637.33.1722622130591; Fri, 02 Aug 2024 11:08:50 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f6a540sm20228195ad.118.2024.08.02.11.08.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Aug 2024 11:08:50 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v6 2/4] net: add new packet dissector Date: Fri, 2 Aug 2024 11:07:45 -0700 Message-ID: <20240802180838.862858-3-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240802180838.862858-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240802180838.862858-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 Fri Aug 2 18:07:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142877 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 BC04A4571E; Fri, 2 Aug 2024 20:09:08 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 73635427B3; Fri, 2 Aug 2024 20:08:55 +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 4A78240E22 for ; Fri, 2 Aug 2024 20:08:52 +0200 (CEST) Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-1fd66cddd07so64333315ad.2 for ; Fri, 02 Aug 2024 11:08:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722622131; x=1723226931; 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=10WcOI9p0YQXzoVk2+AWc4nor9btJTFo0u4lkzJGaL4=; b=eeMIxfbtD2249sb2+x6h1DeYqnYaxtgBcAeH0Owg5s4owyzzgAMeBmuBmM83AUObaW S8Dt0ccsXrx221iKjz9qUDtgMrmHufxHx4R5o9imDSHqvtH6GaI16HZLJ53CEaWXQ1/y ohvx9nA9Qec3TRLe3sY/9aFzI5zLl1dM3YAsYbhOG/IN0ef95Oa0FriCBpej23DRLcFl ZaxT79VI/WIDkJWD/yzU6TuklwVo4tydwZxvYYy0ojVXpxCZmzE54N56YBOcVNMDw8Pr 2IVsqP65S4hPVIb5Rcpo/RTA1R4R3+YTZdj8jdV4w+BW9axyDfDgYklUNVT8kE+ZWq8W a46g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722622131; x=1723226931; 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=10WcOI9p0YQXzoVk2+AWc4nor9btJTFo0u4lkzJGaL4=; b=VayHdV/AU4hp0owcNPbaAPdlCxr3EDc2fdEEpOu6fwPC/oBsq2rBnZ/DgcTd/RghQ6 1vZCkFSf33LQivrIxIybyMlxqszaYWWFdMgNKRDzDz6DMjlHsUIKBGqQOWpVetCnZbJ/ j3gCLax+i9YIwrYCqWmDnzMdXo68UTW648vZDC1mlQfjvJGFqGeD1rB/ktUWohzKZd3R HIOsxcBHT78ySOHeQZymtpsXiOwqE247k1ikQ6jLy65r5ZRazzaYqtKAI67kq5cEaazP 3ozGbVSzpqxOlNjPpSXlBlRhIgS2NScM8pn2JRPEluLWdsX3M9TyN7zNx2j+cofcDV2E 22vA== X-Gm-Message-State: AOJu0YyhU+EQHykgXDa+N7uRNtOCCO0GSNCl6/OfBBiSlpjQjt+5xuB+ +6F7VI6qyVLR4iA+E2NUK88WZwApklDp6u0pnySrbNHW2PbNQwz8ojL6oRnU3kY+wrlIReFrPS4 f X-Google-Smtp-Source: AGHT+IHB9YMjiDaI4W3xQP6xPb4gzrrp3JHizJyCZ6h4wkpIxK/astdocOp4qceAwDoU+GdU/0ye7Q== X-Received: by 2002:a17:903:120c:b0:1fb:37fa:fedb with SMTP id d9443c01a7336-1ff5723bc3amr61000115ad.10.1722622131342; Fri, 02 Aug 2024 11:08:51 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f6a540sm20228195ad.118.2024.08.02.11.08.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Aug 2024 11:08:51 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v6 3/4] test: add test for packet dissector Date: Fri, 2 Aug 2024 11:07:46 -0700 Message-ID: <20240802180838.862858-4-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240802180838.862858-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240802180838.862858-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 some tests for new packet dissector. Signed-off-by: Stephen Hemminger --- app/test/meson.build | 1 + app/test/test_dissect.c | 253 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 254 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..0644d644d5 --- /dev/null +++ b/app/test/test_dissect.c @@ -0,0 +1,253 @@ +/* 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 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + .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.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; + rte_be16_t src_port = rte_rand_max(UINT16_MAX); + const rte_be16_t dst_port = rte_cpu_to_be_16(9); /* Discard port */ + char obuf[LINE_MAX] = { }; + char result[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); + + /* construct the expected result */ + int len = snprintf(result, sizeof(result), + "127.0.0.1 → 224.0.0.0 UDP 966 %u → 9", + rte_be_to_cpu_16(src_port)); + + rte_dissect_mbuf(obuf, sizeof(obuf), &mb, 0); + TEST_ASSERT_BUFFERS_ARE_EQUAL(obuf, result, len, + "Dissect string differs:\nexpect \"%s\"\n got \"%s\"", + result, obuf); + + 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; + rte_be16_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 { + rte_be16_t src_port = rte_rand_max(UINT16_MAX); + 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 rte_be16_t dst_port = rte_cpu_to_be_16(rte_rand_max(1024)); + const rte_be16_t src_port = rte_rand_max(UINT16_MAX); + 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 Fri Aug 2 18:07:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 142878 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 BD79B4571E; Fri, 2 Aug 2024 20:09:16 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4B977427D0; Fri, 2 Aug 2024 20:08:57 +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 19FF8427AC for ; Fri, 2 Aug 2024 20:08:53 +0200 (CEST) Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-1ff1cd07f56so63453895ad.2 for ; Fri, 02 Aug 2024 11:08:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1722622132; x=1723226932; 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=O4b9dy0uFQiSGz3LZpxWrb9tSUXB5spdDkJ2zyAqhEueDuUGOZjqSCUSN6IL4ittsJ eacrgQnHNuFtkUM2Bk8W3BNfqpa7RcvtZASBA9d1hEovRhsQZKJJ5qAkrtrYT9FKjGBJ G1+8Hqj5uBSQXoZs2E+wO/m9wNX7/7ABNo9P1+NaoRVJYipT0k9nf8O2CxS4jCiH6VOv uIe0K63vcMcIchMI4I6hOaZm/2BC4YqYFb9HVaqP3l/IxjyH54nt9fOllYIi4gg1VS93 GhMGPMAppXLxCDX75tF4siY6QOEJYOQz9lGSpvA75Jkhr+bVA35VKLglVjvc99gWmknP dcZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722622132; x=1723226932; 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=XUcm/NsSice3Ue/C3voQ4wevs6Eg1ziZS7YKQ536f5qr9QsmpVZhJ6IBZ9hVxsTM9G QDPEtRDHLezwrqUiNnPyQOKAwGcRjwcHvzjAy9ln/ugDbJ3TnjbxWXwuG5Gt21p3QuEW AacJVE7k744/rekjDKsBIWsK7rMKAWpZCZfh7tt0tQo1lUJ0uFMJeblAdNJnl7WXG6lh ykfvwdKPCg1Ms5VTgvC64Gs/wBaAUCVuCp3niVng+X7Sm3isEVHRwkMJ1inkEFeP5bC5 lWrf9rStu8UECw+soUi91/IdJEUSz5LXblPueuyagkvEzlOZGWpLQ9LkjJxO2zyRGXUf ncyQ== X-Gm-Message-State: AOJu0YwBfrGRqDEjx2U7r1nkm6ji9PqQfVSJEk/xdxnsBxOcB9vnCmdG B2dg4IYbLd9kYaoPZOU0bNvrnd7nKtIL6bzBU+rCvwd4Lx8+25vPIm60/F6mR62cRWIaQlY2IFx f X-Google-Smtp-Source: AGHT+IFET5MN+f0NbSPIJOqUZVRNTudjEmAgHoOKmhyrNKAa8EXGvnFm8ej8sT0ncIjeXAN1pxyioQ== X-Received: by 2002:a17:903:2310:b0:1fb:62e8:ae98 with SMTP id d9443c01a7336-1ff5722da23mr58549345ad.3.1722622132185; Fri, 02 Aug 2024 11:08:52 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1ff58f6a540sm20228195ad.118.2024.08.02.11.08.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Aug 2024 11:08:51 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Ori Kam , Aman Singh Subject: [PATCH v6 4/4] test-pmd: add more packet verbose decode options Date: Fri, 2 Aug 2024 11:07:47 -0700 Message-ID: <20240802180838.862858-5-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240802180838.862858-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20240802180838.862858-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 ~~~~~~~