From 7eeaa1cb070de41ff41d2d881ddb094db7f43352 Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Thu, 22 Sep 2016 13:34:52 -0700 Subject: [PATCH] First try at issue #461. First, realize that we've been setting the congestion control (CC) algorithm unnecessarily; rather than doing it for all listening or connecting sockets, do it just for those sockets that are being used for TCP test streams. Record the CC algorithm in use (this handles the case where a CC algorithm hasn't been specified), and have the client and server exchange this information. Report the CC algorithms that were used (note that it's theoretically possible for the two ends of the test to be using different algorithms, if no algorithm was explicitly specified and the two end hosts have different defaults, or if one side allows setting the CC algorithm and the other doesn't). Committing to a branch to make it easier to test this code on a wider combination of systems. --- src/iperf.h | 2 ++ src/iperf_api.c | 35 ++++++++++++++++++++++++++++++++++- src/iperf_client_api.c | 32 +++++++++++++++++++++++++++++++- src/iperf_server_api.c | 32 ++++++++++++++++++++++++++++++++ src/iperf_tcp.c | 21 --------------------- 5 files changed, 99 insertions(+), 23 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 5e56e48..235065c 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -220,6 +220,8 @@ struct iperf_test #endif /* HAVE_CPUSET_SETAFFINITY */ char *title; /* -T option */ char *congestion; /* -C option */ + char *congestion_used; /* what was actually used */ + char *remote_congestion_used; /* what the other side used */ char *pidfile; /* -P option */ char *logfile; /* --logfile option */ diff --git a/src/iperf_api.c b/src/iperf_api.c index ee751a2..b364835 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1334,6 +1334,8 @@ send_parameters(struct iperf_test *test) cJSON_AddStringToObject(j, "title", test->title); if (test->congestion) cJSON_AddStringToObject(j, "congestion", test->congestion); + if (test->congestion_used) + cJSON_AddStringToObject(j, "congestion_used", test->congestion_used); if (test->get_server_output) cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test)); if (test->udp_counters_64bit) @@ -1414,6 +1416,8 @@ get_parameters(struct iperf_test *test) test->title = strdup(j_p->valuestring); if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL) test->congestion = strdup(j_p->valuestring); + if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL) + test->congestion_used = strdup(j_p->valuestring); if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL) iperf_set_test_get_server_output(test, 1); if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL) @@ -1455,6 +1459,9 @@ send_results(struct iperf_test *test) else sender_has_retransmits = test->sender_has_retransmits; cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits); + if ( test->congestion_used ) { + cJSON_AddStringToObject(j, "congestion_used", test->congestion_used); + } /* If on the server and sending server output, then do this */ if (test->role == 's' && test->get_server_output) { @@ -1529,6 +1536,7 @@ get_results(struct iperf_test *test) cJSON *j_cpu_util_total; cJSON *j_cpu_util_user; cJSON *j_cpu_util_system; + cJSON *j_remote_congestion_used; cJSON *j_sender_has_retransmits; int result_has_retransmits; cJSON *j_streams; @@ -1637,6 +1645,12 @@ get_results(struct iperf_test *test) } } } + + j_remote_congestion_used = cJSON_GetObjectItem(j, "congestion_used"); + if (j_remote_congestion_used != NULL) { + test->remote_congestion_used = strdup(j_remote_congestion_used->valuestring); + } + cJSON_Delete(j); } return r; @@ -1833,6 +1847,8 @@ iperf_defaults(struct iperf_test *testp) #endif /* HAVE_CPUSET_SETAFFINITY */ testp->title = NULL; testp->congestion = NULL; + testp->congestion_used = NULL; + testp->remote_congestion_used = NULL; testp->server_port = PORT; testp->ctrl_sck = -1; testp->prot_listener = -1; @@ -1965,6 +1981,10 @@ iperf_free_test(struct iperf_test *test) free(test->title); if (test->congestion) free(test->congestion); + if (test->congestion_used) + free(test->congestion_used); + if (test->remote_congestion_used) + free(test->remote_congestion_used); if (test->omit_timer != NULL) tmr_cancel(test->omit_timer); if (test->timer != NULL) @@ -2500,11 +2520,24 @@ iperf_print_results(struct iperf_test *test) } } - if (test->json_output) + if (test->json_output) { cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host_total: %f host_user: %f host_system: %f remote_total: %f remote_user: %f remote_system: %f", (double) test->cpu_util[0], (double) test->cpu_util[1], (double) test->cpu_util[2], (double) test->remote_cpu_util[0], (double) test->remote_cpu_util[1], (double) test->remote_cpu_util[2])); + if (test->congestion_used) { + cJSON_AddStringToObject(test->json_end, "local_tcp_congestion", test->congestion_used); + } + if (test->remote_congestion_used) { + cJSON_AddStringToObject(test->json_end, "remote_tcp_congestion", test->remote_congestion_used); + } + } else { if (test->verbose) { iprintf(test, report_cpu, report_local, test->sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, test->sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]); + if (test->congestion_used) { + iprintf(test, "local_tcp_congestion %s\n", test->congestion_used); + } + if (test->remote_congestion_used) { + iprintf(test, "remote_tcp_congestion %s\n", test->remote_congestion_used); + } } /* Print server output if we're on the client and it was requested/provided */ diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index f19f6f1..9df7ee8 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -1,5 +1,5 @@ /* - * iperf, Copyright (c) 2014, 2015, The Regents of the University of + * iperf, Copyright (c) 2014, 2015, 2016, The Regents of the University of * California, through Lawrence Berkeley National Laboratory (subject * to receipt of any required approvals from the U.S. Dept. of * Energy). All rights reserved. @@ -43,6 +43,11 @@ #include "net.h" #include "timer.h" +#if defined(HAVE_TCP_CONGESTION) +#if !defined(TCP_CA_NAME_MAX) +#define TCP_CA_NAME_MAX 16 +#endif /* TCP_CA_NAME_MAX */ +#endif /* HAVE_TCP_CONGESTION */ int iperf_create_streams(struct iperf_test *test) @@ -59,6 +64,31 @@ iperf_create_streams(struct iperf_test *test) if ((s = test->protocol->connect(test)) < 0) return -1; +#if defined(HAVE_TCP_CONGESTION) + if (test->protocol->id == Ptcp) { + if (test->congestion) { + if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { + close(s); + i_errno = IESETCONGESTION; + return -1; + } + } + { + int len = TCP_CA_NAME_MAX; + char ca[TCP_CA_NAME_MAX + 1]; + if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { + close(s); + i_errno = IESETCONGESTION; + return -1; + } + test->congestion_used = strdup(ca); + if (test->debug) { + printf("Congestion algorithm is %s\n", test->congestion_used); + } + } + } +#endif /* HAVE_TCP_CONGESTION */ + if (test->sender) FD_SET(s, &test->write_set); else diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 65661d7..10adc07 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -62,6 +62,11 @@ #include "iperf_util.h" #include "iperf_locale.h" +#if defined(HAVE_TCP_CONGESTION) +#if !defined(TCP_CA_NAME_MAX) +#define TCP_CA_NAME_MAX 16 +#endif /* TCP_CA_NAME_MAX */ +#endif /* HAVE_TCP_CONGESTION */ int iperf_server_listen(struct iperf_test *test) @@ -510,6 +515,33 @@ iperf_run_server(struct iperf_test *test) return -1; } +#if defined(HAVE_TCP_CONGESTION) + if (test->protocol->id == Ptcp) { + if (test->congestion) { + if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { + close(s); + cleanup_server(test); + i_errno = IESETCONGESTION; + return -1; + } + } + { + int len = TCP_CA_NAME_MAX; + char ca[TCP_CA_NAME_MAX + 1]; + if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { + close(s); + cleanup_server(test); + i_errno = IESETCONGESTION; + return -1; + } + test->congestion_used = strdup(ca); + if (test->debug) { + printf("Congestion algorithm is %s\n", test->congestion_used); + } + } + } +#endif /* HAVE_TCP_CONGESTION */ + if (!is_closed(s)) { sp = iperf_new_stream(test, s); if (!sp) { diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index ac3b392..a2eb85b 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -235,16 +235,6 @@ iperf_tcp_listen(struct iperf_test *test) } printf("SO_SNDBUF is %u\n", opt); } -#if defined(HAVE_TCP_CONGESTION) - if (test->congestion) { - if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { - close(s); - freeaddrinfo(res); - i_errno = IESETCONGESTION; - return -1; - } - } -#endif /* HAVE_TCP_CONGESTION */ #if defined(HAVE_SO_MAX_PACING_RATE) /* If socket pacing is available and not disabled, try it. */ if (! test->no_fq_socket_pacing) { @@ -473,17 +463,6 @@ iperf_tcp_connect(struct iperf_test *test) } #endif /* HAVE_FLOWLABEL */ -#if defined(HAVE_TCP_CONGESTION) - if (test->congestion) { - if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { - close(s); - freeaddrinfo(server_res); - i_errno = IESETCONGESTION; - return -1; - } - } -#endif /* HAVE_TCP_CONGESTION */ - #if defined(HAVE_SO_MAX_PACING_RATE) /* If socket pacing is available and not disabled, try it. */ if (! test->no_fq_socket_pacing) {