@@ -1189,6 +1189,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
11891189#if defined(HAVE_IPPROTO_MPTCP )
11901190 {"mptcp" , no_argument , NULL , 'm' },
11911191#endif
1192+ {"gsro" , no_argument , NULL , OPT_GSRO },
11921193 {"debug" , optional_argument , NULL , 'd' },
11931194 {"help" , no_argument , NULL , 'h' },
11941195 {NULL , 0 , NULL , 0 }
@@ -1212,6 +1213,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
12121213
12131214 blksize = 0 ;
12141215 server_flag = client_flag = rate_flag = duration_flag = rcv_timeout_flag = snd_timeout_flag = 0 ;
1216+ int gsro_flag = 0 ;
12151217#if defined(HAVE_SSL )
12161218 char * client_username = NULL , * client_rsa_public_key = NULL , * server_rsa_private_key = NULL ;
12171219 FILE * ptr_file ;
@@ -1790,6 +1792,13 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
17901792 test -> mptcp = 1 ;
17911793 break ;
17921794#endif
1795+ case OPT_GSRO :
1796+ /* Enable GSO/GRO which is disabled by default */
1797+ /* Flag is available regardless of local support to allow client to request server to use it */
1798+ gsro_flag = 1 ;
1799+ test -> settings -> gso = 1 ;
1800+ test -> settings -> gro = 1 ;
1801+ break ;
17931802 case 'h' :
17941803 usage_long (stdout );
17951804 exit (0 );
@@ -1809,6 +1818,21 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
18091818 i_errno = IECLIENTONLY ;
18101819 return -1 ;
18111820 }
1821+ if (test -> role == 's' && gsro_flag ) {
1822+ i_errno = IECLIENTONLY ;
1823+ return -1 ;
1824+ }
1825+
1826+ /* Show platform support warnings only after confirming we're in client mode */
1827+ if (gsro_flag ) {
1828+ #if !defined(HAVE_UDP_SEGMENT ) && !defined(HAVE_UDP_GRO )
1829+ warning ("--gsro requested but UDP GSO/GRO not supported on this client; will only be enabled on server if supported" );
1830+ #elif !defined(HAVE_UDP_SEGMENT )
1831+ warning ("--gsro requested but UDP GSO not supported on this client; will be enabled on server if supported" );
1832+ #elif !defined(HAVE_UDP_GRO )
1833+ warning ("--gsro requested but UDP GRO not supported on this client; will be enabled on server if supported" );
1834+ #endif
1835+ }
18121836
18131837#if defined(HAVE_SSL )
18141838
@@ -1914,6 +1938,18 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
19141938 i_errno = IEUDPBLOCKSIZE ;
19151939 return -1 ;
19161940 }
1941+
1942+ if (test -> protocol -> id == Pudp && test -> settings -> gso ) {
1943+ test -> settings -> gso_dg_size = blksize ;
1944+ /* use the multiple of datagram size for the best efficiency. */
1945+ if (test -> settings -> gso_dg_size > 0 ) {
1946+ test -> settings -> gso_bf_size = (test -> settings -> gso_bf_size / test -> settings -> gso_dg_size ) * test -> settings -> gso_dg_size ;
1947+ } else {
1948+ /* If gso_dg_size is 0 (unlimited bandwidth), use default UDP datagram size */
1949+ test -> settings -> gso_dg_size = DEFAULT_UDP_BLKSIZE ;
1950+ }
1951+ }
1952+
19171953 test -> settings -> blksize = blksize ;
19181954
19191955 if (!rate_flag )
@@ -2457,6 +2493,16 @@ send_parameters(struct iperf_test *test)
24572493 cJSON_AddNumberToObject (j , "pacing_timer" , test -> settings -> pacing_timer );
24582494 if (test -> settings -> burst )
24592495 cJSON_AddNumberToObject (j , "burst" , test -> settings -> burst );
2496+
2497+ /* Send UDP GSO/GRO settings from client to server */
2498+ /* Always send these fields to allow server to use GSO/GRO even if client doesn't support it */
2499+ if (test -> protocol -> id == Pudp ) {
2500+ cJSON_AddNumberToObject (j , "gso" , test -> settings -> gso );
2501+ cJSON_AddNumberToObject (j , "gso_dg_size" , test -> settings -> gso_dg_size );
2502+ cJSON_AddNumberToObject (j , "gso_bf_size" , test -> settings -> gso_bf_size );
2503+ cJSON_AddNumberToObject (j , "gro" , test -> settings -> gro );
2504+ cJSON_AddNumberToObject (j , "gro_bf_size" , test -> settings -> gro_bf_size );
2505+ }
24602506 if (test -> settings -> tos )
24612507 cJSON_AddNumberToObject (j , "TOS" , test -> settings -> tos );
24622508 if (test -> settings -> flowlabel )
@@ -2580,6 +2626,31 @@ get_parameters(struct iperf_test *test)
25802626 test -> settings -> socket_bufsize = j_p -> valueint ;
25812627 if ((j_p = iperf_cJSON_GetObjectItemType (j , "len" , cJSON_Number )) != NULL )
25822628 test -> settings -> blksize = j_p -> valueint ;
2629+
2630+ /* Accept UDP GSO/GRO settings provided by the client */
2631+ /* Always accept these fields to allow server to use GSO/GRO based on its own support */
2632+ if ((j_p = iperf_cJSON_GetObjectItemType (j , "gso" , cJSON_Number )) != NULL )
2633+ test -> settings -> gso = j_p -> valueint ;
2634+ if ((j_p = iperf_cJSON_GetObjectItemType (j , "gso_dg_size" , cJSON_Number )) != NULL )
2635+ test -> settings -> gso_dg_size = j_p -> valueint ;
2636+ if ((j_p = iperf_cJSON_GetObjectItemType (j , "gso_bf_size" , cJSON_Number )) != NULL )
2637+ test -> settings -> gso_bf_size = j_p -> valueint ;
2638+
2639+ /* Backward-compatibility: If client didn't send GSO params, derive from blksize. */
2640+ if (test -> protocol -> id == Pudp && test -> settings -> gso == 1 && test -> settings -> gso_dg_size == 0 ) {
2641+ test -> settings -> gso_dg_size = test -> settings -> blksize ;
2642+ if (test -> settings -> gso_dg_size > 0 ) {
2643+ test -> settings -> gso_bf_size = (test -> settings -> gso_bf_size / test -> settings -> gso_dg_size ) * test -> settings -> gso_dg_size ;
2644+ } else {
2645+ test -> settings -> gso_dg_size = DEFAULT_UDP_BLKSIZE ;
2646+ }
2647+ }
2648+
2649+ if ((j_p = iperf_cJSON_GetObjectItemType (j , "gro" , cJSON_Number )) != NULL )
2650+ test -> settings -> gro = j_p -> valueint ;
2651+ if ((j_p = iperf_cJSON_GetObjectItemType (j , "gro_bf_size" , cJSON_Number )) != NULL )
2652+ test -> settings -> gro_bf_size = j_p -> valueint ;
2653+
25832654 if ((j_p = iperf_cJSON_GetObjectItemType (j , "bandwidth" , cJSON_Number )) != NULL )
25842655 test -> settings -> rate = j_p -> valueint ;
25852656 if ((j_p = iperf_cJSON_GetObjectItemType (j , "fqrate" , cJSON_Number )) != NULL )
@@ -3239,6 +3310,12 @@ iperf_defaults(struct iperf_test *testp)
32393310 testp -> settings -> fqrate = 0 ;
32403311 testp -> settings -> pacing_timer = DEFAULT_PACING_TIMER ;
32413312 testp -> settings -> burst = 0 ;
3313+ /* Always initialize GSO/GRO fields to allow client-server negotiation */
3314+ testp -> settings -> gso = 0 ; /* Disable GSO by default, enabled via --gsro */
3315+ testp -> settings -> gso_dg_size = 0 ;
3316+ testp -> settings -> gso_bf_size = GSO_BF_MAX_SIZE ;
3317+ testp -> settings -> gro = 0 ; /* Disable GRO by default, enabled via --gsro */
3318+ testp -> settings -> gro_bf_size = GRO_BF_MAX_SIZE ;
32423319 testp -> settings -> mss = 0 ;
32433320 testp -> settings -> bytes = 0 ;
32443321 testp -> settings -> blocks = 0 ;
@@ -3552,6 +3629,10 @@ iperf_reset_test(struct iperf_test *test)
35523629 test -> settings -> burst = 0 ;
35533630 test -> settings -> mss = 0 ;
35543631 test -> settings -> tos = 0 ;
3632+ /* Always initialize GSO/GRO fields */
3633+ test -> settings -> gso_dg_size = 0 ;
3634+ test -> settings -> gso_bf_size = GSO_BF_MAX_SIZE ;
3635+ test -> settings -> gro_bf_size = GRO_BF_MAX_SIZE ;
35553636 test -> settings -> dont_fragment = 0 ;
35563637 test -> zerocopy = 0 ;
35573638 test -> settings -> skip_rx_copy = 0 ;
@@ -4716,6 +4797,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
47164797{
47174798 struct iperf_stream * sp ;
47184799 int ret = 0 ;
4800+ int size ;
47194801
47204802 char template [1024 ];
47214803 if (test -> tmp_template ) {
@@ -4774,13 +4856,20 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
47744856 free (sp );
47754857 return NULL ;
47764858 }
4777- if (ftruncate (sp -> buffer_fd , test -> settings -> blksize ) < 0 ) {
4859+ size = test -> settings -> blksize ;
4860+ if (test -> protocol -> id == Pudp && test -> settings -> gso && (size < test -> settings -> gso_bf_size ))
4861+ size = test -> settings -> gso_bf_size ;
4862+ if (test -> protocol -> id == Pudp && test -> settings -> gro && (size < test -> settings -> gro_bf_size ))
4863+ size = test -> settings -> gro_bf_size ;
4864+ if (sp -> test -> debug )
4865+ printf ("Buffer %d bytes\n" , size );
4866+ if (ftruncate (sp -> buffer_fd , size ) < 0 ) {
47784867 i_errno = IECREATESTREAM ;
47794868 free (sp -> result );
47804869 free (sp );
47814870 return NULL ;
47824871 }
4783- sp -> buffer = (char * ) mmap (NULL , test -> settings -> blksize , PROT_READ |PROT_WRITE , MAP_SHARED , sp -> buffer_fd , 0 );
4872+ sp -> buffer = (char * ) mmap (NULL , size , PROT_READ |PROT_WRITE , MAP_SHARED , sp -> buffer_fd , 0 );
47844873 if (sp -> buffer == MAP_FAILED ) {
47854874 i_errno = IECREATESTREAM ;
47864875 free (sp -> result );
0 commit comments