patches for DPDK stable branches
 help / color / mirror / Atom feed
* [PATCH 1/5] cmdline: make rdline status not private
       [not found] <20240831171035.27505-1-stephen@networkplumber.org>
@ 2024-08-31 17:09 ` Stephen Hemminger
  2024-08-31 17:09 ` [PATCH 2/5] cmdline: handle EOF as quit Stephen Hemminger
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2024-08-31 17:09 UTC (permalink / raw)
  To: Kevin Traynor; +Cc: Stephen Hemminger, stable, Chengwen Feng

The function cmdline_poll() returns values from rdline_status enum
but that was moved to being defined only in cmdline_private.h.

For proper use of the API the return value needs to be visible
to callers. This was not a problem before because cmdline_poll()
was not used anywhere.

Fixes: f8f8dc289095 ("cmdline: make struct rdline opaque")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
(cherry picked from commit 1ac8dd1d1b62c59cd440e5529e3bd5a500e72f76)
---
 lib/cmdline/cmdline.h         | 6 ++++++
 lib/cmdline/cmdline_private.h | 6 ------
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/cmdline/cmdline.h b/lib/cmdline/cmdline.h
index 96674dfda2..b14355ef51 100644
--- a/lib/cmdline/cmdline.h
+++ b/lib/cmdline/cmdline.h
@@ -23,6 +23,12 @@
 extern "C" {
 #endif
 
+enum rdline_status {
+	RDLINE_INIT,
+	RDLINE_RUNNING,
+	RDLINE_EXITED
+};
+
 struct cmdline;
 
 struct cmdline *cmdline_new(cmdline_parse_ctx_t *ctx, const char *prompt, int s_in, int s_out);
diff --git a/lib/cmdline/cmdline_private.h b/lib/cmdline/cmdline_private.h
index c2e906d8de..a3271c7693 100644
--- a/lib/cmdline/cmdline_private.h
+++ b/lib/cmdline/cmdline_private.h
@@ -23,12 +23,6 @@
 #define RDLINE_HISTORY_BUF_SIZE BUFSIZ
 #define RDLINE_HISTORY_MAX_LINE 64
 
-enum rdline_status {
-	RDLINE_INIT,
-	RDLINE_RUNNING,
-	RDLINE_EXITED
-};
-
 struct rdline {
 	enum rdline_status status;
 	/* rdline bufs */
-- 
2.45.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/5] cmdline: handle EOF as quit
       [not found] <20240831171035.27505-1-stephen@networkplumber.org>
  2024-08-31 17:09 ` [PATCH 1/5] cmdline: make rdline status not private Stephen Hemminger
@ 2024-08-31 17:09 ` Stephen Hemminger
  2024-08-31 17:09 ` [PATCH 3/5] app/testpmd: cleanup cleanly from signal Stephen Hemminger
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2024-08-31 17:09 UTC (permalink / raw)
  To: Kevin Traynor; +Cc: Stephen Hemminger, stable

If end of file is reached on input, then cmdline_poll() will
return 1 (ie file has something); and then the cmdline_in()
call to read will return 0. With the existing code,
caller has no way to tell that end of file has been reached
 and will retry forever.

A good way to handle this is to make end of file equivalent
to the quit command. Since no more input is possible at that
point.

Fixes: 067855e651d6 ("cmdline: add polling mode")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
(cherry picked from commit 415549f1ccce62b82cb182175346904a65f74cec)
---
 lib/cmdline/cmdline.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lib/cmdline/cmdline.c b/lib/cmdline/cmdline.c
index 8f1854cb0b..5600f012c2 100644
--- a/lib/cmdline/cmdline.c
+++ b/lib/cmdline/cmdline.c
@@ -199,9 +199,14 @@ cmdline_poll(struct cmdline *cl)
 		if (read_status < 0)
 			return read_status;
 
-		status = cmdline_in(cl, &c, 1);
-		if (status < 0 && cl->rdl.status != RDLINE_EXITED)
-			return status;
+		if (read_status == 0) {
+			/* end of file is implicit quit */
+			cmdline_quit(cl);
+		} else {
+			status = cmdline_in(cl, &c, 1);
+			if (status < 0 && cl->rdl.status != RDLINE_EXITED)
+				return status;
+		}
 	}
 
 	return cl->rdl.status;
-- 
2.45.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/5] app/testpmd: cleanup cleanly from signal
       [not found] <20240831171035.27505-1-stephen@networkplumber.org>
  2024-08-31 17:09 ` [PATCH 1/5] cmdline: make rdline status not private Stephen Hemminger
  2024-08-31 17:09 ` [PATCH 2/5] cmdline: handle EOF as quit Stephen Hemminger
@ 2024-08-31 17:09 ` Stephen Hemminger
  2024-08-31 17:09 ` [PATCH 4/5] app/testpmd: fix early exit " Stephen Hemminger
  2024-08-31 17:09 ` [PATCH 5/5] app/testpmd: fix interactive mode on Windows Stephen Hemminger
  4 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2024-08-31 17:09 UTC (permalink / raw)
  To: Kevin Traynor; +Cc: Stephen Hemminger, stable, Ferruh Yigit

Do a clean shutdown of testpmd when a signal is received; instead of
having testpmd kill itself.  This fixes the problem where a signal could
be received in the middle of a PMD and then the signal handler would
call PMD's close routine leading to locking problems.

The cmdline structure no longer needs to be global it can
just be local to the prompt() function.

An added benefit is it gets rid of some Windows specific code.

(cherry picked from commit 0fd1386c30c3ad9365d7fdd2829bf7cb2e1b9dff)

Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Ferruh Yigit <ferruh.yigit@amd.com>
---
 app/test-pmd/cmdline.c | 31 +++++++----------
 app/test-pmd/testpmd.c | 78 ++++++++++++++++++++----------------------
 app/test-pmd/testpmd.h |  3 ++
 3 files changed, 52 insertions(+), 60 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 6e10afeedd..6da5198ac7 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -68,8 +68,6 @@
 #include "cmdline_tm.h"
 #include "bpf_cmd.h"
 
-static struct cmdline *testpmd_cl;
-
 static void cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue);
 
 /* *** Help command with introduction. *** */
@@ -17985,31 +17983,26 @@ cmdline_read_from_file(const char *filename)
 void
 prompt(void)
 {
-	int ret;
+	struct cmdline *cl;
+
 	/* initialize non-constant commands */
 	cmd_set_fwd_mode_init();
 	cmd_set_fwd_retry_mode_init();
 
-	testpmd_cl = cmdline_stdin_new(main_ctx, "testpmd> ");
-	if (testpmd_cl == NULL)
+	cl = cmdline_stdin_new(main_ctx, "testpmd> ");
+	if (cl == NULL)
 		return;
 
-	ret = atexit(prompt_exit);
-	if (ret != 0)
-		fprintf(stderr, "Cannot set exit function for cmdline\n");
+	/* loop until signal or quit command */
+	while (f_quit == 0 && cl_quit == 0) {
+		int status = cmdline_poll(cl);
 
-	cmdline_interact(testpmd_cl);
-	if (ret != 0)
-		cmdline_stdin_exit(testpmd_cl);
-}
-
-void
-prompt_exit(void)
-{
-	if (testpmd_cl != NULL) {
-		cmdline_quit(testpmd_cl);
-		cmdline_stdin_exit(testpmd_cl);
+		if (status < 0 || status == RDLINE_EXITED)
+			break;
 	}
+
+	cmdline_quit(cl);
+	cmdline_stdin_exit(cl);
 }
 
 static void
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 55eb293cc0..40dff96e5c 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,6 +11,7 @@
 #include <fcntl.h>
 #ifndef RTE_EXEC_ENV_WINDOWS
 #include <sys/mman.h>
+#include <sys/select.h>
 #endif
 #include <sys/types.h>
 #include <errno.h>
@@ -219,7 +220,8 @@ unsigned int xstats_display_num; /**< Size of extended statistics to show */
  * In container, it cannot terminate the process which running with 'stats-period'
  * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
  */
-uint8_t f_quit;
+volatile uint8_t f_quit;
+uint8_t cl_quit; /* Quit testpmd from cmdline. */
 
 /*
  * Max Rx frame size, set by '--max-pkt-len' parameter.
@@ -4044,13 +4046,6 @@ init_port(void)
 	memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
 }
 
-static void
-force_quit(void)
-{
-	pmd_test_exit();
-	prompt_exit();
-}
-
 static void
 print_stats(void)
 {
@@ -4069,28 +4064,9 @@ print_stats(void)
 }
 
 static void
-signal_handler(int signum)
+signal_handler(int signum __rte_unused)
 {
-	if (signum == SIGINT || signum == SIGTERM) {
-		fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
-			signum);
-#ifdef RTE_LIB_PDUMP
-		/* uninitialize packet capture framework */
-		rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
-		if (latencystats_enabled != 0)
-			rte_latencystats_uninit();
-#endif
-		force_quit();
-		/* Set flag to indicate the force termination. */
-		f_quit = 1;
-		/* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
-		signal(signum, SIG_DFL);
-		kill(getpid(), signum);
-#endif
-	}
+	f_quit = 1;
 }
 
 int
@@ -4261,15 +4237,9 @@ main(int argc, char** argv)
 			start_packet_forwarding(0);
 		}
 		prompt();
-		pmd_test_exit();
 	} else
 #endif
 	{
-		char c;
-		int rc;
-
-		f_quit = 0;
-
 		printf("No commandline core given, start packet forwarding\n");
 		start_packet_forwarding(tx_first);
 		if (stats_period != 0) {
@@ -4292,15 +4262,41 @@ main(int argc, char** argv)
 				prev_time = cur_time;
 				rte_delay_us_sleep(US_PER_S);
 			}
-		}
+		} else {
+			char c;
+			fd_set fds;
+
+			printf("Press enter to exit\n");
 
-		printf("Press enter to exit\n");
-		rc = read(0, &c, 1);
-		pmd_test_exit();
-		if (rc < 0)
-			return 1;
+			FD_ZERO(&fds);
+			FD_SET(0, &fds);
+
+			/* wait for signal or enter */
+			ret = select(1, &fds, NULL, NULL, NULL);
+			if (ret < 0 && errno != EINTR)
+				rte_exit(EXIT_FAILURE,
+					 "Select failed: %s\n",
+					 strerror(errno));
+
+			/* if got enter then consume it */
+			if (ret == 1 && read(0, &c, 1) < 0)
+				rte_exit(EXIT_FAILURE,
+					 "Read failed: %s\n",
+					 strerror(errno));
+		}
 	}
 
+	pmd_test_exit();
+
+#ifdef RTE_LIB_PDUMP
+	/* uninitialize packet capture framework */
+	rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+	if (latencystats_enabled != 0)
+		rte_latencystats_uninit();
+#endif
+
 	ret = rte_eal_cleanup();
 	if (ret != 0)
 		rte_exit(EXIT_FAILURE,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 2149ecd93a..33b4f5504f 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -32,6 +32,9 @@
 #define RTE_PORT_CLOSED         (uint16_t)2
 #define RTE_PORT_HANDLING       (uint16_t)3
 
+extern uint8_t cl_quit;
+extern volatile uint8_t f_quit;
+
 /*
  * It is used to allocate the memory for hash key.
  * The hash key size is NIC dependent.
-- 
2.45.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/5] app/testpmd: fix early exit from signal
       [not found] <20240831171035.27505-1-stephen@networkplumber.org>
                   ` (2 preceding siblings ...)
  2024-08-31 17:09 ` [PATCH 3/5] app/testpmd: cleanup cleanly from signal Stephen Hemminger
@ 2024-08-31 17:09 ` Stephen Hemminger
  2024-08-31 17:09 ` [PATCH 5/5] app/testpmd: fix interactive mode on Windows Stephen Hemminger
  4 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2024-08-31 17:09 UTC (permalink / raw)
  To: Kevin Traynor; +Cc: Stephen Hemminger, stable, Ferruh Yigit, David Marchand

Other signals may occur causing read to get interrupted.
Loop until quit flag is set by signal, a character is entered,
or end of file. This fixes bug where testpmd would exit early
because of signal used by TAP device.

Bugzilla ID: 1305
Fixes: 0fd1386c30c3 ("app/testpmd: cleanup cleanly from signal")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Ferruh Yigit <ferruh.yigit@amd.com>
Reviewed-by: David Marchand <david.marchand@redhat.com>
(cherry picked from commit a996cd04aeeaeca88e6313174101a1229349fb47)
---
 app/test-pmd/testpmd.c | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 40dff96e5c..1760dd79b8 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,7 +11,6 @@
 #include <fcntl.h>
 #ifndef RTE_EXEC_ENV_WINDOWS
 #include <sys/mman.h>
-#include <sys/select.h>
 #endif
 #include <sys/types.h>
 #include <errno.h>
@@ -4264,25 +4263,17 @@ main(int argc, char** argv)
 			}
 		} else {
 			char c;
-			fd_set fds;
 
 			printf("Press enter to exit\n");
-
-			FD_ZERO(&fds);
-			FD_SET(0, &fds);
-
-			/* wait for signal or enter */
-			ret = select(1, &fds, NULL, NULL, NULL);
-			if (ret < 0 && errno != EINTR)
-				rte_exit(EXIT_FAILURE,
-					 "Select failed: %s\n",
-					 strerror(errno));
-
-			/* if got enter then consume it */
-			if (ret == 1 && read(0, &c, 1) < 0)
-				rte_exit(EXIT_FAILURE,
-					 "Read failed: %s\n",
+			while (f_quit == 0) {
+				/* end-of-file or any character exits loop */
+				if (read(0, &c, 1) >= 0)
+					break;
+				if (errno == EINTR)
+					continue;
+				rte_exit(EXIT_FAILURE, "Read failed: %s\n",
 					 strerror(errno));
+			}
 		}
 	}
 
-- 
2.45.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 5/5] app/testpmd: fix interactive mode on Windows
       [not found] <20240831171035.27505-1-stephen@networkplumber.org>
                   ` (3 preceding siblings ...)
  2024-08-31 17:09 ` [PATCH 4/5] app/testpmd: fix early exit " Stephen Hemminger
@ 2024-08-31 17:09 ` Stephen Hemminger
  4 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2024-08-31 17:09 UTC (permalink / raw)
  To: Kevin Traynor; +Cc: Stephen Hemminger, stable, Olivier Matz

The cmdline_poll() function is broken and was not fully tested,
go back to using cmdline_interact().

Instead, use sigaction() to cancel read character on Unix OS's
and a new helper to cancel I/O on Windows.

Bugzilla ID: 1180
Fixes: 0fd1386c30c3 ("app/testpmd: cleanup cleanly from signal")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
(cherry picked from commit f1d0993e034e39968a2c80a8561b46c260c27487)
---
 app/test-pmd/cmdline.c           | 27 ++++++++++++++-------------
 app/test-pmd/testpmd.c           | 11 +++++++++++
 lib/cmdline/cmdline.c            |  1 +
 lib/cmdline/cmdline_os_unix.c    |  6 ++++++
 lib/cmdline/cmdline_os_windows.c | 14 ++++++++++++++
 lib/cmdline/cmdline_private.h    |  5 ++++-
 6 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 6da5198ac7..126523117f 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -70,6 +70,8 @@
 
 static void cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue);
 
+static struct cmdline *testpmd_cl;
+
 /* *** Help command with introduction. *** */
 struct cmd_help_brief_result {
 	cmdline_fixed_string_t help;
@@ -17979,30 +17981,29 @@ cmdline_read_from_file(const char *filename)
 	printf("Read CLI commands from %s\n", filename);
 }
 
+void
+prompt_exit(void)
+{
+	cmdline_quit(testpmd_cl);
+}
+
 /* prompt function, called from main on MAIN lcore */
 void
 prompt(void)
 {
-	struct cmdline *cl;
-
 	/* initialize non-constant commands */
 	cmd_set_fwd_mode_init();
 	cmd_set_fwd_retry_mode_init();
 
-	cl = cmdline_stdin_new(main_ctx, "testpmd> ");
-	if (cl == NULL)
+	testpmd_cl = cmdline_stdin_new(main_ctx, "testpmd> ");
+	if (testpmd_cl == NULL) {
+		fprintf(stderr,
+			"Failed to create stdin based cmdline context\n");
 		return;
-
-	/* loop until signal or quit command */
-	while (f_quit == 0 && cl_quit == 0) {
-		int status = cmdline_poll(cl);
-
-		if (status < 0 || status == RDLINE_EXITED)
-			break;
 	}
 
-	cmdline_quit(cl);
-	cmdline_stdin_exit(cl);
+	cmdline_interact(testpmd_cl);
+	cmdline_stdin_exit(testpmd_cl);
 }
 
 static void
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 1760dd79b8..27cd83ec74 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -4066,6 +4066,7 @@ static void
 signal_handler(int signum __rte_unused)
 {
 	f_quit = 1;
+	prompt_exit();
 }
 
 int
@@ -4076,8 +4077,18 @@ main(int argc, char** argv)
 	uint16_t count;
 	int ret;
 
+#ifdef RTE_EXEC_ENV_WINDOWS
 	signal(SIGINT, signal_handler);
 	signal(SIGTERM, signal_handler);
+#else
+	/* Want read() not to be restarted on signal */
+	struct sigaction action = {
+		.sa_handler = signal_handler,
+	};
+
+	sigaction(SIGINT, &action, NULL);
+	sigaction(SIGTERM, &action, NULL);
+#endif
 
 	testpmd_logtype = rte_log_register("testpmd");
 	if (testpmd_logtype < 0)
diff --git a/lib/cmdline/cmdline.c b/lib/cmdline/cmdline.c
index 5600f012c2..d0601d69f4 100644
--- a/lib/cmdline/cmdline.c
+++ b/lib/cmdline/cmdline.c
@@ -175,6 +175,7 @@ cmdline_quit(struct cmdline *cl)
 {
 	if (!cl)
 		return;
+	cmdline_cancel(cl);
 	rdline_quit(&cl->rdl);
 }
 
diff --git a/lib/cmdline/cmdline_os_unix.c b/lib/cmdline/cmdline_os_unix.c
index 64a945a34f..9a4ec4e334 100644
--- a/lib/cmdline/cmdline_os_unix.c
+++ b/lib/cmdline/cmdline_os_unix.c
@@ -51,3 +51,9 @@ cmdline_vdprintf(int fd, const char *format, va_list op)
 {
 	return vdprintf(fd, format, op);
 }
+
+/* This function is not needed on Linux, instead use sigaction() */
+void
+cmdline_cancel(__rte_unused struct cmdline *cl)
+{
+}
diff --git a/lib/cmdline/cmdline_os_windows.c b/lib/cmdline/cmdline_os_windows.c
index 73ed9ba290..80863bfc8a 100644
--- a/lib/cmdline/cmdline_os_windows.c
+++ b/lib/cmdline/cmdline_os_windows.c
@@ -203,3 +203,17 @@ cmdline_vdprintf(int fd, const char *format, va_list op)
 
 	return ret;
 }
+
+void
+cmdline_cancel(struct cmdline *cl)
+{
+	if (!cl)
+		return;
+
+	/* force the outstanding read on console to exit */
+	if (cl->oldterm.is_console_input) {
+		HANDLE handle = (HANDLE)_get_osfhandle(cl->s_in);
+
+		CancelIoEx(handle, NULL);
+	}
+}
diff --git a/lib/cmdline/cmdline_private.h b/lib/cmdline/cmdline_private.h
index a3271c7693..86a46cdea6 100644
--- a/lib/cmdline/cmdline_private.h
+++ b/lib/cmdline/cmdline_private.h
@@ -24,7 +24,7 @@
 #define RDLINE_HISTORY_MAX_LINE 64
 
 struct rdline {
-	enum rdline_status status;
+	volatile enum rdline_status status;
 	/* rdline bufs */
 	struct cirbuf left;
 	struct cirbuf right;
@@ -90,6 +90,9 @@ int cmdline_poll_char(struct cmdline *cl);
 /* Read one character from input. */
 ssize_t cmdline_read_char(struct cmdline *cl, char *c);
 
+/* Force current cmdline read to unblock. */
+void cmdline_cancel(struct cmdline *cl);
+
 /* vdprintf(3) */
 __rte_format_printf(2, 0)
 int cmdline_vdprintf(int fd, const char *format, va_list op);
-- 
2.45.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-08-31 17:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20240831171035.27505-1-stephen@networkplumber.org>
2024-08-31 17:09 ` [PATCH 1/5] cmdline: make rdline status not private Stephen Hemminger
2024-08-31 17:09 ` [PATCH 2/5] cmdline: handle EOF as quit Stephen Hemminger
2024-08-31 17:09 ` [PATCH 3/5] app/testpmd: cleanup cleanly from signal Stephen Hemminger
2024-08-31 17:09 ` [PATCH 4/5] app/testpmd: fix early exit " Stephen Hemminger
2024-08-31 17:09 ` [PATCH 5/5] app/testpmd: fix interactive mode on Windows Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).