1
1

Added -C / --linux-congestion.

Also a few other bugfixes I ran across.
Этот коммит содержится в:
Jef Poskanzer 2013-12-13 19:57:52 -08:00
родитель adec7fe48b
Коммит 62bfa88ceb
8 изменённых файлов: 99 добавлений и 12 удалений

Просмотреть файл

@ -156,6 +156,7 @@ struct iperf_test
char *diskfile_name; /* -F option */ char *diskfile_name; /* -F option */
int affinity, server_affinity; /* -A option */ int affinity, server_affinity; /* -A option */
char *title; /* -T option */ char *title; /* -T option */
char *congestion; /* -C option */
int ctrl_sck; int ctrl_sck;
int listener; int listener;

Просмотреть файл

@ -123,6 +123,9 @@ period.
.TP .TP
.BR -T ", " --title " \fIstr\fR" .BR -T ", " --title " \fIstr\fR"
Prefix every output line with this string. Prefix every output line with this string.
.TP
.BR -C ", " --linux-congestion " \fIalgo\fR"
Set the congestion control algorithm (linux only).
.SH AUTHORS .SH AUTHORS
Iperf was originally written by Mark Gates and Alex Warshavsky. Iperf was originally written by Mark Gates and Alex Warshavsky.

Просмотреть файл

@ -519,14 +519,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"file", required_argument, NULL, 'F'}, {"file", required_argument, NULL, 'F'},
{"affinity", required_argument, NULL, 'A'}, {"affinity", required_argument, NULL, 'A'},
{"title", required_argument, NULL, 'T'}, {"title", required_argument, NULL, 'T'},
{"help", no_argument, NULL, 'h'}, #if defined(linux)
{"linux-congestion", required_argument, NULL, 'C'},
/* XXX: The following ifdef needs to be split up. linux-congestion is not
* necessarily supported by systems that support tos.
*/
#ifdef ADD_WHEN_SUPPORTED
{"linux-congestion", required_argument, NULL, 'L'},
#endif #endif
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
int flag; int flag;
@ -536,7 +532,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
blksize = 0; blksize = 0;
server_flag = client_flag = rate_flag = 0; server_flag = client_flag = rate_flag = 0;
while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:l:P:Rw:B:M:N46S:L:ZO:F:A:T:h", longopts, NULL)) != -1) { while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:h", longopts, NULL)) != -1) {
switch (flag) { switch (flag) {
case 'p': case 'p':
test->server_port = atoi(optarg); test->server_port = atoi(optarg);
@ -629,8 +625,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
client_flag = 1; client_flag = 1;
break; break;
case 'B': case 'B':
test->bind_address = (char *) malloc(strlen(optarg)+1); test->bind_address = strdup(optarg);
strncpy(test->bind_address, optarg, strlen(optarg)+1);
break; break;
case 'M': case 'M':
test->settings->mss = atoi(optarg); test->settings->mss = atoi(optarg);
@ -707,6 +702,15 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
sprintf(test->title, "%s: ", optarg); sprintf(test->title, "%s: ", optarg);
client_flag = 1; client_flag = 1;
break; break;
case 'C':
#if defined(linux)
test->congestion = strdup(optarg);
client_flag = 1;
#else /* linux */
i_errno = IEUNIMP;
return -1;
#endif /* linux */
break;
case 'h': case 'h':
default: default:
usage_long(); usage_long();
@ -1023,6 +1027,8 @@ send_parameters(struct iperf_test *test)
cJSON_AddIntToObject(j, "flowlabel", test->settings->flowlabel); cJSON_AddIntToObject(j, "flowlabel", test->settings->flowlabel);
if (test->title) if (test->title)
cJSON_AddStringToObject(j, "title", test->title); cJSON_AddStringToObject(j, "title", test->title);
if (test->congestion)
cJSON_AddStringToObject(j, "congestion", test->congestion);
if (JSON_write(test->ctrl_sck, j) < 0) { if (JSON_write(test->ctrl_sck, j) < 0) {
i_errno = IESENDPARAMS; i_errno = IESENDPARAMS;
r = -1; r = -1;
@ -1078,6 +1084,8 @@ get_parameters(struct iperf_test *test)
test->settings->flowlabel = j_p->valueint; test->settings->flowlabel = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL) if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
test->title = strdup(j_p->valuestring); test->title = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
test->congestion = strdup(j_p->valuestring);
if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits()) if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
test->sender_has_retransmits = 1; test->sender_has_retransmits = 1;
cJSON_Delete(j); cJSON_Delete(j);
@ -1385,6 +1393,7 @@ iperf_defaults(struct iperf_test *testp)
testp->affinity = -1; testp->affinity = -1;
testp->server_affinity = -1; testp->server_affinity = -1;
testp->title = NULL; testp->title = NULL;
testp->congestion = NULL;
testp->server_port = PORT; testp->server_port = PORT;
testp->ctrl_sck = -1; testp->ctrl_sck = -1;
testp->prot_listener = -1; testp->prot_listener = -1;
@ -1465,11 +1474,15 @@ iperf_free_test(struct iperf_test *test)
iperf_free_stream(sp); iperf_free_stream(sp);
} }
free(test->server_hostname); if (test->server_hostname)
free(test->bind_address); free(test->server_hostname);
if (test->bind_address)
free(test->bind_address);
free(test->settings); free(test->settings);
if (test->title) if (test->title)
free(test->title); free(test->title);
if (test->congestion)
free(test->congestion);
if (test->omit_timer != NULL) if (test->omit_timer != NULL)
tmr_cancel(test->omit_timer); tmr_cancel(test->omit_timer);
if (test->timer != NULL) if (test->timer != NULL)
@ -1533,8 +1546,10 @@ iperf_reset_test(struct iperf_test *test)
test->duration = DURATION; test->duration = DURATION;
test->server_affinity = -1; test->server_affinity = -1;
test->title = NULL; test->title = NULL;
test->congestion = NULL;
test->state = 0; test->state = 0;
test->server_hostname = NULL; test->server_hostname = NULL;
test->bind_address = NULL;
test->ctrl_sck = -1; test->ctrl_sck = -1;
test->prot_listener = -1; test->prot_listener = -1;

Просмотреть файл

@ -274,6 +274,7 @@ enum {
IEPROTOCOL = 131, // Protocol does not exist IEPROTOCOL = 131, // Protocol does not exist
IEAFFINITY = 132, // Unable to set CPU affinity (check perror) IEAFFINITY = 132, // Unable to set CPU affinity (check perror)
IEDAEMON = 133, // Unable to become a daemon process IEDAEMON = 133, // Unable to become a daemon process
IESETCONGESTION = 134, // Unable to set TCP_CONGESTION
/* Stream errors */ /* Stream errors */
IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror) IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror)
IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror) IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror)

Просмотреть файл

@ -284,6 +284,10 @@ iperf_strerror(int i_errno)
snprintf(errstr, len, "unable to update timer"); snprintf(errstr, len, "unable to update timer");
perr = 1; perr = 1;
break; break;
case IESETCONGESTION:
snprintf(errstr, len, "unable to set TCP_CONGESTION");
perr = 1;
break;
} }
if (herr || perr) if (herr || perr)

Просмотреть файл

@ -259,6 +259,7 @@ iperf_test_reset(struct iperf_test *test)
test->affinity = -1; test->affinity = -1;
test->server_affinity = -1; test->server_affinity = -1;
test->title = NULL; test->title = NULL;
test->congestion = NULL;
test->state = 0; test->state = 0;
test->server_hostname = NULL; test->server_hostname = NULL;

Просмотреть файл

@ -120,6 +120,7 @@ iperf_tcp_listen(struct iperf_test *test)
struct addrinfo hints, *res; struct addrinfo hints, *res;
char portstr[6]; char portstr[6];
int s, opt; int s, opt;
int saved_errno;
s = test->listener; s = test->listener;
@ -146,8 +147,10 @@ iperf_tcp_listen(struct iperf_test *test)
if (test->no_delay) { if (test->no_delay) {
opt = 1; opt = 1;
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(res); freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETNODELAY; i_errno = IESETNODELAY;
return -1; return -1;
} }
@ -155,30 +158,50 @@ iperf_tcp_listen(struct iperf_test *test)
// XXX: Setting MSS is very buggy! // XXX: Setting MSS is very buggy!
if ((opt = test->settings->mss)) { if ((opt = test->settings->mss)) {
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(res); freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETMSS; i_errno = IESETMSS;
return -1; return -1;
} }
} }
if ((opt = test->settings->socket_bufsize)) { if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(res); freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETBUF; i_errno = IESETBUF;
return -1; return -1;
} }
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(res); freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETBUF; i_errno = IESETBUF;
return -1; return -1;
} }
} }
#if defined(linux)
if (test->congestion) {
if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
saved_errno = errno;
close(s);
freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETCONGESTION;
return -1;
}
}
#endif
opt = 1; opt = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(res); freeaddrinfo(res);
errno = saved_errno;
i_errno = IEREUSEADDR; i_errno = IEREUSEADDR;
return -1; return -1;
} }
@ -191,8 +214,10 @@ iperf_tcp_listen(struct iperf_test *test)
} }
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(res); freeaddrinfo(res);
errno = saved_errno;
i_errno = IESTREAMLISTEN; i_errno = IESTREAMLISTEN;
return -1; return -1;
} }
@ -221,6 +246,7 @@ iperf_tcp_connect(struct iperf_test *test)
struct addrinfo hints, *local_res, *server_res; struct addrinfo hints, *local_res, *server_res;
char portstr[6]; char portstr[6];
int s, opt; int s, opt;
int saved_errno;
if (test->bind_address) { if (test->bind_address) {
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
@ -253,9 +279,11 @@ iperf_tcp_connect(struct iperf_test *test)
if (test->bind_address) { if (test->bind_address) {
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(local_res); freeaddrinfo(local_res);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESTREAMCONNECT; i_errno = IESTREAMCONNECT;
return -1; return -1;
} }
@ -266,30 +294,38 @@ iperf_tcp_connect(struct iperf_test *test)
if (test->no_delay) { if (test->no_delay) {
opt = 1; opt = 1;
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETNODELAY; i_errno = IESETNODELAY;
return -1; return -1;
} }
} }
if ((opt = test->settings->mss)) { if ((opt = test->settings->mss)) {
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETMSS; i_errno = IESETMSS;
return -1; return -1;
} }
} }
if ((opt = test->settings->socket_bufsize)) { if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETBUF; i_errno = IESETBUF;
return -1; return -1;
} }
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETBUF; i_errno = IESETBUF;
return -1; return -1;
} }
@ -297,8 +333,10 @@ iperf_tcp_connect(struct iperf_test *test)
#if defined(linux) #if defined(linux)
if (test->settings->flowlabel) { if (test->settings->flowlabel) {
if (server_res->ai_addr->sa_family != AF_INET6) { if (server_res->ai_addr->sa_family != AF_INET6) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETFLOW; i_errno = IESETFLOW;
return -1; return -1;
} else { } else {
@ -315,8 +353,10 @@ iperf_tcp_connect(struct iperf_test *test)
memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16); memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) { if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETFLOW; i_errno = IESETFLOW;
return -1; return -1;
} }
@ -324,8 +364,10 @@ iperf_tcp_connect(struct iperf_test *test)
opt = 1; opt = 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) { if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETFLOW; i_errno = IESETFLOW;
return -1; return -1;
} }
@ -333,9 +375,24 @@ iperf_tcp_connect(struct iperf_test *test)
} }
#endif #endif
#if defined(linux)
if (test->congestion) {
if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
saved_errno = errno;
close(s);
freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETCONGESTION;
return -1;
}
}
#endif
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
saved_errno = errno;
close(s); close(s);
freeaddrinfo(server_res); freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESTREAMCONNECT; i_errno = IESTREAMCONNECT;
return -1; return -1;
} }
@ -344,7 +401,9 @@ iperf_tcp_connect(struct iperf_test *test)
/* Send cookie for verification */ /* Send cookie for verification */
if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
saved_errno = errno;
close(s); close(s);
errno = saved_errno;
i_errno = IESENDCOOKIE; i_errno = IESENDCOOKIE;
return -1; return -1;
} }

Просмотреть файл

@ -94,6 +94,9 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
" -R, --reverse run in reverse mode (server sends, client receives)\n" " -R, --reverse run in reverse mode (server sends, client receives)\n"
" -w, --window #[KMG] TCP window size (socket buffer size)\n" " -w, --window #[KMG] TCP window size (socket buffer size)\n"
" -B, --bind <host> bind to a specific interface or multicast address\n" " -B, --bind <host> bind to a specific interface or multicast address\n"
#if defined(linux)
" -C, --linux-congestion <algo> set TCP congestion control algorithm (Linux only)\n"
#endif
" -M, --set-mss # set TCP maximum segment size (MTU - 40 bytes)\n" " -M, --set-mss # set TCP maximum segment size (MTU - 40 bytes)\n"
" -N, --nodelay set TCP no delay, disabling Nagle's Algorithm\n" " -N, --nodelay set TCP no delay, disabling Nagle's Algorithm\n"
" -4, --version4 only use IPv4\n" " -4, --version4 only use IPv4\n"