[v10,5/8] test-pmd: add option to redirect packet log

Message ID 20241028022131.142609-6-stephen@networkplumber.org (mailing list archive)
State New
Delegated to: Thomas Monjalon
Headers
Series test-pmd packet decoding enhancements |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Stephen Hemminger Oct. 28, 2024, 2:19 a.m. UTC
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 <stephen@networkplumber.org>
---
 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(-)
  

Patch

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 <filename>",
+	.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 <rte_ethdev.h>
 #include <rte_flow.h>
 #include <rte_mbuf_dyn.h>
+#include <rte_stdatomic.h>
 
 #include <cmdline.h>
 #include <cmdline_parse.h>
@@ -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
 ~~~~~~~~~~~