diff --git a/src/iperf.h b/src/iperf.h index 6763049a6..164589dc3 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -318,6 +318,7 @@ struct iperf_test char *title; /* -T option */ char *extra_data; /* --extra-data */ char *congestion; /* -C option */ + char *congestion_server; /* -C option - used only in the client side to pass the `congestion` value to the server */ char *congestion_used; /* what was actually used */ char *remote_congestion_used; /* what the other side used */ char *pidfile; /* -P option */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 937dd34fe..85c18d918 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -428,6 +428,12 @@ iperf_get_test_congestion_control(struct iperf_test* ipt) return ipt->congestion; } +char* +iperf_get_test_congestion_control_server(struct iperf_test* ipt) +{ + return ipt->congestion_server; +} + int iperf_get_test_mss(struct iperf_test *ipt) { @@ -848,6 +854,12 @@ iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc) ipt->congestion = strdup(cc); } +void +iperf_set_test_congestion_server_control_server(struct iperf_test* ipt, char* cc) +{ + ipt->congestion_server = strdup(cc); +} + void iperf_set_test_mss(struct iperf_test *ipt, int mss) { @@ -1128,10 +1140,8 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"affinity", required_argument, NULL, 'A'}, #endif /* HAVE_CPU_AFFINITY */ {"title", required_argument, NULL, 'T'}, -#if defined(HAVE_TCP_CONGESTION) {"congestion", required_argument, NULL, 'C'}, {"linux-congestion", required_argument, NULL, 'C'}, -#endif /* HAVE_TCP_CONGESTION */ #if defined(HAVE_SCTP_H) {"sctp", no_argument, NULL, OPT_SCTP}, {"nstreams", required_argument, NULL, OPT_NUMSTREAMS}, @@ -1613,13 +1623,30 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) client_flag = 1; break; case 'C': -#if defined(HAVE_TCP_CONGESTION) - test->congestion = strdup(optarg); + if (optarg) { + slash = strchr(optarg, '/'); + if (slash) { + *slash = '\0'; + ++slash; + if (strlen(slash) > 0) { + test->congestion_server = strdup(slash); + } + } + if (strlen(optarg) > 0) { + test->congestion = strdup(optarg); + if (!test->congestion_server) { + test->congestion_server = strdup(test->congestion); + } + } + } client_flag = 1; -#else /* HAVE_TCP_CONGESTION */ - i_errno = IEUNIMP; - return -1; +#ifndef HAVE_TCP_CONGESTION + if (test->congestion) { // Client does not support congestion control, so should not be set for the client + i_errno = IECONGESTIONSUPPORT; + return -1; + } #endif /* HAVE_TCP_CONGESTION */ + break; case 'd': test->debug = 1; @@ -1885,6 +1912,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) return -1; } + // Warning if congestion control algorithm was set to non-sending client or server + if (test->congestion != NULL && test->mode == RECEIVER) { + warning("Congestion control algorithm was set to non-sending client"); + } + if (test->congestion == NULL && test->congestion_server != NULL && test->mode == SENDER) { + warning("Congestion control algorithm was set to non-sending server"); + } + /* Set Total-rate average interval to multiplicity of State interval */ if (test->settings->bitrate_limit_interval != 0) { test->settings->bitrate_limit_stats_per_interval = @@ -2373,8 +2408,8 @@ send_parameters(struct iperf_test *test) cJSON_AddStringToObject(j, "title", test->title); if (test->extra_data) cJSON_AddStringToObject(j, "extra_data", test->extra_data); - if (test->congestion) - cJSON_AddStringToObject(j, "congestion", test->congestion); + if (test->congestion_server) + cJSON_AddStringToObject(j, "congestion", test->congestion_server); if (test->congestion_used) cJSON_AddStringToObject(j, "congestion_used", test->congestion_used); if (test->get_server_output) @@ -3280,6 +3315,8 @@ iperf_free_test(struct iperf_test *test) free(test->extra_data); if (test->congestion) free(test->congestion); + if (test->congestion_server) + free(test->congestion_server); if (test->congestion_used) free(test->congestion_used); if (test->remote_congestion_used) @@ -3395,6 +3432,8 @@ iperf_reset_test(struct iperf_test *test) if (test->congestion) free(test->congestion); + if (test->congestion_server) + free(test->congestion_server); test->congestion = NULL; if (test->remote_congestion_used) free(test->remote_congestion_used); diff --git a/src/iperf_api.h b/src/iperf_api.h index cd82e6f9b..5186959a3 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -169,6 +169,7 @@ int iperf_get_test_no_delay( struct iperf_test* ipt ); int iperf_get_test_connect_timeout( struct iperf_test* ipt ); int iperf_get_dont_fragment( struct iperf_test* ipt ); char* iperf_get_test_congestion_control(struct iperf_test* ipt); +char* iperf_get_test_congestion_control_server(struct iperf_test* ipt); int iperf_get_test_mss(struct iperf_test* ipt); int iperf_get_mapped_v4(struct iperf_test* ipt); @@ -215,6 +216,7 @@ void iperf_set_test_bidirectional( struct iperf_test* ipt, int bidirectional) void iperf_set_test_no_delay( struct iperf_test* ipt, int no_delay); void iperf_set_dont_fragment( struct iperf_test* ipt, int dont_fragment ); void iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc); +void iperf_set_test_congestion_control_server(struct iperf_test* ipt, char* cc); void iperf_set_test_mss(struct iperf_test* ipt, int mss); void iperf_set_mapped_v4(struct iperf_test* ipt, const int val); void iperf_set_on_new_stream_callback(struct iperf_test* ipt, void (*callback)(struct iperf_stream *)); @@ -495,6 +497,7 @@ enum { IESETCNTLKAINTERVAL = 157, // Unable to set/get socket keepalive TCP retry interval (TCP_KEEPINTVL) option IESETCNTLKACOUNT = 158, // Unable to set/get socket keepalive TCP number of retries (TCP_KEEPCNT) option IEPTHREADSIGMASK=159, // Unable to initialize sub thread signal mask (check perror) + IECONGESTIONSUPPORT = 160, // Client does not support setting TCP congestion control algorithm /* Stream errors */ IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror) IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror) diff --git a/src/iperf_error.c b/src/iperf_error.c index f76ad5f21..03e896f56 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -449,6 +449,9 @@ iperf_strerror(int int_errno) snprintf(errstr, len, "unable to update timer"); perr = 1; break; + case IECONGESTIONSUPPORT: + snprintf(errstr, len, "Client does not support setting TCP congestion control algorithm"); + break; case IESETCONGESTION: snprintf(errstr, len, "unable to set TCP_CONGESTION: " "Supplied congestion control algorithm not supported on this host"); diff --git a/src/iperf_locale.c b/src/iperf_locale.c index c59fd116b..717efce70 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -192,7 +192,10 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" " (indirectly sets TCP window size)\n" #if defined(HAVE_TCP_CONGESTION) - " -C, --congestion set TCP congestion control algorithm (Linux and FreeBSD only)\n" + " -C, --congestion [/] set TCP congestion control algorithm (Linux and FreeBSD only)\n" + " for client & server, optional for the server\n" +#else /* HAVE_TCP_CONGESTION */ + " -C, --congestion / set server TCP congestion control algorithm\n" #endif /* HAVE_TCP_CONGESTION */ " -M, --set-mss # set TCP/SCTP maximum segment size (MTU - 40 bytes)\n" " -N, --no-delay set TCP/SCTP no delay, disabling Nagle's Algorithm\n" diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 958bd0557..c73e43c61 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -533,7 +533,7 @@ iperf_run_server(struct iperf_test *test) int result, s; int send_streams_accepted, rec_streams_accepted; int streams_to_send = 0, streams_to_rec = 0; -#if defined(HAVE_TCP_CONGESTION) +#if defined(HAVE_TCP_CONGESTION) || defined(HAVE_TCP_USER_TIMEOUT) int saved_errno; #endif /* HAVE_TCP_CONGESTION */ fd_set read_set, write_set;