From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 Content-Transfer-Encoding: 8bit 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 -- 2.45.2