From 540d2ae4c2f5bc1f763f75895d4eef1ca8b3bd09 Mon Sep 17 00:00:00 2001 From: Brian Tierney Date: Mon, 19 Oct 2009 23:44:36 +0000 Subject: [PATCH] starting adding TCP_INFO stuff. Not yet tested or finished --- src/iperf_api.c | 61 ++++++++++++++++++++++++++++++++++++------------- src/iperf_api.h | 20 ++++++++++++---- src/locale.h | 6 ++++- src/main.c | 8 +++++++ 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 4e01287..f8bcaa8 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1,4 +1,10 @@ +/* + Copyright (c) 2004, 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. +*/ + #include #include #include @@ -7,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -50,7 +56,6 @@ static struct option longopts[] = }; - int all_data_sent(struct iperf_test * test) { @@ -165,13 +170,6 @@ void setnonblocking(int sock) { int opts; - /* - opts = fcntl(sock,F_GETFL); - if (opts < 0) { - perror("fcntl(F_GETFL)"); - exit(EXIT_FAILURE); - } - */ opts = (opts | O_NONBLOCK); if (fcntl(sock, F_SETFL, opts) < 0) @@ -190,6 +188,9 @@ add_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results struct iperf_interval_results *ip = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results)); ip->bytes_transferred = temp.bytes_transferred; ip->interval_duration = temp.interval_duration; +#if defined(linux) || defined(__FreeBSD__) + ip->tcpInfo = temp.tcpInfo; +#endif if (!rp->interval_results) { @@ -214,6 +215,12 @@ display_interval_list(struct iperf_stream_result * rp) while (n) { printf("Interval = %f\tBytes transferred = %llu\n", n->interval_duration, n->bytes_transferred); +#if defined(linux) || defined(__FreeBSD__) + /* TODO: figure out a way to check command line flag for -T option here */ + printf(report_tcpInfo, n->tcp_info.tcpi_snd_cwnd, n->tcp_info.tcpi_snd_ssthresh, + n->tcp_info.tcpi_rcv_ssthresh, n->tcp_info.tcpi_unacked, n->tcp_info.tcpi_sacked, + n->tcp_info.tcpi_lost, n->tcp_info.tcpi_retrans, n->tcp_info.tcpi_fackets); +#endif n = n->next; } } @@ -332,14 +339,14 @@ set_socket_options(struct iperf_stream * sp, struct iperf_test * tp) rc = setsockopt(sp->socket, IPPROTO_TCP, TCP_MAXSEG, (char *) &new_mss, len); if (rc == -1) { - perror("setsockoptBING"); + perror("setsockopt"); return -1; } /* verify results */ rc = getsockopt(sp->socket, IPPROTO_TCP, TCP_MAXSEG, (char *) &new_mss, &len); if (new_mss != tp->default_settings->mss) { - perror("mismatch"); + perror("setsockopt value mismatch"); return -1; } } @@ -402,13 +409,13 @@ iperf_tcp_recv(struct iperf_stream * sp) if (!sp->buffer) { - perror("malloc: unable to allocate receive buffer"); + fprintf(stderr,"receive buffer not allocated"); exit(0); } + do { result = recv(sp->socket, sp->buffer, size, MSG_WAITALL); - } while (result == -1 && errno == EINTR); /* interprete the type of message in packet */ @@ -448,7 +455,8 @@ iperf_udp_recv(struct iperf_stream * sp) if (!sp->buffer) { - perror("malloc: unable to allocate receive buffer"); + fprintf(stderr,"receive buffer not allocated"); + exit(0); } do { @@ -803,6 +811,9 @@ iperf_stats_callback(struct iperf_test * test) { iperf_size_t cumulative_bytes = 0; int i; +#if defined(linux) || defined(__FreeBSD__) + socklen_t tcp_info_length; +#endif struct iperf_stream *sp = test->streams; struct iperf_stream_result *rp = test->streams->result; struct iperf_interval_results *ip, temp; @@ -822,6 +833,14 @@ iperf_stats_callback(struct iperf_test * test) temp.interval_duration = timeval_diff(&sp->result->start_time, &temp.interval_time); +#if defined(linux) || defined(__FreeBSD__) + if (test->tcp_info) { + tcp_info_length = sizeof(tcp_info); + if ( getsockopt( socket, SOL_TCP, TCP_INFO, (void *)&temp.tcp_info, &tcp_info_length ) == 0 ) { + perror("getsockopt"); + } +#endif + gettimeofday(&sp->result->end_time, NULL); add_interval_list(rp, temp); } else @@ -874,7 +893,7 @@ iperf_reporter_callback(struct iperf_test * test) } char *message_final = (char *) malloc((count + 1) * (strlen(report_bw_jitter_loss_header) - + strlen(report_bw_jitter_loss_format) + strlen(report_sum_bw_jitter_loss_format))); + + strlen(report_bw_jitter_loss_format) + strlen(report_sum_bw_jitter_loss_format))); memset(message_final, 0, strlen(message_final)); struct iperf_interval_results *ip = test->streams->result->interval_results; @@ -900,6 +919,13 @@ iperf_reporter_callback(struct iperf_test * test) unit_snprintf(nbuf, UNIT_LEN, (double) (ip->bytes_transferred / (ip->interval_duration - ip_prev->interval_duration)), test->default_settings->unit_format); sprintf(message, report_bw_format, sp->socket, ip_prev->interval_duration, ip->interval_duration, ubuf, nbuf); + +#if defined(linux) || defined(__FreeBSD__) + /* TODO: do something similar to this everywhere */ + sprintf(message, report_tcpInfo, ip->tcp_info.tcpi_snd_cwnd, ip->tcp_info.tcpi_snd_ssthresh, + ip->tcp_info.tcpi_rcv_ssthresh, ip->tcp_info.tcpi_unacked, ip->tcp_info.tcpi_sacked, + ip->tcp_info.tcpi_lost, ip->tcp_info.tcpi_retrans, ip->tcp_info.tcpi_fackets); +#endif } else { sprintf(message, report_bw_header); @@ -1637,7 +1663,7 @@ main(int argc, char **argv) test = iperf_new_test(); iperf_defaults(test); - while ((ch = getopt_long(argc, argv, "c:p:st:uP:b:l:w:i:n:mNM:f:", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "c:p:st:uP:b:l:w:i:n:mNMT:f:", longopts, NULL)) != -1) switch (ch) { case 'c': @@ -1695,6 +1721,9 @@ main(int argc, char **argv) case 'f': test->default_settings->unit_format = *optarg; break; + case 'T': + test->tcp_info = 1; + break; } /* param exchange */ diff --git a/src/iperf_api.h b/src/iperf_api.h index d043d38..17422cb 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -1,3 +1,10 @@ + +/* + Copyright (c) 2004, 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. +*/ + typedef uint64_t iperf_size_t; struct iperf_interval_results @@ -5,6 +12,10 @@ struct iperf_interval_results iperf_size_t bytes_transferred; struct timeval interval_time; float interval_duration; +#if defined(linux) || defined(__FreeBSD__) + /* include getsockopt(TCP_INFO results here for Linux and FreeBSD */ + struct tcp_info tcpInfo; +#endif struct iperf_interval_results *next; void * custom_data; }; @@ -28,12 +39,12 @@ struct iperf_settings int blksize; // -l size of each read/write, in UDP this relates directly to packet_size uint64_t rate; // target data rate, UDP only - int mss; //for TCP MSS + int mss; /* for TCP MSS */ int ttl; int tos; - iperf_size_t bytes; // -n option - char unit_format; // -f - int state; // This is state of a stream/test + iperf_size_t bytes; /* -n option */ + char unit_format; /* -f */ + int state; /* This is state of a stream/test */ char cookie[37]; }; @@ -108,6 +119,7 @@ struct iperf_test int reporter_fd; // file descriptor for reporter int num_streams; // total streams in the test -P + int tcp_info; /* display getsockopt(TCP_INFO) results */ struct iperf_stream *streams; // pointer to list of struct stream struct iperf_settings *default_settings; }; diff --git a/src/locale.h b/src/locale.h index baadd5b..ed7cdf0 100755 --- a/src/locale.h +++ b/src/locale.h @@ -80,7 +80,7 @@ Client/Server:\n\ -M, --mss # set TCP maximum segment size (MTU - 40 bytes)\n\ -N, --nodelay set TCP no delay, disabling Nagle's Algorithm\n\ -V, --IPv6Version Set the domain to IPv6\n\ -\n\ + -T, --tcpinfo Output detailed TCP info\n\ Server specific:\n\ -s, --server run in server mode\n\ -U, --single_udp run in single threaded UDP mode\n\ @@ -106,6 +106,7 @@ Client specific:\n\ -P, --parallel # number of parallel client threads to run\n\ -T, --ttl # time-to-live, for multicast (default 1)\n\ -Z, --linux-congestion set TCP congestion control algorithm (Linux only)\n\ + -T, --tcpinfo Output detailed TCP info (Linux and FreeBSD only)\n\ \n\ Miscellaneous:\n\ -x, --reportexclude [CDMSV] exclude C(connection) D(data) M(multicast) S(settings) V(server) reports\n\ @@ -219,6 +220,9 @@ const char server_reporting[] = const char reportCSV_peer[] = "%s,%u,%s,%u"; +const char report_tcpInfo[] = +"\t TCP Info: CWND=%u SND_SSTHRESH=%u RCV_SSTHRESH=%u UNACKED=%u SACK=%u LOST=%u RETRANS=%u FACK=%u"; + #ifdef HAVE_QUAD_SUPPORT #ifdef HAVE_PRINTF_QD const char reportCSV_bw_format[] = diff --git a/src/main.c b/src/main.c index b76a167..cc362c0 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,14 @@ * iperf3 */ +/* + Copyright (c) 2004, 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. +*/ + + + #include #include #include