From patchwork Mon Oct 28 02:19:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147453 X-Patchwork-Delegate: thomas@monjalon.net 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 5C8C645BE5; Mon, 28 Oct 2024 03:21:48 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 214794065E; Mon, 28 Oct 2024 03:21:45 +0100 (CET) Received: from mail-pl1-f169.google.com (mail-pl1-f169.google.com [209.85.214.169]) by mails.dpdk.org (Postfix) with ESMTP id 71DBB402A3 for ; Mon, 28 Oct 2024 03:21:42 +0100 (CET) Received: by mail-pl1-f169.google.com with SMTP id d9443c01a7336-207115e3056so30719645ad.2 for ; Sun, 27 Oct 2024 19:21:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082101; x=1730686901; 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=MEG5s04o67W0W9cj0UdOKiBDXWrcq8BCrKHcNUyGAyI=; b=nUK4S72OqihC0Q8fWNr61o0DiXIeo04IUOMspohQ36c7F4DkM+k+rOk/AIFdpcLS9o V4QCUQyGX8KDPDMQ8lIxb5MtbDwrKzyFmXxyf1x6Yf5O12EynzTJJ1nrveIgxn8+Ze2y FZQqhyHcIgKhyFPpffkwqjHOxNaHBkzYIgIsXduLecIeaFMGrEeZCj1F6QJr3HCuhVyH lmyD3/Yeb2Yqa+NGA3hBc5WHF+VtYs3bF00MlWajrr0po7vjIDZRTV2UUhmB+qtdpuNo sXcqUMRBeHyPqxaqxzj8YWsLrzPxsTNVQqg2gNjWv5VKrcikpCpq/ePTMLSNGKJYBfV2 Jlzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082101; x=1730686901; 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=MEG5s04o67W0W9cj0UdOKiBDXWrcq8BCrKHcNUyGAyI=; b=urvhQppUkBBiw8TxoqSXwMhjv9ngi0NXkKpFyi9HQR6TPMN+OljiXA1XUhZuiDRvb0 Ky7yJhIA0U1J++YeKIvkfg5W7ddrMeizYNotFOFJYknpEnryvDFcsk+oSUOVSr3LEL4c Qqz2GMgaptirOvcawrgLYKc4s4Z4YeT6/cjz/U+3eglb+ERtAVMzteNrf0Dw6y1eyWkU YgTsuKewgUr8uCjqKmqxZlqsGoDcIPwlJ/5nRouJpihcaZfhDqFPnxnZ+bodK/G2Lghp F4xZgHOth5UKKCeLKeqJtpwsF+ynshElhmADLH0OYi0y3eMU4ZLAps1BAfnyUYtRm4H4 qFqw== X-Gm-Message-State: AOJu0Yz4iwyrHF492kdsCmeXETia8uBzzKcAmmZNH5fWC3AtV6qbiBfh JzRZOWRGGr8udUTFTCtjcQVZs7jdnKcNTjCqyOYBisiTg+gRBfu2d12sSA6R7vHiLJ0P73sQ3T1 wIro= X-Google-Smtp-Source: AGHT+IH81WKMWC60kBpJWGdBeK2ZQXNDbpa1zidNollRjO0rCoKCuHs+tUeGkknB9GZOpxwiGEzInQ== X-Received: by 2002:a17:902:ce09:b0:203:a0ea:63c5 with SMTP id d9443c01a7336-210c67231d0mr93989425ad.0.1730082101560; Sun, 27 Oct 2024 19:21:41 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:41 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v10 1/8] net: add more icmp types Date: Sun, 27 Oct 2024 19:19:27 -0700 Message-ID: <20241028022131.142609-2-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 types for SOURCE_QUENCH and IPv6 neighbor discovery. Signed-off-by: Stephen Hemminger --- lib/net/rte_icmp.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/net/rte_icmp.h b/lib/net/rte_icmp.h index e69d68ab6e..1ca6cf35cb 100644 --- a/lib/net/rte_icmp.h +++ b/lib/net/rte_icmp.h @@ -54,6 +54,7 @@ struct rte_icmp_hdr { #define RTE_IP_ICMP_ECHO_REPLY \ (RTE_DEPRECATED(RTE_IP_ICMP_ECHO_REPLY) RTE_ICMP_TYPE_ECHO_REPLY) #define RTE_ICMP_TYPE_DEST_UNREACHABLE 3 +#define RTE_ICMP_TYPE_SOURCE_QUENCH 4 #define RTE_ICMP_TYPE_REDIRECT 5 #define RTE_ICMP_TYPE_ECHO_REQUEST 8 #define RTE_IP_ICMP_ECHO_REQUEST \ @@ -62,6 +63,8 @@ struct rte_icmp_hdr { #define RTE_ICMP_TYPE_PARAM_PROBLEM 12 #define RTE_ICMP_TYPE_TIMESTAMP_REQUEST 13 #define RTE_ICMP_TYPE_TIMESTAMP_REPLY 14 +#define RTE_ICMP_TYPE_INFO_REQUEST 15 +#define RTE_ICMP_TYPE_INFO_REPLY 16 /* Destination Unreachable codes */ #define RTE_ICMP_CODE_UNREACH_NET 0 @@ -84,4 +87,10 @@ struct rte_icmp_hdr { #define RTE_ICMP6_ECHO_REQUEST 128 #define RTE_ICMP6_ECHO_REPLY 129 +/* Neighbor discovery */ +#define RTE_ND_ROUTER_SOLICIT 133 +#define RTE_ND_ROUTER_ADVERT 134 +#define RTE_ND_NEIGHBOR_SOLICIT 135 +#define RTE_ND_NEIGHBOR_ADVERT 136 + #endif /* RTE_ICMP_H_ */ From patchwork Mon Oct 28 02:19:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147454 X-Patchwork-Delegate: thomas@monjalon.net 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 A09CF45BE5; Mon, 28 Oct 2024 03:21:54 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 163AD4067A; Mon, 28 Oct 2024 03:21:50 +0100 (CET) Received: from mail-pg1-f169.google.com (mail-pg1-f169.google.com [209.85.215.169]) by mails.dpdk.org (Postfix) with ESMTP id 5D7A2402A3 for ; Mon, 28 Oct 2024 03:21:43 +0100 (CET) Received: by mail-pg1-f169.google.com with SMTP id 41be03b00d2f7-7ea7e2ff5ceso2559072a12.2 for ; Sun, 27 Oct 2024 19:21:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082102; x=1730686902; 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=HwA35hjyZK2tKp1HMDLebbip7XEcncSGyz7UjVuS6GY=; b=2m9HbYW7oaLt+lW02Jo6m38D3cVUynUsZMI2ulwIALFuIveiCLqd9f7lPAXJEqtdZC zIM7q/d5vNZdieHm0X7s4Wh1uNe1yHvHyscXmtHSBlz9D+T41zDSyQnv+vsWvUIJvZUh CwyZqtFIFIlOemJer9Tt+abg0iJxGvlcdlnlVYaEvo91qD+ByFbG/P5MCcEfT901Z8X1 i9AT3tkngNnIoPZa887AffprCpw8TuiNOxDxKn5PP0lDdab7WXNXHtSyf6albxllC0EV FuP2eiOBbwJLkFiUqlK8YiwmjdH9j8DvVNy5Q+2kFd0T0NCM9Pj8XGaXxAZYZ4rTS+C6 dx7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082102; x=1730686902; 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=HwA35hjyZK2tKp1HMDLebbip7XEcncSGyz7UjVuS6GY=; b=DlgwEyXI/GiBjGlAf0k6fJGJsjaDSpJ2C15IWQ6BrhwXEtH8doRAyJmvA8Kff+L3Qp tltp9qYdHIawWwiOmWUx+dPpRsFqLNRgeHAu66HzbNGNkNZshkPmp6KqO66F84pAKoIN y2wYhAJxvO2jbu/eO4BTe0YUGGsjnM4dAez1H7EwW8b1VmumPCIc0ZY6hYaXcvdEHyRc PQbVYVc8gqUktRXM5vrYmH2whNKyA9m1vTPLUiZcbdwsiaOOQw7LlGAw4iQqWGM2hElG 7kvKtXMXWr78N1fYYUovs7dJu4TLxII+J9tGdIjvMWNiUTmp9McNGa2j+4COciY7IsBC hG9A== X-Gm-Message-State: AOJu0YwzgCHSXDiq+0c3Eb14YLPvgnMX8ksKnRYjX9VSW5iXrnv9+V3h d0QA66SlLHevVF9UdRFdYgfJBeWInBJsDusiE3aZcR8PgT6NsbjZuC0wHu8lDtjMTKwqCXqdnAO SriQ= X-Google-Smtp-Source: AGHT+IF5yzXJzV5QSmcw04kgTjr/IrPjZ2z/w6BhDxDh7iPxLAyL3pXDHNETmB/J59GfMBE358A+UA== X-Received: by 2002:a17:902:e54f:b0:20b:7731:e3df with SMTP id d9443c01a7336-210c6c6a143mr115612455ad.43.1730082102426; Sun, 27 Oct 2024 19:21:42 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:42 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v10 2/8] net: add new packet dissector Date: Sun, 27 Oct 2024 19:19:28 -0700 Message-ID: <20241028022131.142609-3-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 | 429 ++++++++++++++++++++++++++++++++++++++++++ lib/net/rte_dissect.h | 45 +++++ lib/net/version.map | 7 + 4 files changed, 483 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 8afcc4ed37..ebeeb561b8 100644 --- a/lib/net/meson.build +++ b/lib/net/meson.build @@ -3,6 +3,7 @@ headers = files( 'rte_cksum.h', + 'rte_dissect.h', 'rte_ip.h', 'rte_ip4.h', 'rte_ip6.h', @@ -33,6 +34,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..80e84b8c70 --- /dev/null +++ b/lib/net/rte_dissect.c @@ -0,0 +1,429 @@ +/* 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 int +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 */ + 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) int +dissect_print(char **buf, size_t *sz, const char *fmt, ...) +{ + va_list ap; + int count; + + va_start(ap, fmt); + count = vsnprintf(*buf, *sz, fmt, ap); + va_end(ap); + + /* error or string is full */ + if (count < 0 || count >= (int)*sz) { + *sz = 0; + } else { + *buf += count; + *sz -= count; + } + return count; +} + +static int +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; + int count = 0; + char abuf[64]; + + arp = dissect_read(mb, offset, sizeof(_arp), &_arp, dump_len); + if (arp == NULL) + return snprintf(buf, size, "Missing ARP header"); + + 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)); + count += dissect_print(&buf, &size, "Who has %s? ", abuf); + + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_sha); + count += dissect_print(&buf, &size, "Tell %s ", abuf); + break; + + case RTE_ARP_OP_REPLY: + inet_ntop(AF_INET, &arp->arp_data.arp_sip, abuf, sizeof(abuf)); + count += dissect_print(&buf, &size, "%s is at", abuf); + + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_sha); + count += dissect_print(&buf, &size, "%s ", abuf); + break; + + case RTE_ARP_OP_INVREQUEST: + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_tha); + count += dissect_print(&buf, &size, "Who is %s? ", abuf); + + rte_ether_format_addr(abuf, sizeof(abuf), &arp->arp_data.arp_sha); + count += dissect_print(&buf, &size, "Tell %s ", abuf); + break; + + case RTE_ARP_OP_INVREPLY: + rte_ether_format_addr(abuf, sizeof(buf), &arp->arp_data.arp_sha); + count += dissect_print(&buf, &size, "%s is at ", abuf); + + inet_ntop(AF_INET, &arp->arp_data.arp_sip, abuf, sizeof(abuf)); + count += dissect_print(&buf, &size, "%s ", abuf); + break; + + default: + count += dissect_print(&buf, &size, "Unknown ARP %#x ", ar_op); + break; + } + + return count; +} + +static int +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; + int count = 0; + + vxlan = dissect_read(mb, offset, sizeof(_vxlan), &_vxlan, dump_len); + if (vxlan == NULL) + return snprintf(buf, size, "Missing VXLAN header"); + + offset += sizeof(_vxlan); + + if (vxlan->flag_i) { + uint32_t vni = rte_be_to_cpu_32(vxlan->vx_vni); + + count += dissect_print(&buf, &size, "%#x ", vni >> 8); + } + + count += dissect_eth(buf, size, mb, offset, dump_len); + return count; +} + +static int +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 snprintf(buf, size, "Missing UDP header"); + + 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: + return dissect_vxlan(buf, size, mb, offset, dump_len); + default: + return dissect_print(&buf, &size, "UDP %u %u → %u ", len, src_port, dst_port); + } +} + +static int +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; + int count; + + tcph = dissect_read(mb, offset, sizeof(_tcp), &_tcp, dump_len); + if (tcph == NULL) + return snprintf(buf, size, "Missing TCP header"); + + offset += sizeof(_tcp); + src_port = rte_be_to_cpu_16(tcph->src_port); + dst_port = rte_be_to_cpu_16(tcph->dst_port); + + count = dissect_print(&buf, &size, "TCP %u → %u", src_port, dst_port); + +#define PRINT_TCP_FLAG(flag) do { \ + if (tcph->tcp_flags & RTE_TCP_ ## flag ## _FLAG) \ + count += dissect_print(&buf, &size, " [ " #flag " ]"); \ + } while (0) + + PRINT_TCP_FLAG(URG); + PRINT_TCP_FLAG(ACK); + PRINT_TCP_FLAG(RST); + PRINT_TCP_FLAG(SYN); + PRINT_TCP_FLAG(FIN); +#undef PRINT_TCP_FLAG + + count += 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)); + return count; +} + +static int +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_ICMP_TYPE_ECHO_REPLY] = "ICMP Echo Reply", + [RTE_ICMP_TYPE_DEST_UNREACHABLE] = "ICMP Destination Unreachable", + [RTE_ICMP_TYPE_SOURCE_QUENCH] = "ICMP Source Quench", + [RTE_ICMP_TYPE_REDIRECT] = "ICMP Redirect", + [RTE_ICMP_TYPE_ECHO_REQUEST] = "ICMP Echo Request", + [RTE_ICMP_TYPE_TTL_EXCEEDED] = "ICMP TTL Exceeded", + [RTE_ICMP_TYPE_PARAM_PROBLEM] = "ICMP Parameter Problem", + [RTE_ICMP_TYPE_TIMESTAMP_REQUEST] = "ICMP Timestamp Request", + [RTE_ICMP_TYPE_TIMESTAMP_REPLY] = "ICMP Timestamp Reply", + [RTE_ICMP_TYPE_INFO_REQUEST] = "ICMP Info Request", + [RTE_ICMP_TYPE_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 snprintf(buf, size, "Missing ICMP header"); + + offset += sizeof(_icmp); + const char *name = icmp_types[icmp->icmp_type]; + if (name != NULL) + return dissect_print(&buf, &size, "%s ", name); + else + return dissect_print(&buf, &size, "ICMP %u ", icmp->icmp_type); +} + +static int +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]; + int count; + + ip_hdr = dissect_read(mb, offset, sizeof(_ip_hdr), &_ip_hdr, dump_len); + if (ip_hdr == NULL) + return snprintf(buf, size, "Missing IP header"); + + inet_ntop(AF_INET, &ip_hdr->src_addr, sbuf, sizeof(sbuf)); + inet_ntop(AF_INET, &ip_hdr->dst_addr, dbuf, sizeof(dbuf)); + count = dissect_print(&buf, &size, "%s → %s ", sbuf, dbuf); + + offset += ip_hdr->ihl * 4; + switch (ip_hdr->next_proto_id) { + case IPPROTO_UDP: + count += dissect_udp(buf, size, mb, offset, dump_len); + break; + case IPPROTO_TCP: + count += dissect_tcp(buf, size, mb, offset, dump_len); + break; + case IPPROTO_ICMP: + count += dissect_icmp(buf, size, mb, offset, dump_len); + break; + default: + /* TODO dissect tunnels */ + count += dissect_print(&buf, &size, "IP %#x ", ip_hdr->next_proto_id); + } + return count; +} + +static int +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; + int count; + + ip6_hdr = dissect_read(mb, offset, sizeof(_ip6_hdr), &_ip6_hdr, dump_len); + if (ip6_hdr == NULL) + return snprintf(buf, size, "Missing IPv6 header"); + + 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)); + count = dissect_print(&buf, &size, "%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: + count += dissect_udp(buf, size, mb, offset, dump_len); + return count; + + case IPPROTO_TCP: + count += dissect_tcp(buf, size, mb, offset, dump_len); + return count; + + case IPPROTO_ICMPV6: + count += dissect_icmp(buf, size, mb, offset, dump_len); + return count; + + 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 count; + + offset += (xh->hdr_len + 1) * 8; + proto = xh->next_hdr; + continue; + } + + case IPPROTO_FRAGMENT: + count += dissect_print(&buf, &size, "%s", "FRAG "); + return count; + + case IPPROTO_NONE: + count += dissect_print(&buf, &size, "%s", "NONE "); + return count; + + default: + count += dissect_print(&buf, &size, "IPv6 %#x ", proto); + return count; + } + } + return count; +} + +/* + * Format up a string describing contents of packet in tshark like style. + */ +static int +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; + int count = 0; + 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 snprintf(buf, size, "Missing ETH header"); + + 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; + struct rte_vlan_hdr _vh; + + vh = dissect_read(mb, offset, sizeof(_vh), &_vh, dump_len); + if (unlikely(vh == NULL)) + return snprintf(buf, size, "Missing VLAN header"); + + eth_type = vh->eth_proto; + offset += sizeof(*vh); + + count += dissect_print(&buf, &size, "%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(dbuf, sizeof(dbuf), ð_hdr->dst_addr); + count += dissect_print(&buf, &size, "%s → %s ARP ", sbuf, dbuf); + count += dissect_arp(buf, size, mb, offset, dump_len); + break; + + case RTE_ETHER_TYPE_IPV4: + count += dissect_ipv4(buf, size, mb, offset, dump_len); + break; + + case RTE_ETHER_TYPE_IPV6: + count += dissect_ipv6(buf, size, mb, offset, dump_len); + break; + + default: + count += dissect_print(&buf, &size, "ETH %#x ", eth_type); + } + + return count; +} + +int +rte_dissect_mbuf(char *buf, size_t size, const struct rte_mbuf *m, uint32_t dump_len) +{ + int count; + + count = dissect_eth(buf, size, m, 0, dump_len); + if (count <= 0) + return count; + + /* output was truncated, but redact the trailing blank */ + if (count >= (int)size) + return count - 1; + + if (buf[count] == ' ') + buf[count--] = '\0'; + + return count; +} diff --git a/lib/net/rte_dissect.h b/lib/net/rte_dissect.h new file mode 100644 index 0000000000..343e9daa4d --- /dev/null +++ b/lib/net/rte_dissect.h @@ -0,0 +1,45 @@ +/* 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. + * @return + * Returns the number of bytes printed (excluding null byte at end of string). + * if output was truncated returns the number of bytes that would have been printed. + */ +__rte_experimental +int +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 bec4ce23ea..9a27339df5 100644 --- a/lib/net/version.map +++ b/lib/net/version.map @@ -12,3 +12,10 @@ DPDK_25 { local: *; }; + +EXPERIMENTAL { + global: + + # added in 24.11 + rte_dissect_mbuf; +}; From patchwork Mon Oct 28 02:19:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147455 X-Patchwork-Delegate: thomas@monjalon.net 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 2ED4245BE5; Mon, 28 Oct 2024 03:22:01 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 49D9D4069F; Mon, 28 Oct 2024 03:21:51 +0100 (CET) Received: from mail-pl1-f173.google.com (mail-pl1-f173.google.com [209.85.214.173]) by mails.dpdk.org (Postfix) with ESMTP id 0C4F540649 for ; Mon, 28 Oct 2024 03:21:44 +0100 (CET) Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-20e6981ca77so40373325ad.2 for ; Sun, 27 Oct 2024 19:21:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082103; x=1730686903; 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=hhWvuVXRgHku1oHh1xOxXvjG58ltiAKxpo7DsbakfzY=; b=Pn4dAcjSxVlQP7PK9ns1BTaDZ5Wmz6LyviuXiM4E8yIkKCKsDfVKB3a326xtKtrbpr wwmVYIJO4kYzEzbfRIlYWAvhfSh7BRpPMvrKE1nRkpcFrM8XD3t27H8A8tGxOXwJ/cOl khdnJ/+dfv3vNFp/dZOwtdIrT+j0komsBAWM2uOx2XS+QgGQdQOjTuE9e0xyrw7Lhsd7 rZ6TU6RstR7C8Ip4A5NNkf44R2BMTo4Olibd8sSCi+qm6tTYjgjpJNLLycZ4YpOZH2RQ XuDS0J69GSHCDTEYQwqdYz5DEwes0kFnR7KtkWGCasYJebzbT/zMZji3JjDJZoo2bi9P hNcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082103; x=1730686903; 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=hhWvuVXRgHku1oHh1xOxXvjG58ltiAKxpo7DsbakfzY=; b=PL+O6cpRrqXNWTkZHHUSSflobJHdWmKCCOYkPrb7uKvHvEVEDP3hFa1VWMs8r6ufmj Z6ymANpMCajktwM0DXvAhH2XcfaL17dvV5fHfGfeh301npWxziOII/vQ6XdYWg1McyVY +tIQgONcxqh6zAN45MYKW1/o3wEuEZM9luJSF3c2t1p+R9yl+yMRdL9YuXN1NDanPLUH 5WHA1AOncevn8nyu9V9e7IIxwHXtxaCJDP/Qk6CNixKjTZ2MqZmy9IlYAn/+ruLNL+SW TA79SvbM/R1Ig/yvn9FtfvOtsvK/Pf1D0jlV6c5FjFmVw3Ne8mDjfx33qbbJJ1/xC7og +pZA== X-Gm-Message-State: AOJu0Yw5ie6dcyRh5uWiWUlfiKAAJ6rpnWKghV7i59xGVWXGxpuSgd4u xzYF35Nwec/b4i0qcJyJVCxLC36PF0t972C5z0DefCJNQgv2EXdMsWMYVjmHy8tbWHAHG5l19z4 b59w= X-Google-Smtp-Source: AGHT+IHaWYvigv7RJLtXd1qBB2VOv3Nv8nf6LO0aHh0ZrYaXU+gAzdEAW9o9rvfOUEBv0ks/X45r7A== X-Received: by 2002:a17:902:c94d:b0:20c:d428:adf4 with SMTP id d9443c01a7336-210c6c6ed84mr96768545ad.38.1730082103228; Sun, 27 Oct 2024 19:21:43 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:42 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v10 3/8] mbuf: decode the hash and fdir info in rte_pktmbuf_dump Date: Sun, 27 Oct 2024 19:19:29 -0700 Message-ID: <20241028022131.142609-4-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 Useful to be able to see the meta data in the hex dump. Signed-off-by: Stephen Hemminger --- lib/mbuf/rte_mbuf.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c index 559d5ad8a7..8e452ca98f 100644 --- a/lib/mbuf/rte_mbuf.c +++ b/lib/mbuf/rte_mbuf.c @@ -678,12 +678,26 @@ rte_pktmbuf_dump(FILE *f, const struct rte_mbuf *m, unsigned dump_len) fprintf(f, " pkt_len=%u, ol_flags=%#"PRIx64", nb_segs=%u, port=%u", m->pkt_len, m->ol_flags, m->nb_segs, m->port); + if (m->port != RTE_MBUF_PORT_INVALID) + fprintf(f, ", port=%u", m->port); + if (m->ol_flags & (RTE_MBUF_F_RX_QINQ | RTE_MBUF_F_TX_QINQ)) fprintf(f, ", vlan_tci_outer=%u", m->vlan_tci_outer); if (m->ol_flags & (RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_TX_VLAN)) fprintf(f, ", vlan_tci=%u", m->vlan_tci); + if (m->ol_flags & RTE_MBUF_F_RX_RSS_HASH) + fprintf(f, ", rss=%#x", m->hash.rss); + else if (m->ol_flags & RTE_MBUF_F_RX_FDIR) { + if (m->ol_flags & RTE_MBUF_F_RX_FDIR_ID) + fprintf(f, ", fdir id=%u", m->hash.fdir.id); + else if (m->ol_flags & RTE_MBUF_F_RX_FDIR_FLX) + fprintf(f, ", fdir flex=%#x %x", m->hash.fdir.hi, m->hash.fdir.lo); + else + fprintf(f, " fdir hash=%#x id=%#x ", m->hash.fdir.hash, m->hash.fdir.id); + } + fprintf(f, ", ptype=%#"PRIx32"\n", m->packet_type); nb_segs = m->nb_segs; From patchwork Mon Oct 28 02:19:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147456 X-Patchwork-Delegate: thomas@monjalon.net 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 0A6CA45BE5; Mon, 28 Oct 2024 03:22:09 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E9F5F4068A; Mon, 28 Oct 2024 03:21:54 +0100 (CET) Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) by mails.dpdk.org (Postfix) with ESMTP id E21A440655 for ; Mon, 28 Oct 2024 03:21:44 +0100 (CET) Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-20c8c50fdd9so29490515ad.0 for ; Sun, 27 Oct 2024 19:21:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082104; x=1730686904; 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=ZVRlP9OcpXv3Wy8Rp3wfMvs8R4zhfL0FFcJBSTuQlXk=; b=0FkSYc2ZUkT2ja+CnJ/VbPlhSYOxpfpeBmkEA+9CsFxbJtlwrF+qTOIA05BAvfW06R Pyk5PWCLgw6byOh/Nsc4/gks+mX87JREr8ERETzdTjAYUWJlk2LlT7LNIq5WRq3v9NO/ JRN5p9IwKaNsyztMKRTnwf+AfNpnNfSvx8KkqBxJkp/oznfQXpGxZT+ocV/B+nhttyd9 nY7hCY1Rlu30+C4SxR8UJban6fh19eRY6xbdq9uPQRxRrYCK9NmUNjSemFHjzhDEWK3I Hg4o1yENpr0mTx2dRKvOOtjaCKlIJ+cmxlZE6NKhjLc0HXJHNgzcwStIGEpOAVBgCKPS Is0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082104; x=1730686904; 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=ZVRlP9OcpXv3Wy8Rp3wfMvs8R4zhfL0FFcJBSTuQlXk=; b=QmP9B8W7lmHYhzB4QY+YZ0LNyeMUdbSMibt32yk3TpPFic8CDRc5TDTgh/6uLWUU84 2Xg5/VeczbCRITaB3cK2UzNkpbdKxnT5SVNATsPWUQUZiUiVHAX68d3tPfU9HeIGb63X D3PUVQSFkOWEvMqh/KwM9OvHgRlpHowLKUKHsR4gMzRCDrrmUzg/M25TdjDmOJldov1D lmXjkaNw/rgXV9wL4MI2BL3ZHIjLCmktBUMhSv6s1D2ZFsqY2eMQ5pjOILAUqoVHugtN sknCFsT30DXus4GgAdj5fPA8pWrb6kcjYX2xt8FaCYxY+olMPUXfgPIRQZVTx74dCkwu G6UA== X-Gm-Message-State: AOJu0Yz7hxd2nVuKAbQKiEcG4CT2QBm3byZJd7oUAWIDGIjW4yJRe2kl JY3axJKd7FclQujFKd5EJZe4seMJTSCwnO49TvbzwwEmivi7qeb37psFqUPRJoq9X1/FVJEdgsm 5z78= X-Google-Smtp-Source: AGHT+IHb/CGjCKHKIFU0noX/REgik3rVUVIv4+beo67Wla5x0tKbqO+aKTMoqetuprvATVlLZXbqew== X-Received: by 2002:a17:902:d4c4:b0:20c:b6cf:f450 with SMTP id d9443c01a7336-20fb8ab9eecmr194141525ad.29.1730082104018; Sun, 27 Oct 2024 19:21:44 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:43 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v10 4/8] test: add test for packet dissector Date: Sun, 27 Oct 2024 19:19:30 -0700 Message-ID: <20241028022131.142609-5-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 | 302 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 app/test/test_dissect.c diff --git a/app/test/meson.build b/app/test/meson.build index 0f7e11969a..9fa0ad7cfe 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -63,6 +63,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..08734134d5 --- /dev/null +++ b/app/test/test_dissect.c @@ -0,0 +1,302 @@ +/* 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] = { }; + int ret; + + /* 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)); + + ret = rte_dissect_mbuf(obuf, sizeof(obuf), &mb, 0); + TEST_ASSERT(ret > 0, "Dissect returned: %d", ret); + + TEST_ASSERT_BUFFERS_ARE_EQUAL(obuf, result, len, + "Dissect string differs:\nexpect \"%s\"\n got \"%s\"", + result, obuf); + + return TEST_SUCCESS; +} + +static int +test_buffer(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 = NULL; + char result[LINE_MAX] = { }; + int ret; + + /* 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)); + + /* call rte_dissect first to determine buffer length needed. */ + ret = rte_dissect_mbuf(obuf, 0, &mb, 0); + TEST_ASSERT(ret == len, "Dissect with NULL returned %d not %d", ret, len); + + size_t size = (size_t) ret + 1; /* One extra byte for '\0' */ + obuf = malloc(size); + TEST_ASSERT_NOT_NULL(obuf, "Malloc for buf failed"); + + ret = rte_dissect_mbuf(obuf, size, &mb, 0); + TEST_ASSERT(ret == len, "Dissect with buffer returned %d not %d", ret, len); + + TEST_ASSERT_BUFFERS_ARE_EQUAL(obuf, result, len, + "Dissect string differs:\nexpect \"%s\"\n got \"%s\"", + result, obuf); + free(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]; + int ret; + + /* 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); + + ret = rte_dissect_mbuf(obuf, sizeof(obuf), &mb, snaplen); + TEST_ASSERT(ret > 0, "Truncated len %u failed: %d", + snaplen, ret); + } + + 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]; + int ret; + + /* 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; + ret = rte_dissect_mbuf(obuf, sizeof(obuf), &mb, 0); + TEST_ASSERT(ret > 0, "Fuzz bit %u failed", bit); + *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_buffer), + 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 Mon Oct 28 02:19:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147457 X-Patchwork-Delegate: thomas@monjalon.net 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 0E15A45BE5; Mon, 28 Oct 2024 03:22:15 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 193E740A77; Mon, 28 Oct 2024 03:21:56 +0100 (CET) Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) by mails.dpdk.org (Postfix) with ESMTP id B2D264066F for ; Mon, 28 Oct 2024 03:21:45 +0100 (CET) Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-20c7edf2872so34863515ad.1 for ; Sun, 27 Oct 2024 19:21:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082105; x=1730686905; 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=14sNidZTnXXCRl98/mnIV8Ul+x0NwGeK36XwOtLl1Go=; b=Lxsek+VMn8og5hyAR9WcfBvXLz97Kl6rieT8ny2XNZ4RTmaz47NiBboqL/QS1RrPV2 +h8FfT3h98apxpSjrtyE8K6JYyc/Qvryyo6YXix2AyASEQQHuWYExgmlmbBX5Qdbnhvw UzLzdcBhUs2r7Jp0koXBTtXIKZNFPvOOGXyZZOLJp6oN3qantr6jMD3c5U5DaEAG7nbb aSUUgyhldFnfZMAQWmAAhwMW9JCmm5/yXmsXlw4aXEU76ZUAxzelef6RgjgvMMkbbuep eNImpji+ki5fDA2fJCvbXhYxsPeLcGmJL/ztxplkp4f3IxDdCqsOeI6fXudUeIBTfacJ eIog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082105; x=1730686905; 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=14sNidZTnXXCRl98/mnIV8Ul+x0NwGeK36XwOtLl1Go=; b=TQdKJWcuBgqH0GlkJa6cJ+xvOlQXEjhyC/ZYt98uCC/i3zpOdiVLHiv1RzMvOhcfbz qdnjpXDBbzb5LHcRn1DfdX+mpMiEsWiz9sjNGfA76febPPG3bg8luGGrK8zzkNmOx8dx DGC7hH2zTyst3iaFdcJI5HskqiiFLJd0qNwSIacjaIwEcHqQTf+mgfswySu5f3PZP+Ni RrHX1FW990dqPNu8WwsUby5Jj9WABKubU28qRgg/2DhJ5OHhWl4BewhuLaaaGBvqEKGz tDcwdiJXtqn7KRGiK9dstI8rXqWsMjHOmkdVyWqRzeXhAfCQX80eAqqsWG9oMdN/8TWI k6QQ== X-Gm-Message-State: AOJu0YzmraaMtogP2D4SHN33eT6JDXMwnvoGz6mwC4EP7ukOMYK5uKfy +hgEEw685HDmH1xIHhAMC/6b648qR6Y96OB82rwzlqjkxyEI0w1hNjIyJ3xe5bsKelgfkCHZ2Bl 1YE0= X-Google-Smtp-Source: AGHT+IHlLMtX40Z+Xtrm9btm9OmM3q3odEwfUs5XrDF6O1bSNLNWNN3/jiyj3Aa4H3RAr/JEL7fcBA== X-Received: by 2002:a17:902:d4c4:b0:20c:b6cf:f450 with SMTP id d9443c01a7336-20fb8ab9eecmr194141875ad.29.1730082104832; Sun, 27 Oct 2024 19:21:44 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:44 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Aman Singh Subject: [PATCH v10 5/8] test-pmd: add option to redirect packet log Date: Sun, 27 Oct 2024 19:19:31 -0700 Message-ID: <20241028022131.142609-6-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 When running tests in interactive mode, it is useful to be able to redirect the packet decode (verbose output) into a file. Signed-off-by: Stephen Hemminger --- app/test-pmd/cmdline.c | 41 +++++++++++++++++++++ app/test-pmd/config.c | 23 ++++++++++++ app/test-pmd/testpmd.c | 3 ++ app/test-pmd/testpmd.h | 3 ++ app/test-pmd/util.c | 11 +++++- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 7 ++++ 6 files changed, 86 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 7e0666e9f6..a6dfa116c7 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -315,6 +315,9 @@ static void cmd_help_long_parsed(void *parsed_result, "set verbose (level)\n" " Set the debug verbosity level X.\n\n" + "set output (filename)\n" + " Set the packet debug log file\n\n" + "set log global|(type) (level)\n" " Set the log level.\n\n" @@ -4110,6 +4113,43 @@ static cmdline_parse_inst_t cmd_set_numbers = { }, }; + +/* *** SET OUTPUT FILENAME *** */ +struct cmd_set_output_result { + cmdline_fixed_string_t set; + cmdline_fixed_string_t output; + cmdline_fixed_string_t filename; +}; + +static void +cmd_set_output_parsed(void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_set_output_result *res = parsed_result; + + set_output_file(res->filename); +} + +static cmdline_parse_token_string_t cmd_set_output_set = + TOKEN_STRING_INITIALIZER(struct cmd_set_output_result, set, "set"); +static cmdline_parse_token_string_t cmd_set_output_output = + TOKEN_STRING_INITIALIZER(struct cmd_set_output_result, output, "output"); +static cmdline_parse_token_string_t cmd_set_output_name = + TOKEN_STRING_INITIALIZER(struct cmd_set_output_result, filename, NULL); + +static cmdline_parse_inst_t cmd_set_output = { + .f = cmd_set_output_parsed, + .data = NULL, + .help_str = "set output ", + .tokens = { + (void *)&cmd_set_output_set, + (void *)&cmd_set_output_output, + (void *)&cmd_set_output_name, + NULL, + }, +}; + /* *** SET LOG LEVEL CONFIGURATION *** */ struct cmd_set_log_result { @@ -13650,6 +13690,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = { &cmd_set_xstats_hide_zero, &cmd_set_record_core_cycles, &cmd_set_record_burst_stats, + &cmd_set_output, &cmd_operate_port, &cmd_operate_specific_port, &cmd_operate_attach_port, diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 88770b4dfc..d806cea3d3 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -6340,6 +6340,29 @@ set_verbose_level(uint16_t vb_level) configure_rxtx_dump_callbacks(verbose_level); } +void +set_output_file(const char *filename) +{ + FILE *outf, *oldf; + + if (!strcmp(filename, "-")) { + outf = stdout; + } else { + outf = fopen(filename, "a"); + if (outf == NULL) { + perror(filename); + return; + } + } + + oldf = rte_atomic_exchange_explicit(&output_file, outf, rte_memory_order_seq_cst); + if (oldf != NULL && oldf != stdout) { + /* make sure other threads are not mid print */ + rte_delay_us_sleep(US_PER_S/10); + fclose(oldf); + } +} + void vlan_extend_set(portid_t port_id, int on) { diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index b1401136e4..7790ba6ce0 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -99,6 +99,7 @@ #define EXTBUF_ZONE_SIZE (RTE_PGSIZE_2M - 4 * RTE_CACHE_LINE_SIZE) uint16_t verbose_level = 0; /**< Silent by default. */ +RTE_ATOMIC(FILE *) output_file; /**< log to console by default. */ int testpmd_logtype; /**< Log type for testpmd logs */ /* use main core for command line ? */ @@ -4543,6 +4544,8 @@ main(int argc, char** argv) rte_exit(EXIT_FAILURE, "Cannot register log type"); rte_log_set_level(testpmd_logtype, RTE_LOG_DEBUG); + output_file = stdout; + diag = rte_eal_init(argc, argv); if (diag < 0) rte_exit(EXIT_FAILURE, "Cannot init EAL: %s\n", diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 131ea53f84..e5affd44a2 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -493,6 +494,7 @@ extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */ extern uint8_t record_core_cycles; /**< Enables measurement of CPU cycles */ extern uint8_t record_burst_stats; /**< Enables display of RX and TX bursts */ extern uint16_t verbose_level; /**< Drives messages being displayed, if any. */ +extern RTE_ATOMIC(FILE *) output_file; /**< Where packet data is written */ extern int testpmd_logtype; /**< Log type for testpmd logs */ extern uint8_t interactive; extern uint8_t auto_start; @@ -1105,6 +1107,7 @@ void set_xstats_hide_zero(uint8_t on_off); void set_record_core_cycles(uint8_t on_off); void set_record_burst_stats(uint8_t on_off); void set_verbose_level(uint16_t vb_level); +void set_output_file(const char *filename); void set_rx_pkt_segments(unsigned int *seg_lengths, unsigned int nb_segs); void set_rx_pkt_hdrs(unsigned int *seg_protos, unsigned int nb_segs); void show_rx_pkt_hdrs(void); diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index bf9b639d95..2446687090 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -89,9 +89,15 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], size_t buf_size = MAX_STRING_LEN; size_t cur_len = 0; uint64_t restore_info_dynflag; + FILE *outf; if (!nb_pkts) return; + + outf = rte_atomic_load_explicit(&output_file, rte_memory_order_relaxed); + if (!outf) + 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, @@ -292,11 +298,12 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], MKDUMPSTR(print_buf, buf_size, cur_len, "INVALID mbuf: %s\n", reason); if (cur_len >= buf_size) - printf("%s ...\n", print_buf); + fprintf(outf, "%s ...\n", print_buf); else - printf("%s", print_buf); + fprintf(outf, "%s", print_buf); cur_len = 0; } + fflush(outf); } uint16_t diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index eeef49500f..6aef74ff45 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -684,6 +684,13 @@ Reset forwarding to the default configuration:: testpmd> set default +set output +~~~~~~~~~~ + +Redirect the debug log:: + + testpmd> set output /tmp/packet.log + set verbose ~~~~~~~~~~~ From patchwork Mon Oct 28 02:19:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147458 X-Patchwork-Delegate: thomas@monjalon.net 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 E842045BE5; Mon, 28 Oct 2024 03:22:21 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6BD9D40B8C; Mon, 28 Oct 2024 03:21:57 +0100 (CET) Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) by mails.dpdk.org (Postfix) with ESMTP id 84FEA4066F for ; Mon, 28 Oct 2024 03:21:46 +0100 (CET) Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-20cb47387ceso32180735ad.1 for ; Sun, 27 Oct 2024 19:21:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082106; x=1730686906; 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=glCqBIq6hUrPBN7nC8uIsJYHIiXFMLCfhNidhPzB8W8=; b=0txj5Grr1peOoqpuegDJE1lSAWGbCqHmDGa/b9WJzGLKHejzuCN8CBqTMvQWM8J1nl P6IrsdHku3Xb1MrDh+8vadmpvAhummvhKmgmeDGIqv/Ml7M8y8IATmQVv6m0Q/lF1A+o FzrmkNWeC7hBtUujeq0XDXqDuGkNKXTle9MnUXOffNsfpJF7sBzAH/OHX4+L4J9DJUnC zkjYLr3M72v7nui27h+eNcu+32YXrpJdbK+gRoxzIanX32WiTSGIPIkI/Qvi7OVMzhmH AVFb2jQXv/R0ttnfBC7C+N4BiIf/GG3nNZOe/fnGqemPcHpr5zLVfioF69qKIqK4JIy1 l+ag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082106; x=1730686906; 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=glCqBIq6hUrPBN7nC8uIsJYHIiXFMLCfhNidhPzB8W8=; b=YKh2DGOtEpAvqnyd0zpqrXG6G0CqCQkldJRbW7ToH7WGJUWWzTAI13pP8L/dJ6roOQ hZmZszX6+Efmd/TINU3oDE2bARCzb1lUjmqHng4ho6WdBAABpJEJVEWjZF1CQAIql1uO 3hzOgdjv2/Ck5fBKaSSXzZ0ciKjfwtIg/W63ZSEJ6veXxXut9g/tFYZq3H+YYoTTVhbk NzCrSzpREvkxPVvhrKmJMFZvGVFMkEJ9mPXuY5j8KeSWHktRzRoPu1ikzMAYRpZiLUUw BNtL7X1I9nn8p4dWw1rLQ89SoWJKsZBkvAasiuowoT5kgimiQUCys1eaYY9h96ew/Z0k E3IQ== X-Gm-Message-State: AOJu0YxrbnJzV+JldLtgkHreSGZA7LRnGYEuUwuEx7iCaW4LwcRbVOXf b4BvKe/+7PuJYFGIu781PRLHFWcRG250aNVrbpOWkQuhcq3xfTtaUhFZYyDToLNck5JITpZ1T7S vfls= X-Google-Smtp-Source: AGHT+IFk9lpWnvJbLq/HDjJPSosUiDjhkEkbGYzVbXZMhT1+XeHpnvHmTNhOEDjB1xjemg+/PwdAfQ== X-Received: by 2002:a17:902:d581:b0:20c:bb1c:d216 with SMTP id d9443c01a7336-210c68b6e48mr89212925ad.21.1730082105643; Sun, 27 Oct 2024 19:21:45 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:45 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Aman Singh Subject: [PATCH v10 6/8] test-pmd: add hex decode Date: Sun, 27 Oct 2024 19:19:32 -0700 Message-ID: <20241028022131.142609-7-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 This adds new command: testpmd> set format hex which decodes packet in hex. Signed-off-by: Stephen Hemminger --- app/test-pmd/cmdline.c | 40 +++++++++++++++ app/test-pmd/config.c | 11 +++++ app/test-pmd/testpmd.c | 1 + app/test-pmd/testpmd.h | 7 +++ app/test-pmd/util.c | 54 ++++++++++++++++----- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 13 +++++ 6 files changed, 115 insertions(+), 11 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index a6dfa116c7..fb73087880 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -318,6 +318,9 @@ static void cmd_help_long_parsed(void *parsed_result, "set output (filename)\n" " Set the packet debug log file\n\n" + "set format (verbose|hex)\n" + " Set the format of packet log\\n" + "set log global|(type) (level)\n" " Set the log level.\n\n" @@ -4150,6 +4153,42 @@ static cmdline_parse_inst_t cmd_set_output = { }, }; +/* *** SET FORMAT OF PACKET LOG */ +struct cmd_set_format_result { + cmdline_fixed_string_t set; + cmdline_fixed_string_t format; + cmdline_fixed_string_t value; +}; + +static void +cmd_set_format_parsed(void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_set_format_result *res = parsed_result; + + set_output_format(res->value); +} + +static cmdline_parse_token_string_t cmd_set_format_set = + TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, set, "set"); +static cmdline_parse_token_string_t cmd_set_format_output = + TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, format, "format"); +static cmdline_parse_token_string_t cmd_set_format_value = + TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, value, "verbose#hex"); + +static cmdline_parse_inst_t cmd_set_format = { + .f = cmd_set_format_parsed, + .data = NULL, + .help_str = "set format verbose|hex", + .tokens = { + (void *)&cmd_set_format_set, + (void *)&cmd_set_format_output, + (void *)&cmd_set_format_value, + NULL, + }, +}; + /* *** SET LOG LEVEL CONFIGURATION *** */ struct cmd_set_log_result { @@ -13685,6 +13724,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = { &cmd_read_rxd_txd, &cmd_stop, &cmd_mac_addr, + &cmd_set_format, &cmd_set_fwd_eth_peer, &cmd_set_qmap, &cmd_set_xstats_hide_zero, diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index d806cea3d3..86c18a7dc1 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -6340,6 +6340,17 @@ set_verbose_level(uint16_t vb_level) configure_rxtx_dump_callbacks(verbose_level); } +void +set_output_format(const char *mode) +{ + if (!strcmp(mode, "verbose")) + output_format = OUTPUT_MODE_VERBOSE; + else if (!strcmp(mode, "hex")) + output_format = OUTPUT_MODE_HEX; + else + fprintf(stderr, "Unknown output format '%s'\n", mode); +} + void set_output_file(const char *filename) { diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 7790ba6ce0..f4fd51e46f 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -100,6 +100,7 @@ uint16_t verbose_level = 0; /**< Silent by default. */ RTE_ATOMIC(FILE *) output_file; /**< log to console by default. */ +enum output_mode output_format; /**< default to original mode. */ int testpmd_logtype; /**< Log type for testpmd logs */ /* use main core for command line ? */ diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index e5affd44a2..6c21fb16f8 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -488,6 +488,11 @@ enum dcb_mode_enable DCB_ENABLED }; +enum output_mode { + OUTPUT_MODE_VERBOSE = 0, + OUTPUT_MODE_HEX, +}; + extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */ /* globals used for configuration */ @@ -495,6 +500,7 @@ extern uint8_t record_core_cycles; /**< Enables measurement of CPU cycles */ extern uint8_t record_burst_stats; /**< Enables display of RX and TX bursts */ extern uint16_t verbose_level; /**< Drives messages being displayed, if any. */ extern RTE_ATOMIC(FILE *) output_file; /**< Where packet data is written */ +extern enum output_mode output_format; /**< Format of packet decode */ extern int testpmd_logtype; /**< Log type for testpmd logs */ extern uint8_t interactive; extern uint8_t auto_start; @@ -1107,6 +1113,7 @@ void set_xstats_hide_zero(uint8_t on_off); void set_record_core_cycles(uint8_t on_off); void set_record_burst_stats(uint8_t on_off); void set_verbose_level(uint16_t vb_level); +void set_output_format(const char *mode); void set_output_file(const char *filename); void set_rx_pkt_segments(unsigned int *seg_lengths, unsigned int nb_segs); void set_rx_pkt_hdrs(unsigned int *seg_protos, unsigned int nb_segs); diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index 2446687090..130821fddb 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -16,6 +16,7 @@ #include "testpmd.h" #define MAX_STRING_LEN 8192 +#define MAX_DUMP_LEN 1024 #define MKDUMPSTR(buf, buf_size, cur_len, ...) \ do { \ @@ -67,9 +68,9 @@ 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) +static void +dump_pkt_verbose(FILE *outf, 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; @@ -89,14 +90,6 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], size_t buf_size = MAX_STRING_LEN; size_t cur_len = 0; uint64_t restore_info_dynflag; - FILE *outf; - - if (!nb_pkts) - return; - - outf = rte_atomic_load_explicit(&output_file, rte_memory_order_relaxed); - if (!outf) - return; restore_info_dynflag = rte_flow_restore_info_dynflag(); MKDUMPSTR(print_buf, buf_size, cur_len, @@ -303,6 +296,45 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], fprintf(outf, "%s", print_buf); cur_len = 0; } +} + +static void +dump_pkt_hex(FILE *outf, uint16_t port_id, uint16_t queue, + struct rte_mbuf *pkts[], uint16_t nb_pkts, int is_rx) +{ + fprintf(outf, "port %u/queue %u: %s %u packets\n", port_id, queue, + is_rx ? "received" : "sent", (unsigned int) nb_pkts); + + for (uint16_t i = 0; i < nb_pkts; i++) { + rte_pktmbuf_dump(outf, pkts[i], MAX_DUMP_LEN); + fprintf(outf, "\n"); + } +} + + +static void +dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], + uint16_t nb_pkts, int is_rx) +{ + FILE *outf; + + if (!nb_pkts) + return; + + outf = rte_atomic_load_explicit(&output_file, rte_memory_order_relaxed); + if (unlikely(!outf)) + return; + + switch (output_format) { + case OUTPUT_MODE_VERBOSE: + dump_pkt_verbose(outf, port_id, queue, pkts, nb_pkts, is_rx); + return; + case OUTPUT_MODE_HEX: + dump_pkt_hex(outf, port_id, queue, pkts, nb_pkts, is_rx); + break; + default: + return; + } fflush(outf); } diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 6aef74ff45..088dffd9fd 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -691,6 +691,19 @@ Redirect the debug log:: testpmd> set output /tmp/packet.log +set format +~~~~~~~~~~ + +Chose the output format for packet debug log:: + + testpmd> set format verbose|hex + +Available formats are: + +* ``verbose`` print the packet meta data information +* ``hex`` print the mbuf flags and data in hex + + set verbose ~~~~~~~~~~~ From patchwork Mon Oct 28 02:19:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147459 X-Patchwork-Delegate: thomas@monjalon.net 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 933D445BE5; Mon, 28 Oct 2024 03:22:27 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9E80740B9B; Mon, 28 Oct 2024 03:21:58 +0100 (CET) Received: from mail-pl1-f173.google.com (mail-pl1-f173.google.com [209.85.214.173]) by mails.dpdk.org (Postfix) with ESMTP id 6A8194066F for ; Mon, 28 Oct 2024 03:21:47 +0100 (CET) Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-20c8c50fdd9so29490635ad.0 for ; Sun, 27 Oct 2024 19:21:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082106; x=1730686906; 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=54qwxhKy913FrmKd+E7qWObgNfK78bB+MQcEmg3oeE8=; b=JIqdTHlt7AUy2dB7Glv2/QumK5V73CxzwIvHQmNbWATPKSW/VP3OR4zApstIg9/wS3 /RPkiBqqr1Ao1NasiZ+XMnZZF6NUM2SBz9darewq/akmGphOmgiVHmiG5vGGGE4dyiAn wzxYkEzHVcjmDDMbiAHfKkcEs/wvmqjFBY0qx3ebSW7Jp1JwzqPoWVOMq1Fpe2VLui7i Bam8pf2gdoBwmiu6qZhdPHJcxDoopBNnVPc80OQE0+P24aTLeLAUEdpEMB6TFI7V1fim 0zbKI5tMZBtJz6OWMDzNlNtfpYCaPq+4uyKKqiYRyLAhzY1/li/XdseD+gVPlGjPYFa2 5LGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082106; x=1730686906; 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=54qwxhKy913FrmKd+E7qWObgNfK78bB+MQcEmg3oeE8=; b=qIwcMhqRUXGxXe2eSetkoIdMCpDkVCXBplkIbawMluuUDxykQqLirwyJnDJSrvtuOX CUKADz6fuctVZuy1D1p2Fkiv+MLbgbKsYvq9k2H62pi4lPDL7hnDv0oU4x8hHS6nOBwh 8uh4fMHLJe3kt5yL06RIdyGDcY6OEWIkT8N/deBUJE40OsrKXFF+RH6s80jyNibjxmbN ofBLTRtyh49EIAea3C3HaajtXntaxp0GB8iChEdloyjcFSZZ0IdKszisvM50NWNjIcR+ GKuCVDYsDVvFuhHnyj37lHU6Pn0wMF4lRSVy/1/GgHFpRlzDtaoVgGOlOs5oN/f/58IF 2tbg== X-Gm-Message-State: AOJu0YxWqh9duhr1GCsMwizoGs3qfXrwjkxpAmDuFxBnoIh2mrHHfYAi YyBMrSifs+OUuHVlUtCyiMekURUNjg8dW1lhysOVZ7MMcqWyXlveeo6uwPRyVg/iMiFtwHxzdVI nedA= X-Google-Smtp-Source: AGHT+IGXBQsKpbJhDrZpv/X1JG1hE7OWN27hEr6xhtPsk+Zh3jaSMi9UEnkvmDcfHIPn3cQJELFOTQ== X-Received: by 2002:a17:902:ef43:b0:20e:567c:9d87 with SMTP id d9443c01a7336-20fb89daae4mr183355435ad.20.1730082106498; Sun, 27 Oct 2024 19:21:46 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:46 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Aman Singh Subject: [PATCH v10 7/8] test-pmd: add packet dissect format Date: Sun, 27 Oct 2024 19:19:33 -0700 Message-ID: <20241028022131.142609-8-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 ability to get decode packet in summary tshark style format. Signed-off-by: Stephen Hemminger --- app/test-pmd/cmdline.c | 6 ++-- app/test-pmd/config.c | 23 +++++++++---- app/test-pmd/testpmd.h | 1 + app/test-pmd/util.c | 36 +++++++++++++++++++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 3 +- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index fb73087880..0595da6749 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -318,7 +318,7 @@ static void cmd_help_long_parsed(void *parsed_result, "set output (filename)\n" " Set the packet debug log file\n\n" - "set format (verbose|hex)\n" + "set format (dissect|hex|verbose)\n" " Set the format of packet log\\n" "set log global|(type) (level)\n" @@ -4175,12 +4175,12 @@ static cmdline_parse_token_string_t cmd_set_format_set = static cmdline_parse_token_string_t cmd_set_format_output = TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, format, "format"); static cmdline_parse_token_string_t cmd_set_format_value = - TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, value, "verbose#hex"); + TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, value, "dissect#hex#verbose"); static cmdline_parse_inst_t cmd_set_format = { .f = cmd_set_format_parsed, .data = NULL, - .help_str = "set format verbose|hex", + .help_str = "set format dissect|hex|verbose", .tokens = { (void *)&cmd_set_format_set, (void *)&cmd_set_format_output, diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 86c18a7dc1..410d5a60f2 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -6343,12 +6343,23 @@ set_verbose_level(uint16_t vb_level) void set_output_format(const char *mode) { - if (!strcmp(mode, "verbose")) - output_format = OUTPUT_MODE_VERBOSE; - else if (!strcmp(mode, "hex")) - output_format = OUTPUT_MODE_HEX; - else - fprintf(stderr, "Unknown output format '%s'\n", mode); + static const char * const output_formats[] = { + [OUTPUT_MODE_VERBOSE] = "verbose", + [OUTPUT_MODE_HEX] = "hex", + [OUTPUT_MODE_DISSECT] = "dissect", + }; + + printf("Change output format from %s to %s\n", + output_formats[output_format], mode); + + for (unsigned int i = 0; i < RTE_DIM(output_formats); i++) { + if (strcasecmp(mode, output_formats[i]) == 0) { + output_format = i; + return; + } + } + + fprintf(stderr, "Unknown output format '%s'\n", mode); } void diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 6c21fb16f8..167bfeb00f 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -491,6 +491,7 @@ enum dcb_mode_enable enum output_mode { OUTPUT_MODE_VERBOSE = 0, OUTPUT_MODE_HEX, + OUTPUT_MODE_DISSECT, }; extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */ diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index 130821fddb..551e684e4c 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -311,6 +312,38 @@ dump_pkt_hex(FILE *outf, uint16_t port_id, uint16_t queue, } } +/* Brief tshark style one line output which is + * number time_delta Source Destination Protocol len info + */ +static void +dump_pkt_brief(FILE *outf, 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, count; + double interval; + + /* Compute time interval from the first packet received */ + 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(); + + /* Packet counter needs to be thread safe */ + count = rte_atomic_fetch_add_explicit(&packet_count, nb_pkts, rte_memory_order_relaxed); + + for (uint16_t i = 0; i < nb_pkts; i++) { + const struct rte_mbuf *mb = pkts[i]; + char str[256]; + + rte_dissect_mbuf(str, sizeof(str), mb, 0); + fprintf(outf, "%6"PRIu64" %11.9f %4u:%-3u %c %s\n", + count + i, interval, port, queue, is_rx ? 'R' : 'T', str); + } +} static void dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], @@ -332,6 +365,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], case OUTPUT_MODE_HEX: dump_pkt_hex(outf, port_id, queue, pkts, nb_pkts, is_rx); break; + case OUTPUT_MODE_DISSECT: + dump_pkt_brief(outf, port_id, queue, pkts, nb_pkts, is_rx); + break; default: return; } diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 088dffd9fd..4a852297fb 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -696,12 +696,13 @@ set format Chose the output format for packet debug log:: - testpmd> set format verbose|hex + testpmd> set format dissect|hex|verbose Available formats are: * ``verbose`` print the packet meta data information * ``hex`` print the mbuf flags and data in hex +* ``dissect`` print the packet in tshark summary format set verbose From patchwork Mon Oct 28 02:19:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 147460 X-Patchwork-Delegate: thomas@monjalon.net 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 5A2BC45BE5; Mon, 28 Oct 2024 03:22:33 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 04CD640B9F; Mon, 28 Oct 2024 03:22:00 +0100 (CET) Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) by mails.dpdk.org (Postfix) with ESMTP id 3630F4066F for ; Mon, 28 Oct 2024 03:21:48 +0100 (CET) Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-20e6981ca77so40373585ad.2 for ; Sun, 27 Oct 2024 19:21:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082107; x=1730686907; 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=s7nRBFYAe6SnE5qA+5SG1q4e7VUWvHWA1HvIvZWjzKQ=; b=l9HzpKr507uottOLY/M6NJWNdKrdOtn9hETy7yF5EIMQ89qkzUr0f2gMFCEBuoHlXm +akreVt/FjrZF0IYdAryiEWfiXulhYhkK3GrpNDrnSQPA0v8xylYKrV/+xoSTO33AkMP VahP/z2JTRlWVwCZomaNB3J01Gy9Uky61DtxhkpfJBO/kOJSD4ghnvya2uxRulnnDKcg GouIblcmHUOgd5MPlghRvv7zIFv53qfvsWblE4EqypDGmN2oF0UWBwZxnNXJTSBQydx8 gmU1KGtHk2F9q+21rh5bVRV8SWeetP9ULAEqNyjhse0fw5Z1+T1RywUyG1SWkWudO14J knBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082107; x=1730686907; 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=s7nRBFYAe6SnE5qA+5SG1q4e7VUWvHWA1HvIvZWjzKQ=; b=XdWS27mEiihbRKRE16RTLbvdkJVZNcipFDuWpa14NtanHJTDFS39+qDc3ACPFI5Zpu 26M7L7+IEZYnh58bgz/MBKEcXws+OyQVCAADBEo3Mv5jUtH9R+UeH6laiEaHRtMq6vJ4 mDFSJQtmwKoXTn2UZfFPnmOSDVVpvV26+FdkQLBI3Vs/xjaTm+9KXyDaOUByYioNja21 SeBqy3ELw3we3LQXD0bC1ZFTBVzRWJDvn/TPRTDtpHkmVqns8WFtLv0vkxNSiXVmgGev 6Y0oMrjYyfcfJk2ctKCZ8YAur+Hz2Devqf+6RfSEHTiS1XLRUn1RgkjXJWnnCKAjmE8z weNw== X-Gm-Message-State: AOJu0YxNSp+Y/+cE+IOiO6Jp973jXaISYNgATbnmk9dwPMxBT+ag4K1E sTWWsE+Q5SA9Q2H7OBRVpv7lGoVDg6bDcoT0AOTCp/LcbDnHj/zs08WkM+mCld++jXgElpuHqSV jVNY= X-Google-Smtp-Source: AGHT+IFRSR4YBeEf7WzMrP9CxSpv6p8Kr70NGWaOUqmk5WOUQfSG7EizBnViVHAtSLiINWPn+EZYlA== X-Received: by 2002:a17:903:22c3:b0:20c:90a0:f064 with SMTP id d9443c01a7336-210c6874c00mr93573765ad.10.1730082107269; Sun, 27 Oct 2024 19:21:47 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:46 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , Aman Singh Subject: [PATCH v10 8/8] test-pmd: add a JSON packet output Date: Sun, 27 Oct 2024 19:19:34 -0700 Message-ID: <20241028022131.142609-9-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 When doing automated testing it is useful to show packet meta data in JSON. Signed-off-by: Stephen Hemminger --- app/test-pmd/cmdline.c | 6 +- app/test-pmd/config.c | 3 + app/test-pmd/testpmd.h | 1 + app/test-pmd/util.c | 167 ++++++++++++++++++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 7 +- 5 files changed, 178 insertions(+), 6 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 0595da6749..e132dfb3be 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -318,7 +318,7 @@ static void cmd_help_long_parsed(void *parsed_result, "set output (filename)\n" " Set the packet debug log file\n\n" - "set format (dissect|hex|verbose)\n" + "set format (dissect|hex|json|verbose)\n" " Set the format of packet log\\n" "set log global|(type) (level)\n" @@ -4175,12 +4175,12 @@ static cmdline_parse_token_string_t cmd_set_format_set = static cmdline_parse_token_string_t cmd_set_format_output = TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, format, "format"); static cmdline_parse_token_string_t cmd_set_format_value = - TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, value, "dissect#hex#verbose"); + TOKEN_STRING_INITIALIZER(struct cmd_set_format_result, value, "dissect#hex#json#verbose"); static cmdline_parse_inst_t cmd_set_format = { .f = cmd_set_format_parsed, .data = NULL, - .help_str = "set format dissect|hex|verbose", + .help_str = "set format dissect|hex|json|verbose", .tokens = { (void *)&cmd_set_format_set, (void *)&cmd_set_format_output, diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 410d5a60f2..99076a326e 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -6347,6 +6347,9 @@ set_output_format(const char *mode) [OUTPUT_MODE_VERBOSE] = "verbose", [OUTPUT_MODE_HEX] = "hex", [OUTPUT_MODE_DISSECT] = "dissect", +#ifdef RTE_HAS_JANSSON + [OUTPUT_MODE_JSON] = "json", +#endif }; printf("Change output format from %s to %s\n", diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 167bfeb00f..fe6025473e 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -492,6 +492,7 @@ enum output_mode { OUTPUT_MODE_VERBOSE = 0, OUTPUT_MODE_HEX, OUTPUT_MODE_DISSECT, + OUTPUT_MODE_JSON, }; extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */ diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index 551e684e4c..7da59988db 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -299,6 +299,168 @@ dump_pkt_verbose(FILE *outf, uint16_t port_id, uint16_t queue, } } +#ifdef RTE_HAS_JANSSON + +/* Encode offload flags as JSON array */ +static json_t * +encode_ol_flags(uint64_t flags, int is_rx) +{ + json_t *ol_array = json_array(); + unsigned int i; + + if (is_rx) + flags &= ~RTE_MBUF_F_TX_OFFLOAD_MASK; + else + flags &= RTE_MBUF_F_TX_OFFLOAD_MASK; + + for (i = 0; i < 64; i++) { + uint64_t mask = (uint64_t)1 << i; + const char *name; + + if (!(mask & flags)) + continue; + + if (is_rx) + name = rte_get_rx_ol_flag_name(mask); + else + name = rte_get_tx_ol_flag_name(mask); + json_array_append_new(ol_array, json_string(name)); + } + return ol_array; +} + +/* Encode packet type fields as JSON object */ +static json_t * +encode_ptype(uint32_t ptype) +{ + if ((ptype & RTE_PTYPE_ALL_MASK) == RTE_PTYPE_UNKNOWN) + return json_string("UNKNOWN"); + + json_t *ptypes = json_array(); + if (ptype & RTE_PTYPE_L2_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_l2_name(ptype))); + if (ptype & RTE_PTYPE_L3_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_l3_name(ptype))); + if (ptype & RTE_PTYPE_L4_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_l4_name(ptype))); + if (ptype & RTE_PTYPE_TUNNEL_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_tunnel_name(ptype))); + if (ptype & RTE_PTYPE_INNER_L2_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_inner_l2_name(ptype))); + if (ptype & RTE_PTYPE_INNER_L3_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_inner_l3_name(ptype))); + if (ptype & RTE_PTYPE_INNER_L4_MASK) + json_array_append(ptypes, json_string(rte_get_ptype_inner_l4_name(ptype))); + + return ptypes; +} + +static void +dump_pkt_json(FILE *outf, uint16_t port_id, uint16_t queue, + struct rte_mbuf *pkts[], uint16_t nb_pkts, int is_rx) +{ + char buf[256]; + + for (uint16_t i = 0; i < nb_pkts; i++) { + const struct rte_mbuf *mb = pkts[i]; + struct rte_net_hdr_lens hdr_lens; + const struct rte_ether_hdr *eth_hdr; + struct rte_ether_hdr _eth_hdr; + uint16_t eth_type; + uint64_t ol_flags = mb->ol_flags; + const char *reason = NULL; + json_t *jobj; + + jobj = json_object(); + json_object_set_new(jobj, "port", json_integer(port_id)); + json_object_set_new(jobj, "queue", json_integer(queue)); + json_object_set_new(jobj, "is_rx", json_boolean(is_rx)); + + if (rte_mbuf_check(mb, 1, &reason) < 0) { + json_object_set_new(jobj, "invalid", json_string(reason)); + continue; + } + + eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr); + eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type); + + rte_ether_format_addr(buf, sizeof(buf), ð_hdr->dst_addr); + json_object_set_new(jobj, "dst", json_string(buf)); + rte_ether_format_addr(buf, sizeof(buf), ð_hdr->src_addr); + json_object_set_new(jobj, "src", json_string(buf)); + + snprintf(buf, sizeof(buf), "0x%04x", eth_type); + json_object_set_new(jobj, "type", json_string(buf)); + + json_object_set_new(jobj, "length", json_integer(mb->pkt_len)); + json_object_set_new(jobj, "nb_segs", json_integer(mb->nb_segs)); + + if (ol_flags & RTE_MBUF_F_RX_RSS_HASH) + json_object_set_new(jobj, "rss_hash", json_integer(mb->hash.rss)); + + if (ol_flags & RTE_MBUF_F_RX_FDIR) { + json_t *fdir = json_object(); + + if (ol_flags & RTE_MBUF_F_RX_FDIR_ID) + json_object_set_new(fdir, "id", + json_integer(mb->hash.fdir.hi)); + else if (ol_flags & RTE_MBUF_F_RX_FDIR_FLX) { + json_t *bytes = json_array(); + + json_array_append(bytes, json_integer(mb->hash.fdir.hi)); + json_array_append(bytes, json_integer(mb->hash.fdir.lo)); + json_object_set_new(fdir, "flex", bytes); + } else { + json_object_set_new(fdir, "hash", json_integer(mb->hash.fdir.hash)); + json_object_set_new(fdir, "id", json_integer(mb->hash.fdir.id)); + } + } + + if (is_timestamp_enabled(mb)) + json_object_set_new(jobj, "timestamp", json_integer(get_timestamp(mb))); + + if ((is_rx && (ol_flags & RTE_MBUF_F_RX_QINQ) != 0) || + (!is_rx && (ol_flags & RTE_MBUF_F_TX_QINQ) != 0)) { + json_object_set_new(jobj, "vlan_tci", json_integer(mb->vlan_tci)); + json_object_set_new(jobj, "vlan_outer_tci", + json_integer(mb->vlan_tci_outer)); + } else if ((is_rx && (ol_flags & RTE_MBUF_F_RX_VLAN) != 0) || + (!is_rx && (ol_flags & RTE_MBUF_F_TX_VLAN) != 0)) { + json_object_set_new(jobj, "vlan_tci", json_integer(mb->vlan_tci)); + } + + if (mb->packet_type) + json_object_set_new(jobj, "hw_ptype", encode_ptype(mb->packet_type)); + + uint32_t sw_packet_type = rte_net_get_ptype(mb, &hdr_lens, RTE_PTYPE_ALL_MASK); + json_object_set_new(jobj, "sw_ptype", encode_ptype(sw_packet_type)); + + if (sw_packet_type & RTE_PTYPE_L2_MASK) + json_object_set_new(jobj, "l2_len", json_integer(hdr_lens.l2_len)); + if (sw_packet_type & RTE_PTYPE_L3_MASK) + json_object_set_new(jobj, "l3_len", json_integer(hdr_lens.l3_len)); + if (sw_packet_type & RTE_PTYPE_L4_MASK) + json_object_set_new(jobj, "l4_len", json_integer(hdr_lens.l4_len)); + if (sw_packet_type & RTE_PTYPE_TUNNEL_MASK) + json_object_set_new(jobj, "tunnel_len", json_integer(hdr_lens.tunnel_len)); + if (sw_packet_type & RTE_PTYPE_INNER_L2_MASK) + json_object_set_new(jobj, "inner_l2_len", + json_integer(hdr_lens.inner_l2_len)); + if (sw_packet_type & RTE_PTYPE_INNER_L3_MASK) + json_object_set_new(jobj, "inner_l3_len", + json_integer(hdr_lens.inner_l3_len)); + if (sw_packet_type & RTE_PTYPE_INNER_L4_MASK) + json_object_set_new(jobj, "inner_l4_len", + json_integer(hdr_lens.inner_l4_len)); + + json_object_set_new(jobj, "ol_flags", encode_ol_flags(mb->ol_flags, is_rx)); + + json_dumpf(jobj, outf, JSON_INDENT(4)); + json_decref(jobj); + } +} +#endif + static void dump_pkt_hex(FILE *outf, uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, int is_rx) @@ -368,6 +530,11 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], case OUTPUT_MODE_DISSECT: dump_pkt_brief(outf, port_id, queue, pkts, nb_pkts, is_rx); break; +#ifdef RTE_HAS_JANSSON + case OUTPUT_MODE_JSON: + dump_pkt_json(outf, port_id, queue, pkts, nb_pkts, is_rx); + break; +#endif default: return; } diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 4a852297fb..e66689ccfd 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -696,13 +696,14 @@ set format Chose the output format for packet debug log:: - testpmd> set format dissect|hex|verbose + testpmd> set format dissect|hex|json|verbose Available formats are: -* ``verbose`` print the packet meta data information -* ``hex`` print the mbuf flags and data in hex * ``dissect`` print the packet in tshark summary format +* ``hex`` print the mbuf flags and data in hex +* ``json`` print the packet meta data in json +* ``verbose`` print the packet meta data information set verbose