From 3021aef828425d342b1c876efb1a53fb6ac85a4b Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Mon, 1 May 2017 14:40:38 -0700 Subject: [PATCH 1/4] Untangle some problems with printing summary statistics. There were (at least) two problems: o The server cannot print summary statistics as seen from the client, because the server has to generate its summaries before receiving any statistics from the client. This shortcoming is somewhat hard-coded into the semantics of messages on the control channel, and probably can't be easily changed. o UDP summary statistics for each stream were ambiguous in that it wasn't clear whether they were intended to apply to the sender or receiver. To fix this, we split UDP summary statistics into two lines, one for the sender side and one for the receiver side. This hopefully eliminates any ambiguity about the statistics. On the server, we don't attempt to print the (not very meaningful and potentially misleading) statistics corresponding to the client. Possible fix for #560. --- src/iperf_api.c | 70 ++++++++++++++++++++++++++++++++++++++++------ src/iperf_locale.c | 2 ++ src/iperf_locale.h | 4 ++- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index f0d2bdd..e6ad842 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -2556,20 +2556,32 @@ iperf_print_results(struct iperf_test *test) unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { if (test->sender_has_retransmits) { - /* Summary, TCP with retransmits. */ + /* Sender summary, TCP and SCTP with retransmits. */ if (test->json_output) cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt))); else - iperf_printf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); + if (test->role == 's' && !test->sender) { + if (test->verbose) + iperf_printf(test, report_sender_not_available_format, sp->socket); + } + else { + iperf_printf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); + } } else { - /* Summary, TCP without retransmits. */ + /* Sender summary, TCP and SCTP without retransmits. */ if (test->json_output) cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8)); else - iperf_printf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_sender); + if (test->role == 's' && !test->sender) { + if (test->verbose) + iperf_printf(test, report_sender_not_available_format, sp->socket); + } + else { + iperf_printf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_sender); + } } } else { - /* Summary, UDP. */ + /* Sender summary, UDP. */ if (sp->packet_count - sp->omitted_packet_count > 0) { lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sp->packet_count - sp->omitted_packet_count); } @@ -2577,11 +2589,28 @@ iperf_print_results(struct iperf_test *test) lost_percent = 0.0; } if (test->json_output) + /* + * For hysterical raisins, we only emit one JSON + * object for the UDP summary, and it contains + * information for both the sender and receiver + * side. + */ cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets))); else { - iperf_printf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, ""); - if (test->role == 'c') - iperf_printf(test, report_datagrams, sp->socket, (sp->packet_count - sp->omitted_packet_count)); + /* + * Due to ordering of messages on the control channel, + * the server cannot report on client-side summary + * statistics. If we're the server, omit one set of + * summary statistics to avoid giving meaningless + * results. + */ + if (test->role == 's' && !test->sender) { + if (test->verbose) + iperf_printf(test, report_sender_not_available_format, sp->socket); + } + else { + iperf_printf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, 0, (sp->packet_count - sp->omitted_packet_count), (double) 0, report_sender); + } if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0) iperf_printf(test, report_sum_outoforder, start_time, end_time, (sp->outoforder_packets - sp->omitted_outoforder_packets)); } @@ -2606,10 +2635,33 @@ iperf_print_results(struct iperf_test *test) bandwidth = (double) bytes_received / (double) end_time; unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { + /* Receiver summary, TCP and SCTP */ if (test->json_output) cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8)); else - iperf_printf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_receiver); + if (test->role == 's' && test->sender) { + if (test->verbose) + iperf_printf(test, report_receiver_not_available_format, sp->socket); + } + else { + iperf_printf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_receiver); + } + } + else { + /* + * Receiver summary, UDP. Note that JSON was emitted with + * the sender summary, so we only deal with human-readable + * data here. + */ + if (! test->json_output) { + if (test->role == 's' && test->sender) { + if (test->verbose) + iperf_printf(test, report_receiver_not_available_format, sp->socket); + } + else { + iperf_printf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, report_receiver); + } + } } } } diff --git a/src/iperf_locale.c b/src/iperf_locale.c index 6fd6f0b..d72005a 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -383,6 +383,8 @@ const char report_local[] = "local"; const char report_remote[] = "remote"; const char report_sender[] = "sender"; const char report_receiver[] = "receiver"; +const char report_sender_not_available_format[] = "[%3d] (sender statistics not available)\n"; +const char report_receiver_not_available_format[] = "[%3d] (receiver statistics not available)\n"; #if defined(linux) const char report_tcpInfo[] = diff --git a/src/iperf_locale.h b/src/iperf_locale.h index e1c8383..f07bd6e 100644 --- a/src/iperf_locale.h +++ b/src/iperf_locale.h @@ -1,5 +1,5 @@ /* - * iperf, Copyright (c) 2014, The Regents of the University of + * iperf, Copyright (c) 2014, 2017, 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. @@ -95,6 +95,8 @@ extern const char report_local[] ; extern const char report_remote[] ; extern const char report_sender[] ; extern const char report_receiver[] ; +extern const char report_sender_not_available_format[]; +extern const char report_receiver_not_available_format[]; extern const char report_tcpInfo[] ; extern const char report_tcpInfo[] ; From d25e1b78fd042713d66b5aab5115de91aea0bf31 Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Tue, 2 May 2017 13:20:31 -0700 Subject: [PATCH 2/4] Try to report more accurate ending statistics. Basically the client side was using only its measured test duration to compute figures such as bitrate, but the server's test duration could be different due to network delays/jitter. So we make sure that the test durations (for each stream) are passed in the test results and used appropriately when we print statistics for the sender and receiver. Towards #560, also this could help towards #238. --- src/iperf.h | 2 ++ src/iperf_api.c | 64 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 5073ad9..c565f42 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -102,6 +102,8 @@ struct iperf_stream_result struct timeval start_time; struct timeval end_time; struct timeval start_time_fixed; + double sender_time; + double receiver_time; TAILQ_HEAD(irlisthead, iperf_interval_results) interval_results; void *data; }; diff --git a/src/iperf_api.c b/src/iperf_api.c index e6ad842..c28ad42 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1585,6 +1585,7 @@ send_results(struct iperf_test *test) int sender_has_retransmits; iperf_size_t bytes_transferred; int retransmits; + double start_time, end_time; j = cJSON_CreateObject(); if (j == NULL) { @@ -1652,6 +1653,12 @@ send_results(struct iperf_test *test) cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter); cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error); cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count); + + start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); + end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); + cJSON_AddNumberToObject(j_stream, "start_time", start_time); + cJSON_AddNumberToObject(j_stream, "end_time", end_time); + } } if (r == 0 && test->debug) { @@ -1690,6 +1697,7 @@ get_results(struct iperf_test *test) cJSON *j_errors; cJSON *j_packets; cJSON *j_server_output; + cJSON *j_start_time, *j_end_time; int sid, cerror, pcount; double jitter; iperf_size_t bytes_transferred; @@ -1737,6 +1745,8 @@ get_results(struct iperf_test *test) j_jitter = cJSON_GetObjectItem(j_stream, "jitter"); j_errors = cJSON_GetObjectItem(j_stream, "errors"); j_packets = cJSON_GetObjectItem(j_stream, "packets"); + j_start_time = cJSON_GetObjectItem(j_stream, "start_time"); + j_end_time = cJSON_GetObjectItem(j_stream, "end_time"); if (j_id == NULL || j_bytes == NULL || j_retransmits == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) { i_errno = IERECVRESULTS; r = -1; @@ -1758,9 +1768,30 @@ get_results(struct iperf_test *test) sp->cnt_error = cerror; sp->packet_count = pcount; sp->result->bytes_received = bytes_transferred; + /* + * We have to handle the possibilty that + * start_time and end_time might not be + * available; this is the case for older (pre-3.2) + * servers. + * + * We need to have result structure members to hold + * the both sides' start_time and end_time. + */ + if (j_start_time && j_end_time) { + sp->result->receiver_time = j_end_time->valuedouble - j_start_time->valuedouble; + } + else { + sp->result->receiver_time = 0.0; + } } else { sp->result->bytes_sent = bytes_transferred; sp->result->stream_retrans = retransmits; + if (j_start_time && j_end_time) { + sp->result->sender_time = j_end_time->valuedouble - j_start_time->valuedouble; + } + else { + sp->result->sender_time = 0.0; + } } } } @@ -2496,6 +2527,7 @@ iperf_print_results(struct iperf_test *test) iperf_size_t bytes_sent, total_sent = 0; iperf_size_t bytes_received, total_received = 0; double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent; + double sender_time, receiver_time; double bandwidth; /* print final summary for all intervals */ @@ -2528,6 +2560,14 @@ iperf_print_results(struct iperf_test *test) */ if (sp) { end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); + if (test->sender) { + sp->result->sender_time = end_time; + } + else { + sp->result->receiver_time = end_time; + } + sender_time = sp->result->sender_time; + receiver_time = sp->result->receiver_time; SLIST_FOREACH(sp, &test->streams, streams) { if (test->json_output) { json_summary_stream = cJSON_CreateObject(); @@ -2552,32 +2592,32 @@ iperf_print_results(struct iperf_test *test) } unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A'); - bandwidth = (double) bytes_sent / (double) end_time; + bandwidth = (double) bytes_sent / (double) sender_time; unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { if (test->sender_has_retransmits) { /* Sender summary, TCP and SCTP with retransmits. */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt))); + cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt))); else if (test->role == 's' && !test->sender) { if (test->verbose) iperf_printf(test, report_sender_not_available_format, sp->socket); } else { - iperf_printf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); + iperf_printf(test, report_bw_retrans_format, sp->socket, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); } } else { /* Sender summary, TCP and SCTP without retransmits. */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8)); + cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8)); else if (test->role == 's' && !test->sender) { if (test->verbose) iperf_printf(test, report_sender_not_available_format, sp->socket); } else { - iperf_printf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_sender); + iperf_printf(test, report_bw_format, sp->socket, start_time, sender_time, ubuf, nbuf, report_sender); } } } else { @@ -2595,7 +2635,7 @@ iperf_print_results(struct iperf_test *test) * information for both the sender and receiver * side. */ - cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets))); + cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets))); else { /* * Due to ordering of messages on the control channel, @@ -2609,10 +2649,10 @@ iperf_print_results(struct iperf_test *test) iperf_printf(test, report_sender_not_available_format, sp->socket); } else { - iperf_printf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, 0, (sp->packet_count - sp->omitted_packet_count), (double) 0, report_sender); + iperf_printf(test, report_bw_udp_format, sp->socket, start_time, sender_time, ubuf, nbuf, sp->jitter * 1000.0, 0, (sp->packet_count - sp->omitted_packet_count), (double) 0, report_sender); } if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0) - iperf_printf(test, report_sum_outoforder, start_time, end_time, (sp->outoforder_packets - sp->omitted_outoforder_packets)); + iperf_printf(test, report_sum_outoforder, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets)); } } @@ -2632,19 +2672,19 @@ iperf_print_results(struct iperf_test *test) } unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A'); - bandwidth = (double) bytes_received / (double) end_time; + bandwidth = (double) bytes_received / (double) receiver_time; unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { /* Receiver summary, TCP and SCTP */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8)); + cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8)); else if (test->role == 's' && test->sender) { if (test->verbose) iperf_printf(test, report_receiver_not_available_format, sp->socket); } else { - iperf_printf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_receiver); + iperf_printf(test, report_bw_format, sp->socket, start_time, receiver_time, ubuf, nbuf, report_receiver); } } else { @@ -2659,7 +2699,7 @@ iperf_print_results(struct iperf_test *test) iperf_printf(test, report_receiver_not_available_format, sp->socket); } else { - iperf_printf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, report_receiver); + iperf_printf(test, report_bw_udp_format, sp->socket, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, report_receiver); } } } From 3f6325cff0f80dd6a4436ff61dcb3b6304604236 Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Tue, 2 May 2017 19:36:20 -0700 Subject: [PATCH 3/4] Silence a warning over an uninitialized variable. --- src/iperf_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index c28ad42..99d8dd7 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -2526,7 +2526,7 @@ iperf_print_results(struct iperf_test *test) struct iperf_stream *sp = NULL; iperf_size_t bytes_sent, total_sent = 0; iperf_size_t bytes_received, total_received = 0; - double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent; + double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent = 0.0; double sender_time, receiver_time; double bandwidth; From 7d151314d88cdf5b9541836013fa2ce901ca33a2 Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Wed, 3 May 2017 14:57:39 -0700 Subject: [PATCH 4/4] Fold in the 3.1.X release notes and begin draft 3.2 release notes. --- RELEASE_NOTES | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7949f0b..193cd03 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,218 @@ +== iperf 3.2 2017-05-XX == + +* User-visible changes + + * Authentication via a username/password mechanism is now an + optional way of limiting access to an iperf3 server (#517). + + * Ending statistics are less ambituous for UDP and also now use + correct test durations for all protocols (#560, #238). + + * Application-level bandwidth pacing (--bandwidth option) is now + checked every millisecond, instead of of every tenth of a second, + to provide smoother traffic behavior when using application + pacing. (#460) + + * A new --dscp option allows specifying the DSCP value to be used + for outgoing packets (#508). The TOS byte value is now printed in + the JSON output (#226). + + * Congestion window data on FreeBSD is now computed correctly (#465, + #475, #338). + + * The T/t suffixes for terabytes/terabits are now accepted for + quantities where suffixes are supported, such as --bandwidth + (#402). + + * Sanity checks for UDP send sizes have been added (#390), and + existing checks on the --window option have been improved (#557). + + * The TCP rttvar value is now available in the JSON (#534). + +* Developer-visible changes + + * Various warnings and build fixes (#551, #518). + + * Some dead code has been removed. + +== iperf 3.1.7 2017-03-06 == + +iperf 3.1.7 is functionally identical to iperf 3.1.6. Its only +changes consist of updated documentation files and text in the RPM +spec file. + +== iperf 3.1.6 2017-02-02 == + +The release notes for iperf 3.1.6 describe changes, including bug +fixes and new functionality, made since iperf 3.1.5. + +* User-visible changes + + * Specifying --fq-rate or --no-fq-socket-pacing on a system where + these options are not supported now generate an error instead of a + warning. This change makes diagnosing issues related to pacing + more apparent. + + * Fixed a bug where two recently-added diagnostic messages spammed + the JSON output on UDP tests. + +== iperf 3.1.5 2017-01-12 == + +The release notes for iperf 3.1.5 describe changes, including bug +fixes and new functionality, made since iperf 3.1.4. + +Compatibility note: Fair-queueing is now specified differently in +iperf 3.1.5 than in prior versions (which include 3.1.3 and 3.1.4). + +Compatibility note: UDP tests may yield different results from all +prior versions of iperf3 (through 3.1.4) due to the new default UDP +sending size. + +* User-visible changes + + * The fair-queueing per-socket based pacing available on recent + Linux systems has been reimplemented with a different user + interface (#325, #467, #488). The --bandwidth command-line flag + now controls only the application-level pacing, as was the case in + iperf 3.1.2 and all earlier versions. Fair-queueing per-socket + based pacing is now controlled via a new --fq-rate command-line + flag. Note that TCP and UDP tests may use --bandwidth, --fq-rate, + both flags, or neither flag. SCTP tests currently support + --bandwidth only. The --no-fq-socket-pacing flag, which was + introduced in iperf 3.1.3, has now been deprecated, and is + equivalent to --fq-rate=0. iperf3 now reacts more gracefully if + --no-fq-socket-pacing or --fq-rate are specified on platforms that + don't support these options. + + For UDP tests, note that the default --bandwidth is 1 Mbps. Using + the fair-queueing-based pacing will probably require explicitly + setting both --bandwidth and --fq-rate, preferably to the same + value. (While setting different values for --bandwidth and + --fq-rate can certainly be done, the results can range from + entertaining to perplexing.) + + * iperf3 now chooses a more sane default UDP send size (#496, #498). + The former default (8KB) caused IP packet fragmentation on paths + having smaller MTUs (including any Ethernet network not configured + for jumbo frames). This could have effects ranging from increased + burstiness, to packet loss, to complete failure of the test. + iperf3 now attempts to use the MSS of the control connection to + determine a default UDP send size if no sending length was + explicitly specified with --length. + + * Several checks are now made when setting the socket buffer sizes + with the -w option, to verify that the settings have been applied + correctly. The results of these checks can been seen when the + --debug flag is specified. (#356) + + * A --forceflush flag has been added to flush the output stream + after every statistics reporting interval. + +* Developer-visible changes + + * A systemd service file has been added (#340, #430). + +== iperf 3.1.4 2016-10-31 == + +The release notes for iperf 3.1.4 describe changes, including bug +fixes and new functionality, made since iperf 3.1.3. + +* User-visible changes + + * On systems that support setting the congestion control algorithm, + iperf3 now keeps track of the congestion control algorithm and + print it in the JSON output in the members sender_tcp_congestion + and receiver_tcp_congestion (issue #461). A few bugs (probably + not user-visible) with setting the congestion control algorithm + were also fixed. + +* Developer-visible changes + + * Fixed a buffer overflow in the cJSON library (issue #466). It is + not believed that this bug created any security vulnerabilities in + the context of iperf3. + + * Travis CI builds are now enabled on this codeline (pull request #424). + + * Various bug fixes (issue #459, pull request #429, issue #388). + +== iperf 3.1.3 2016-06-08 == + +The release notes for iperf 3.1.3 describe changes, including bug +fixes and new functionality, made since iperf 3.1.2. + +* Security + + * Fixed a buffer overflow / heap corruption issue that could occur + if a malformed JSON string was passed on the control channel. In + theory, this vulnerability could be leveraged to create a heap + exploit. This issue, present in the cJSON library, was already + fixed upstream, so was addressed in iperf3 by importing a newer + version of cJSON (plus local ESnet modifications). Discovered and + reported by Dave McDaniel, Cisco Talos. Cross-references: + TALOS-CAN-0164, ESNET-SECADV-2016-0001, CVE-2016-4303. + +* User-visible changes + + * On supported platforms (recent Linux), iperf3 can use + fair-queueing-based per-socket pacing instead of its own + application-level pacing for the --bandwidth option. + Application-level pacing can be forced with the + -no-fq-socket-pacing flag. + + * A bug that could show negative loss counters with --udp and --omit + has been fixed (issue #412, pull request #414). + + * Error handling has been made slightly more robust. Also, the + iperf3 server will no longer exit after five consecutive errors, + but will only exit for certain types of errors that prevent it + from participating in any tests at all. + +* Developer-visible changes + + * Fixed the build on FreeBSD 11-CURRENT (issue #413). + + * Fixed various coding errors (issue #423, issue #425). + +== iperf 3.1.2 2016-02-01 == + +The release notes for iperf 3.1.2 describe changes, including bug +fixes and new functionality, made since iperf 3.1.1. + +* User-visible changes + + * Fixed a bug that caused nan values to be emitted (incorrectly) + into JSON, particularly at the end of UDP tests (issue #278). + + * Fixed a bug that caused the wrong value to be printed for + out-of-order UDP packets (issue #329). + + * Added a contrib/ directory containing a few submitted graphing + scripts. + +* Developer-visible changes + +== iperf 3.1.1 2015-11-19 == + +The release notes for iperf 3.1.1 describe changes and new +functionality in iperf 3.1.1, but not present in 3.1. + +* User-visible changes + + * Some markup fixes have been made in the manpages for Debian + compatibility (issue #291). + + * A bug where the -T title option was not being output correctly + in JSON output has been fixed (issue #292). + + * Argument handling for some command-line options has been improved + (issue #316). + +* Developer-visible changes + + * A regression with C++ compatibility in one of the iperf header + files has been fixed (issue #323). + == iperf 3.1 2015-10-16 == The release notes for iperf 3.1 describe changes and new