This adds plug-able TCP congestion control support to iperf.
u_char mTTL; // -T
char mUDP;
char free;
+ char *congAlgo; // -A
} Transfer_Info;
typedef struct Connection_Info {
// chars
char mFormat; // -f
int mTTL; // -T
+ char *congAlgo; // -A
char pad1[2];
// structs or miscellaneous
struct sockaddr_storage peer; // remote part of socket
#define SHUT_RDWR 2
#endif // SHUT_RD
+/* Plug-able TCP congestion control algorithm */
+#ifndef TCP_CONGESTION
+#define TCP_CONGESTION 13 /* include/linux/tcp.h */
+#endif
+
/* DCCP-specific definitions */
#include <linux/dccp.h>
#ifndef SOCK_DCCP
-#define IPERF_VERSION "2.0.2 with support for DCCP"
+#define IPERF_VERSION "2.0.2 with support for DCCP and TCP CC"
#define IPERF_VERSION_DATE "20th Jan 2009"
-u, --udp use UDP as transport protocol\n\
-d, --dccp use DCCP as transport protocol\n\
-w, --window #[KM] TCP window size (socket buffer size)\n\
+ -A, --algorithm set TCP congestion control algorithm\n\
-B, --bind <host> bind to <host>, an interface or multicast address\n\
-C, --compatibility for use with older versions does not sent extra msgs\n\
-M, --mss # set TCP maximum segment size (MTU - 40 bytes)\n\
WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_NODELAY" );
}
#endif
+ if ( inSettings->congAlgo ) {
+ len = strlen( inSettings->congAlgo );
+ rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION,
+ inSettings->congAlgo , len );
+ WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_CONGESTION" );
+ }
+
} else {
rc = set_buffer_sock_size(inSettings->mSock, inSettings->mWinSize,
inSettings->mThreadMode == kMode_Client);
printf( warn_window_requested, buffer );
}
printf( "\n" );
+
+ if (data->mProtocol == kProto_TCP) {
+ char *cong_requested = data->info.congAlgo,
+ cong[64];
+ Socklen_t len = sizeof(cong);
+
+ if (getsockopt(data->info.transferID, IPPROTO_TCP, TCP_CONGESTION, cong, &len) < 0) {
+ fprintf(stderr, "WARNING: cannot determine TCP congestion control algorithm (err: %d %s)\n",
+ errno, strerror(errno));
+ } else {
+ printf("TCP congestion control algorithm: %s", cong[0] == '\0' ? "default" : cong);
+
+ if (data->info.congAlgo && strcmp(cong, data->info.congAlgo))
+ printf(" (NOT \"%s\"!)", data->info.congAlgo);
+ printf("\n");
+ }
+ }
+
printf( seperator_line );
}
data->info.transferID = agent->mSock;
data->info.groupID = (agent->multihdr != NULL ? agent->multihdr->groupID
: -1);
+ data->info.congAlgo = agent->congAlgo;
data->type = TRANSFER_REPORT;
if ( agent->mInterval != 0.0 ) {
struct timeval *interval = &data->intervalTime;
data = &reporthdr->report;
data->info.transferID = agent->mSock;
data->info.groupID = -1;
+ data->info.congAlgo = agent->congAlgo;
} else {
FAIL(1, "Out of Memory!!\n", agent);
}
data->mMcastIface = agent->mMcastIface;
data->info.mFormat = agent->mFormat;
data->info.mTTL = agent->mTTL;
+ data->info.congAlgo = agent->congAlgo;
data->connection.peer = agent->peer;
data->connection.local = agent->local;
{"reportstyle",required_argument, NULL, 'y'},
// more esoteric options
+{"algorithm", required_argument, NULL, 'A'},
{"bind", required_argument, NULL, 'B'},
{"compatibility", no_argument, NULL, 'C'},
{"daemon", no_argument, NULL, 'D'},
{"IPERF_REPORTSTYLE",required_argument, NULL, 'y'},
// more esoteric options
+{"IPERF_CC", required_argument, NULL, 'A'},
{"IPERF_BIND", required_argument, NULL, 'B'},
{"IPERF_COMPAT", no_argument, NULL, 'C'},
{"IPERF_DAEMON", no_argument, NULL, 'D'},
#define SHORT_OPTIONS()
const char short_options[] =
- "12b::c:df:hi:j:l:mn:o:p:rst:uvw:x:y:B:CDF:IJ:L:M:NP:RS:T:UV:W";
+ "12b::c:df:hi:j:l:mn:o:p:rst:uvw:x:y:A:B:CDF:IJ:L:M:NP:RS:T:UV:W";
/* -------------------------------------------------------------------
* defaults
// more esoteric options
+ case 'A': // set TCP congestion control algorithm
+ mExtSettings->congAlgo = new char[ strlen( optarg ) + 1 ];
+ strcpy( mExtSettings->congAlgo, optarg );
+ break;
+
case 'B': // specify bind address
mExtSettings->mLocalhost = new char[ strlen( optarg ) + 1 ];
strcpy( mExtSettings->mLocalhost, optarg );