From 66d8979b35b990098530e56c23f2223bd990683b Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 30 Sep 2025 20:24:22 +0530 Subject: [PATCH] [nrf fromlist] net: Extend display options for vendor stats Add few options for dumping vendor stats, esp. for easier parsing. Upstream PR: https://github.com/zephyrproject-rtos/zephyr/pull/96753 Signed-off-by: Chaitanya Tata --- subsys/net/lib/shell/net_shell_private.h | 8 +++ subsys/net/lib/shell/stats.c | 83 ++++++++++++++++++++---- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/subsys/net/lib/shell/net_shell_private.h b/subsys/net/lib/shell/net_shell_private.h index 076bfd63d33..107c384272a 100644 --- a/subsys/net/lib/shell/net_shell_private.h +++ b/subsys/net/lib/shell/net_shell_private.h @@ -56,9 +56,17 @@ #include "net_private.h" #include "../ip/ipv6.h" +enum net_shell_stats_format { + NET_SHELL_STATS_FORMAT_DEFAULT, + NET_SHELL_STATS_FORMAT_KEY_VALUE, + NET_SHELL_STATS_FORMAT_HEX_BLOB, + NET_SHELL_STATS_FORMAT_BOTH +}; + struct net_shell_user_data { const struct shell *sh; void *user_data; + enum net_shell_stats_format vendor_stats_format; }; #if !defined(NET_VLAN_MAX_COUNT) diff --git a/subsys/net/lib/shell/stats.c b/subsys/net/lib/shell/stats.c index 666a98e35d7..025ffc845d6 100644 --- a/subsys/net/lib/shell/stats.c +++ b/subsys/net/lib/shell/stats.c @@ -45,7 +45,7 @@ static const char *priority2str(enum net_priority priority) #if defined(CONFIG_NET_STATISTICS_ETHERNET) && \ defined(CONFIG_NET_STATISTICS_USER_API) static void print_eth_stats(struct net_if *iface, struct net_stats_eth *data, - const struct shell *sh) + const struct shell *sh, struct net_shell_user_data *user_data) { PR("Statistics for Ethernet interface %p [%d]\n", iface, net_if_get_by_iface(iface)); @@ -69,16 +69,42 @@ static void print_eth_stats(struct net_if *iface, struct net_stats_eth *data, #if defined(CONFIG_NET_STATISTICS_ETHERNET_VENDOR) if (data->vendor) { - PR("Vendor specific statistics for Ethernet " - "interface %p [%d]:\n", - iface, net_if_get_by_iface(iface)); size_t i = 0; + enum net_shell_stats_format format = NET_SHELL_STATS_FORMAT_DEFAULT; + + if (user_data) { + format = user_data->vendor_stats_format; + } + + PR("Vendor specific statistics for Ethernet interface %p [%d]:\n", + iface, net_if_get_by_iface(iface)); + + /* Print key-value pairs if requested */ + if (format == NET_SHELL_STATS_FORMAT_DEFAULT || + format == NET_SHELL_STATS_FORMAT_KEY_VALUE || + format == NET_SHELL_STATS_FORMAT_BOTH) { + do { + PR("%s : %u\n", data->vendor[i].key, data->vendor[i].value); + i++; + } while (data->vendor[i].key); + } - do { - PR("%s : %u\n", data->vendor[i].key, - data->vendor[i].value); - i++; - } while (data->vendor[i].key); + /* Print hex blob if requested */ + if (format == NET_SHELL_STATS_FORMAT_HEX_BLOB || + format == NET_SHELL_STATS_FORMAT_BOTH) { + /* Suitable for parsing */ + PR("Vendor stats hex blob: "); + for (i = 0; data->vendor[i].key; i++) { + uint32_t v = data->vendor[i].value; + + PR("%02x%02x%02x%02x", + (uint8_t)(v & 0xFF), + (uint8_t)((v >> 8) & 0xFF), + (uint8_t)((v >> 16) & 0xFF), + (uint8_t)((v >> 24) & 0xFF)); + } + PR("\n"); + } } #endif /* CONFIG_NET_STATISTICS_ETHERNET_VENDOR */ } @@ -513,7 +539,7 @@ static void net_shell_print_statistics(struct net_if *iface, void *user_data) ret = net_mgmt(NET_REQUEST_STATS_GET_ETHERNET, iface, ð_data, sizeof(eth_data)); if (!ret) { - print_eth_stats(iface, ð_data, sh); + print_eth_stats(iface, ð_data, sh, data); } } #endif /* CONFIG_NET_STATISTICS_ETHERNET && CONFIG_NET_STATISTICS_USER_API */ @@ -551,6 +577,18 @@ int cmd_net_stats_all(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_NET_STATISTICS) user_data.sh = sh; + user_data.vendor_stats_format = NET_SHELL_STATS_FORMAT_DEFAULT; + + /* Parse format argument if provided */ + if (argc > 1) { + if (strcmp(argv[1], "key-value") == 0) { + user_data.vendor_stats_format = NET_SHELL_STATS_FORMAT_KEY_VALUE; + } else if (strcmp(argv[1], "hex-blob") == 0) { + user_data.vendor_stats_format = NET_SHELL_STATS_FORMAT_HEX_BLOB; + } else if (strcmp(argv[1], "both") == 0) { + user_data.vendor_stats_format = NET_SHELL_STATS_FORMAT_BOTH; + } + } /* Print global network statistics */ net_shell_print_statistics_all(&user_data); @@ -596,6 +634,18 @@ int cmd_net_stats_iface(const struct shell *sh, size_t argc, char *argv[]) } data.sh = sh; + data.vendor_stats_format = NET_SHELL_STATS_FORMAT_DEFAULT; + + /* Parse format argument if provided */ + if (argc > 2) { + if (strcmp(argv[2], "key-value") == 0) { + data.vendor_stats_format = NET_SHELL_STATS_FORMAT_KEY_VALUE; + } else if (strcmp(argv[2], "hex-blob") == 0) { + data.vendor_stats_format = NET_SHELL_STATS_FORMAT_HEX_BLOB; + } else if (strcmp(argv[2], "both") == 0) { + data.vendor_stats_format = NET_SHELL_STATS_FORMAT_BOTH; + } + } net_shell_print_statistics(iface, &data); #else @@ -645,15 +695,20 @@ static int cmd_net_stats(const struct shell *sh, size_t argc, char *argv[]) SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_stats, SHELL_CMD(all, NULL, - "Show network statistics for all network interfaces.", + "Show network statistics for all network interfaces.\n" + "Usage: net stats all [key-value|hex-blob|both]", cmd_net_stats_all), SHELL_CMD(iface, IFACE_DYN_CMD, - "'net stats ' shows network statistics for " - "one specific network interface.", + "'net stats [key-value|hex-blob|both]' shows network statistics for " + "one specific network interface.\n" + "Format options:\n" + " key-value: Show vendor stats as key-value pairs (default)\n" + " hex-blob: Show vendor stats as hex blob for parsing\n" + " both: Show both key-value and hex blob formats", cmd_net_stats_iface), SHELL_SUBCMD_SET_END ); SHELL_SUBCMD_ADD((net), stats, &net_cmd_stats, "Show network statistics.", - cmd_net_stats, 1, 1); + cmd_net_stats, 1, 3);