-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add UDP GSO/GRO support (Linux) and --no-gsro switch #1925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
baae50a
c0ed6db
5158428
dca294e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1188,6 +1188,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) | |
| #endif /* HAVE_TCP_KEEPALIVE */ | ||
| #if defined(HAVE_IPPROTO_MPTCP) | ||
| {"mptcp", no_argument, NULL, 'm'}, | ||
| #endif | ||
| #if defined(HAVE_UDP_SEGMENT) || defined(HAVE_UDP_GRO) | ||
| {"no-gsro", no_argument, NULL, OPT_NO_GSRO}, | ||
| #endif | ||
| {"debug", optional_argument, NULL, 'd'}, | ||
| {"help", no_argument, NULL, 'h'}, | ||
|
|
@@ -1781,6 +1784,17 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) | |
| set_protocol(test, Ptcp); | ||
| test->mptcp = 1; | ||
| break; | ||
| #endif | ||
| #if defined(HAVE_UDP_SEGMENT) || defined(HAVE_UDP_GRO) | ||
| case OPT_NO_GSRO: | ||
| /* Disable GSO/GRO which would otherwise be enabled by default */ | ||
| #ifdef HAVE_UDP_SEGMENT | ||
| test->settings->gso = 0; | ||
| #endif | ||
| #ifdef HAVE_UDP_GRO | ||
| test->settings->gro = 0; | ||
| #endif | ||
| break; | ||
| #endif | ||
| case 'h': | ||
| usage_long(stdout); | ||
|
|
@@ -1802,6 +1816,8 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) | |
| return -1; | ||
| } | ||
|
|
||
| /* GSO/GRO are enabled by default when available, disabled only via --no-gsro */ | ||
|
|
||
| #if defined(HAVE_SSL) | ||
|
|
||
| if (test->role == 's' && (client_username || client_rsa_public_key)){ | ||
|
|
@@ -1906,6 +1922,20 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) | |
| i_errno = IEUDPBLOCKSIZE; | ||
| return -1; | ||
| } | ||
|
|
||
| #ifdef HAVE_UDP_SEGMENT | ||
| if (test->protocol->id == Pudp && test->settings->gso) { | ||
| test->settings->gso_dg_size = blksize; | ||
| /* use the multiple of datagram size for the best efficiency. */ | ||
| if (test->settings->gso_dg_size > 0) { | ||
| test->settings->gso_bf_size = (test->settings->gso_bf_size / test->settings->gso_dg_size) * test->settings->gso_dg_size; | ||
| } else { | ||
| /* If gso_dg_size is 0 (unlimited bandwidth), use default UDP datagram size */ | ||
| test->settings->gso_dg_size = DEFAULT_UDP_BLKSIZE; | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| test->settings->blksize = blksize; | ||
|
|
||
| if (!rate_flag) | ||
|
|
@@ -2449,6 +2479,22 @@ send_parameters(struct iperf_test *test) | |
| cJSON_AddNumberToObject(j, "pacing_timer", test->settings->pacing_timer); | ||
| if (test->settings->burst) | ||
| cJSON_AddNumberToObject(j, "burst", test->settings->burst); | ||
|
|
||
| #ifdef HAVE_UDP_SEGMENT | ||
| /* Send UDP GSO settings from client to server */ | ||
| if (test->protocol->id == Pudp) { | ||
| cJSON_AddNumberToObject(j, "gso", test->settings->gso); | ||
| cJSON_AddNumberToObject(j, "gso_dg_size", test->settings->gso_dg_size); | ||
| cJSON_AddNumberToObject(j, "gso_bf_size", test->settings->gso_bf_size); | ||
| } | ||
| #endif | ||
| #ifdef HAVE_UDP_GRO | ||
| /* Send UDP GRO settings from client to server */ | ||
| if (test->protocol->id == Pudp) { | ||
| cJSON_AddNumberToObject(j, "gro", test->settings->gro); | ||
| cJSON_AddNumberToObject(j, "gro_bf_size", test->settings->gro_bf_size); | ||
| } | ||
| #endif | ||
| if (test->settings->tos) | ||
| cJSON_AddNumberToObject(j, "TOS", test->settings->tos); | ||
| if (test->settings->flowlabel) | ||
|
|
@@ -2572,6 +2618,33 @@ get_parameters(struct iperf_test *test) | |
| test->settings->socket_bufsize = j_p->valueint; | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "len", cJSON_Number)) != NULL) | ||
| test->settings->blksize = j_p->valueint; | ||
|
|
||
| #ifdef HAVE_UDP_SEGMENT | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing this out. Addressed in e63ff17.
This keeps |
||
| /* Accept UDP GSO settings provided by the client */ | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "gso", cJSON_Number)) != NULL) | ||
| test->settings->gso = j_p->valueint; | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "gso_dg_size", cJSON_Number)) != NULL) | ||
| test->settings->gso_dg_size = j_p->valueint; | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "gso_bf_size", cJSON_Number)) != NULL) | ||
| test->settings->gso_bf_size = j_p->valueint; | ||
|
|
||
| /* Backward-compatibility: If client didn't send GSO params, derive from blksize. */ | ||
| if (test->protocol->id == Pudp && test->settings->gso == 1 && test->settings->gso_dg_size == 0) { | ||
| test->settings->gso_dg_size = test->settings->blksize; | ||
| if (test->settings->gso_dg_size > 0) { | ||
| test->settings->gso_bf_size = (test->settings->gso_bf_size / test->settings->gso_dg_size) * test->settings->gso_dg_size; | ||
| } else { | ||
| test->settings->gso_dg_size = DEFAULT_UDP_BLKSIZE; | ||
| } | ||
| } | ||
| #endif | ||
| #ifdef HAVE_UDP_GRO | ||
| /* Accept UDP GRO settings provided by the client */ | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "gro", cJSON_Number)) != NULL) | ||
| test->settings->gro = j_p->valueint; | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "gro_bf_size", cJSON_Number)) != NULL) | ||
| test->settings->gro_bf_size = j_p->valueint; | ||
| #endif | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "bandwidth", cJSON_Number)) != NULL) | ||
| test->settings->rate = j_p->valueint; | ||
| if ((j_p = iperf_cJSON_GetObjectItemType(j, "fqrate", cJSON_Number)) != NULL) | ||
|
|
@@ -3231,6 +3304,15 @@ iperf_defaults(struct iperf_test *testp) | |
| testp->settings->fqrate = 0; | ||
| testp->settings->pacing_timer = DEFAULT_PACING_TIMER; | ||
| testp->settings->burst = 0; | ||
| #ifdef HAVE_UDP_SEGMENT | ||
| testp->settings->gso = 1; /* Enable GSO by default */ | ||
| testp->settings->gso_dg_size = 0; | ||
| testp->settings->gso_bf_size = GSO_BF_MAX_SIZE; | ||
| #endif | ||
| #ifdef HAVE_UDP_GRO | ||
| testp->settings->gro = 1; /* Enable GRO by default */ | ||
| testp->settings->gro_bf_size = GRO_BF_MAX_SIZE; | ||
| #endif | ||
| testp->settings->mss = 0; | ||
| testp->settings->bytes = 0; | ||
| testp->settings->blocks = 0; | ||
|
|
@@ -3544,6 +3626,13 @@ iperf_reset_test(struct iperf_test *test) | |
| test->settings->burst = 0; | ||
| test->settings->mss = 0; | ||
| test->settings->tos = 0; | ||
| #ifdef HAVE_UDP_SEGMENT | ||
| test->settings->gso_dg_size = 0; | ||
| test->settings->gso_bf_size = GSO_BF_MAX_SIZE; | ||
| #endif | ||
| #ifdef HAVE_UDP_GRO | ||
| test->settings->gro_bf_size = GRO_BF_MAX_SIZE; | ||
| #endif | ||
| test->settings->dont_fragment = 0; | ||
| test->zerocopy = 0; | ||
| test->settings->skip_rx_copy = 0; | ||
|
|
@@ -4708,6 +4797,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) | |
| { | ||
| struct iperf_stream *sp; | ||
| int ret = 0; | ||
| int size; | ||
|
|
||
| char template[1024]; | ||
| if (test->tmp_template) { | ||
|
|
@@ -4766,13 +4856,24 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) | |
| free(sp); | ||
| return NULL; | ||
| } | ||
| if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) { | ||
| size = test->settings->blksize; | ||
| #ifdef HAVE_UDP_SEGMENT | ||
| if (test->protocol->id == Pudp && test->settings->gso && (size < test->settings->gso_bf_size)) | ||
| size = test->settings->gso_bf_size; | ||
| #endif | ||
| #ifdef HAVE_UDP_GRO | ||
| if (test->protocol->id == Pudp && test->settings->gro && (size < test->settings->gro_bf_size)) | ||
| size = test->settings->gro_bf_size; | ||
| #endif | ||
| if (sp->test->debug) | ||
| printf("Buffer %d bytes\n", size); | ||
| if (ftruncate(sp->buffer_fd, size) < 0) { | ||
| i_errno = IECREATESTREAM; | ||
| free(sp->result); | ||
| free(sp); | ||
| return NULL; | ||
| } | ||
| sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_SHARED, sp->buffer_fd, 0); | ||
| sp->buffer = (char *) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0); | ||
| if (sp->buffer == MAP_FAILED) { | ||
| i_errno = IECREATESTREAM; | ||
| free(sp->result); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have experience with using gso/gro, but since there are two separate options for
setsockopt(), it may be better to also allow setting these options separately. This can be done by adding anoptional_argument:--no-gsro [<GSO>][/<GRO>], where GSO/GRO are boolean (0/1, T/F, E/N (enable/disable), etc.). The default will be that gso/gro will not be supported as it is implemented now (with the name of the option, this probably means they are set to true by default). For example of how to define and parse option with optional arguments see--cntl-ka(OPT_CNTL_KA).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davidBar-On I hear what you’re saying, and I’m open to changing the option’s behavior. For example, I originally had two distinct options to explicitly enable or disable each feature (
--no-gsoand--no-gro). But then I started thinking: if the kernel supports them and they’re implemented correctly, why wouldn’t we want both enabled by default? The packets on the wire are identical, and the benefits—whether higher throughput or lower CPU usage—are significant.That said, if the consensus is to provide more knobs and finer-grained control, I’m fine with that too.