PATCH: Add support for binding to a network device.
I am attaching a patch to iperf 2.0.2 that allows binding hard to
a local interface, using the SO_BINDTODEVICE socket option. This
can be useful in cases where simply binding to a local IP address
does not suffice to cause the packets to be sent out the
associated interface.
Please apply this to future iperf releases if it meets your approval.
Thanks,
Ben
--
Ben Greear <greearb --at-- candelatech.com>
Candela Technologies Inc http://www.candelatech.com
diff -urN iperf-2.0.2/include/Settings.hpp iperf-2.0.2.sts/include/Settings.hpp
--- iperf-2.0.2/include/Settings.hpp 2005-05-02 13:09:26.000000000 -0700
+++ iperf-2.0.2.sts/include/Settings.hpp 2007-05-18 14:46:31.000000000 -0700
@@ -112,6 +112,7 @@
char* mHost; // -c
char* mLocalhost; // -B
char* mOutputFileName; // -o
+ char* mBindDev; // -E eth0, --bind_dev eth0
FILE* Extractor_file;
ReportHeader* reporthdr;
MultiHeader* multihdr;
diff -urN iperf-2.0.2/src/Client.cpp iperf-2.0.2.sts/src/Client.cpp
--- iperf-2.0.2/src/Client.cpp 2005-05-02 13:09:27.000000000 -0700
+++ iperf-2.0.2.sts/src/Client.cpp 2007-05-18 14:49:28.000000000 -0700
@@ -318,6 +318,16 @@
WARN_errno( rc == SOCKET_ERROR, "bind" );
}
+#ifndef WIN32
+ // Bind to a local device. This will fail if not user root and may only work on Linux.
+ if ( mSettings->mBindDev != NULL ) {
+ if (setsockopt(mSettings->mSock, SOL_SOCKET, SO_BINDTODEVICE,
+ mSettings->mBindDev, 16)) {
+ WARN_errno( rc == SOCKET_ERROR, "setsockopt-SO_BINDTODEVICE" );
+ }
+ }
+#endif
+
// connect socket
rc = connect( mSettings->mSock, (sockaddr*) &mSettings->peer,
SockAddr_get_sizeof_sockaddr( &mSettings->peer ));
diff -urN iperf-2.0.2/src/Listener.cpp iperf-2.0.2.sts/src/Listener.cpp
--- iperf-2.0.2/src/Listener.cpp 2005-05-02 13:09:27.000000000 -0700
+++ iperf-2.0.2.sts/src/Listener.cpp 2007-05-18 14:49:30.000000000 -0700
@@ -323,6 +323,16 @@
Socklen_t len = sizeof(boolean);
setsockopt( mSettings->mSock, SOL_SOCKET, SO_REUSEADDR, (char*) &boolean, len );
+#ifndef WIN32
+ // Bind to a local device. This will fail if not user root and may only work on Linux.
+ if ( mSettings->mBindDev != NULL ) {
+ if (setsockopt(mSettings->mSock, SOL_SOCKET, SO_BINDTODEVICE,
+ mSettings->mBindDev, 16)) {
+ WARN_errno( rc == SOCKET_ERROR, "setsockopt-SO_BINDTODEVICE" );
+ }
+ }
+#endif
+
// bind socket to server address
#ifdef WIN32
if ( SockAddr_isMulticast( &mSettings->local ) ) {
diff -urN iperf-2.0.2/src/Locale.c iperf-2.0.2.sts/src/Locale.c
--- iperf-2.0.2/src/Locale.c 2005-05-02 13:09:27.000000000 -0700
+++ iperf-2.0.2.sts/src/Locale.c 2007-05-18 14:52:29.000000000 -0700
@@ -139,6 +139,7 @@
-u, --udp use UDP rather than TCP\n\
-w, --window #[KM] TCP window size (socket buffer size)\n\
-B, --bind <host> bind to <host>, an interface or multicast address\n\
+ -E, --bind-dev <dev> bind to <device>, for example eth0 This only does the SO_BINDTODEVICE call.\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\
-N, --nodelay set TCP no delay, disabling Nagle's Algorithm\n\
diff -urN iperf-2.0.2/src/Settings.cpp iperf-2.0.2.sts/src/Settings.cpp
--- iperf-2.0.2/src/Settings.cpp 2005-05-02 13:09:27.000000000 -0700
+++ iperf-2.0.2.sts/src/Settings.cpp 2007-05-18 14:37:51.000000000 -0700
@@ -108,6 +108,7 @@
{"bind", required_argument, NULL, 'B'},
{"compatibility", no_argument, NULL, 'C'},
{"daemon", no_argument, NULL, 'D'},
+{"bind-dev", required_argument, NULL, 'E'},
{"file_input", required_argument, NULL, 'F'},
{"stdin_input", no_argument, NULL, 'I'},
{"mss", required_argument, NULL, 'M'},
@@ -151,6 +152,7 @@
{"IPERF_BIND", required_argument, NULL, 'B'},
{"IPERF_COMPAT", no_argument, NULL, 'C'},
{"IPERF_DAEMON", no_argument, NULL, 'D'},
+{"IPERF_BIND_DEV", required_argument, NULL, 'E'},
{"IPERF_FILE_INPUT", required_argument, NULL, 'F'},
{"IPERF_STDIN_INPUT", no_argument, NULL, 'I'},
{"IPERF_MSS", required_argument, NULL, 'M'},
@@ -167,7 +169,7 @@
#define SHORT_OPTIONS()
-const char short_options[] = "1b:c:df:hi:l:mn:o:p:rst:uvw:x:y:B:CDF:IL:M:NP:RS:T:UVW";
+const char short_options[] = "1b:c:df:hi:l:mn:o:p:rst:uvw:x:y:B:CDE:F:IL:M:NP:RS:T:UVW";
/* -------------------------------------------------------------------
* defaults
@@ -229,7 +231,7 @@
main->mTTL = 1; // -T, link-local TTL
//main->mDomain = kMode_IPv4; // -V,
//main->mSuggestWin = false; // -W, Suggest the window size.
-
+ //main->mBindDev = NULL // -E --bind-dev
} // end Settings
void Settings_Copy( thread_Settings *from, thread_Settings **into ) {
@@ -251,6 +253,10 @@
(*into)->mFileName = new char[ strlen(from->mFileName) + 1];
strcpy( (*into)->mFileName, from->mFileName );
}
+ if ( from->mBindDev != NULL ) {
+ (*into)->mBindDev = new char[ strlen(from->mBindDev) + 1];
+ strcpy( (*into)->mBindDev, from->mBindDev );
+ }
// Zero out certain entries
(*into)->mTID = thread_zeroid();
(*into)->runNext = NULL;
@@ -266,6 +272,7 @@
DELETE_ARRAY( mSettings->mLocalhost );
DELETE_ARRAY( mSettings->mFileName );
DELETE_ARRAY( mSettings->mOutputFileName );
+ DELETE_ARRAY( mSettings->mBindDev );
DELETE_PTR( mSettings );
} // end ~Settings
@@ -566,6 +573,11 @@
setDaemon( mExtSettings );
break;
+ case 'E' : // Bind to a particular device.
+ mExtSettings->mBindDev = new char[strlen(optarg)+1];
+ strcpy( mExtSettings->mBindDev, optarg);
+ break;
+
case 'F' : // Get the input for the data stream from a file
if ( mExtSettings->mThreadMode != kMode_Client ) {
fprintf( stderr, warn_invalid_server_option, option );
@@ -713,12 +725,17 @@
(*listener)->mHost = NULL;
(*listener)->mLocalhost = NULL;
(*listener)->mOutputFileName = NULL;
+ (*listener)->mBindDev = NULL;
(*listener)->mMode = kTest_Normal;
(*listener)->mThreadMode = kMode_Listener;
if ( client->mHost != NULL ) {
(*listener)->mHost = new char[strlen( client->mHost ) + 1];
strcpy( (*listener)->mHost, client->mHost );
}
+ if ( client->mBindDev != NULL ) {
+ (*listener)->mBindDev = new char[strlen( client->mBindDev ) + 1];
+ strcpy( (*listener)->mBindDev, client->mBindDev );
+ }
if ( client->mLocalhost != NULL ) {
(*listener)->mLocalhost = new char[strlen( client->mLocalhost ) + 1];
strcpy( (*listener)->mLocalhost, client->mLocalhost );
@@ -770,6 +787,7 @@
}
(*client)->mFileName = NULL;
(*client)->mHost = NULL;
+ (*client)->mBindDev = NULL;
(*client)->mLocalhost = NULL;
(*client)->mOutputFileName = NULL;
(*client)->mMode = ((flags & RUN_NOW) == 0 ?
@@ -779,6 +797,10 @@
(*client)->mLocalhost = new char[strlen( server->mLocalhost ) + 1];
strcpy( (*client)->mLocalhost, server->mLocalhost );
}
+ if ( server->mBindDev != NULL ) {
+ (*client)->mBindDev = new char[strlen( server->mBindDev ) + 1];
+ strcpy( (*client)->mBindDev, server->mBindDev );
+ }
(*client)->mHost = new char[REPORT_ADDRLEN];
if ( ((sockaddr*)&server->peer)->sa_family == AF_INET ) {
inet_ntop( AF_INET, &((sockaddr_in*)&server->peer)->sin_addr,