diff --git a/src/iperf3.1 b/src/iperf3.1 index 626c6372f..394f3166b 100644 --- a/src/iperf3.1 +++ b/src/iperf3.1 @@ -525,6 +525,27 @@ settings to the server automatically. This feature is disabled by default and must be explicitly enabled with this flag. .TP +.BR --gsro/s +Enable UDP Generic Segmentation Offload (GSO) on the sender, where +supported by the operating system and network hardware (currently Linux only). +GSO allows the network stack to aggregate multiple UDP datagrams +into larger packets, improving throughput and reducing CPU overhead. +This is a client-only option; the client communicates the GSO +settings to the server automatically. +This feature is disabled by default and must be explicitly enabled +with this flag. +.TP +.BR --gsro/r +Enable UDP Generic Receive Offload (GRO) on the receiver, where supported by +the operating system and network hardware (currently Linux only). +GRO is an aggregation technique to coalesce several receive packets from a +stream into a single large packet, thus saving CPU cycles as fewer packets +need to be processed by the kernel. By default, GRO is accomplished in the Linux kernel. +This is a client-only option; the client communicates the GRO +settings to the server automatically. +This feature is disabled by default and must be explicitly enabled +with this flag. +.TP .BR --repeating-payload Use repeating pattern in payload, instead of random bytes. The same payload is used in iperf2 (ASCII '0..9' repeating). diff --git a/src/iperf_api.c b/src/iperf_api.c index ddfb69f76..2aadf5b78 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1194,6 +1194,8 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"mptcp", no_argument, NULL, 'm'}, #endif {"gsro", no_argument, NULL, OPT_GSRO}, + {"gsro/s", no_argument, NULL, OPT_GSRO_S}, + {"gsro/r", no_argument, NULL, OPT_GSRO_R}, {"debug", optional_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} @@ -1813,6 +1815,20 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) test->settings->gso = 1; test->settings->gro = 1; break; + case OPT_GSRO_S: + /* Enable GSO which is disabled by default */ + /* Flag is available regardless of local support to allow client to request server to use it */ + gsro_flag = 1; + test->settings->gso = 1; + test->settings->gro = 0; + break; + case OPT_GSRO_R: + /* Enable GRO which is disabled by default */ + /* Flag is available regardless of local support to allow client to request server to use it */ + gsro_flag = 1; + test->settings->gso = 0; + test->settings->gro = 1; + break; case 'h': usage_long(stdout); exit(0); @@ -1840,11 +1856,11 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) /* Show platform support warnings only after confirming we're in client mode */ if (gsro_flag) { #if !defined(HAVE_UDP_SEGMENT) && !defined(HAVE_UDP_GRO) - warning("--gsro requested but UDP GSO/GRO not supported on this client; will only be enabled on server if supported"); + warning("GSO/GRO requested but UDP GSO/GRO not supported on this client; will only be enabled on server if supported"); #elif !defined(HAVE_UDP_SEGMENT) - warning("--gsro requested but UDP GSO not supported on this client; will be enabled on server if supported"); + warning("GSO requested but UDP GSO not supported on this client; will be enabled on server if supported"); #elif !defined(HAVE_UDP_GRO) - warning("--gsro requested but UDP GRO not supported on this client; will be enabled on server if supported"); + warning("GRO requested but UDP GRO not supported on this client; will be enabled on server if supported"); #endif } @@ -3455,10 +3471,10 @@ iperf_defaults(struct iperf_test *testp) testp->settings->pacing_timer = DEFAULT_PACING_TIMER; testp->settings->burst = 0; /* Always initialize GSO/GRO fields to allow client-server negotiation */ - testp->settings->gso = 0; /* Disable GSO by default, enabled via --gsro */ + testp->settings->gso = 0; /* Disable GSO by default, enabled via --gsro or --gsro/s*/ testp->settings->gso_dg_size = 0; testp->settings->gso_bf_size = GSO_BF_MAX_SIZE; - testp->settings->gro = 0; /* Disable GRO by default, enabled via --gsro */ + testp->settings->gro = 0; /* Disable GRO by default, enabled via --gsro or --gsro/r*/ testp->settings->gro_bf_size = GRO_BF_MAX_SIZE; testp->settings->mss = 0; testp->settings->bytes = 0; diff --git a/src/iperf_api.h b/src/iperf_api.h index 25ac951e0..c4845fb39 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -107,6 +107,8 @@ typedef atomic_uint_fast64_t atomic_iperf_size_t; #define OPT_JSON_STREAM_FULL_OUTPUT 33 #define OPT_SERVER_MAX_DURATION 34 #define OPT_GSRO 35 +#define OPT_GSRO_S 36 +#define OPT_GSRO_R 37 /* states */ #define TEST_START 1 diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 23ca67f61..d73b35c7a 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -521,7 +521,7 @@ iperf_connect(struct iperf_test *test) printf("Setting UDP block size to %d\n", test->settings->blksize); } } - /* Initialize GSO parameters when --gsro is used */ + /* Initialize GSO parameters when --gsro or --gsro/s is used */ if (test->settings->gso) { test->settings->gso_dg_size = test->settings->blksize; /* use the multiple of datagram size for the best efficiency. */ diff --git a/src/iperf_locale.c b/src/iperf_locale.c index eb07c9651..2f90f0eb9 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -219,7 +219,12 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" " --extra-data str data string to include in client and server JSON\n" " --get-server-output get results from server\n" " --udp-counters-64bit use 64-bit counters in UDP test packets\n" - " --gsro enable UDP GSO/GRO on both client and server (client-only option)\n" + " --gsro | --gsro/s | --gsro/r enable UDP GSO and/or GRO on both client and server.\n" + " Exclusive options (choose only one):\n" + " --gsro : Enable both GSO and GRO\n" + " --gsro/s : Enable GSO only\n" + " --gsro/r : Enable GRO only\n" + " (client-only options)\n" " --repeating-payload use repeating pattern in payload, instead of\n" " randomized payload (like in iperf2)\n" #if defined(HAVE_DONT_FRAGMENT)