1
1
This lets iperf work better with multi-homed machines and
VRF.

Fixes #1089.

Based on a patch by Ben Greear <greearb@candelatech.com> via PR #817.

Co-authored-by: Ben Greear <greearb@candelatech.com>
Этот коммит содержится в:
Bruce A. Mah 2020-12-22 15:52:24 -08:00 коммит произвёл GitHub
родитель d1260e6f94
Коммит 21581a7216
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 182 добавлений и 34 удалений

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

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.16.2 from Makefile.am. # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@ # @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc. # Copyright (C) 1994-2020 Free Software Foundation, Inc.
@ -204,6 +204,8 @@ am__relativize = \
DIST_ARCHIVES = $(distdir).tar.gz DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best GZIP_ENV = --best
DIST_TARGETS = dist-gzip DIST_TARGETS = dist-gzip
# Exists only to be overridden by the user if desired.
AM_DISTCHECK_DVI_TARGET = dvi
distuninstallcheck_listfiles = find . -type f -print distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
@ -629,7 +631,7 @@ distcheck: dist
$(DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=../.. --prefix="$$dc_install_base" \ --srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
&& $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \

13
aclocal.m4 поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
# generated automatically by aclocal 1.16.2 -*- Autoconf -*- # generated automatically by aclocal 1.16.3 -*- Autoconf -*-
# Copyright (C) 1996-2020 Free Software Foundation, Inc. # Copyright (C) 1996-2020 Free Software Foundation, Inc.
@ -9059,7 +9059,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.16' [am__api_version='1.16'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro. dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.16.2], [], m4_if([$1], [1.16.3], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
]) ])
@ -9075,7 +9075,7 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.16.2])dnl [AM_AUTOMAKE_VERSION([1.16.3])dnl
m4_ifndef([AC_AUTOCONF_VERSION], m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
@ -9763,12 +9763,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
AC_REQUIRE_AUX_FILE([missing])dnl AC_REQUIRE_AUX_FILE([missing])dnl
if test x"${MISSING+set}" != xset; then if test x"${MISSING+set}" != xset; then
case $am_aux_dir in MISSING="\${SHELL} '$am_aux_dir/missing'"
*\ * | *\ *)
MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
*)
MISSING="\${SHELL} $am_aux_dir/missing" ;;
esac
fi fi
# Use eval to expand $SHELL # Use eval to expand $SHELL
if eval "$MISSING --is-lightweight"; then if eval "$MISSING --is-lightweight"; then

38
configure поставляемый
Просмотреть файл

@ -2531,12 +2531,7 @@ program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
am_aux_dir=`cd "$ac_aux_dir" && pwd` am_aux_dir=`cd "$ac_aux_dir" && pwd`
if test x"${MISSING+set}" != xset; then if test x"${MISSING+set}" != xset; then
case $am_aux_dir in MISSING="\${SHELL} '$am_aux_dir/missing'"
*\ * | *\ *)
MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
*)
MISSING="\${SHELL} $am_aux_dir/missing" ;;
esac
fi fi
# Use eval to expand $SHELL # Use eval to expand $SHELL
if eval "$MISSING --is-lightweight"; then if eval "$MISSING --is-lightweight"; then
@ -13950,6 +13945,37 @@ $as_echo "#define HAVE_SO_MAX_PACING_RATE 1" >>confdefs.h
fi fi
# Check for SO_BINDTODEVICE sockopt (believed to be Linux only)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SO_BINDTODEVICE socket option" >&5
$as_echo_n "checking SO_BINDTODEVICE socket option... " >&6; }
if ${iperf3_cv_header_so_bindtodevice+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/socket.h>
#ifdef SO_BINDTODEVICE
yes
#endif
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "yes" >/dev/null 2>&1; then :
iperf3_cv_header_so_bindtodevice=yes
else
iperf3_cv_header_so_bindtodevice=no
fi
rm -f conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $iperf3_cv_header_so_bindtodevice" >&5
$as_echo "$iperf3_cv_header_so_bindtodevice" >&6; }
if test "x$iperf3_cv_header_so_bindtodevice" = "xyes"; then
$as_echo "#define HAVE_SO_BINDTODEVICE 1" >>confdefs.h
fi
# Check if we need -lrt for clock_gettime # Check if we need -lrt for clock_gettime
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
$as_echo_n "checking for library containing clock_gettime... " >&6; } $as_echo_n "checking for library containing clock_gettime... " >&6; }

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

@ -224,6 +224,19 @@ if test "x$iperf3_cv_header_so_max_pacing_rate" = "xyes"; then
AC_DEFINE([HAVE_SO_MAX_PACING_RATE], [1], [Have SO_MAX_PACING_RATE sockopt.]) AC_DEFINE([HAVE_SO_MAX_PACING_RATE], [1], [Have SO_MAX_PACING_RATE sockopt.])
fi fi
# Check for SO_BINDTODEVICE sockopt (believed to be Linux only)
AC_CACHE_CHECK([SO_BINDTODEVICE socket option],
[iperf3_cv_header_so_bindtodevice],
AC_EGREP_CPP(yes,
[#include <sys/socket.h>
#ifdef SO_BINDTODEVICE
yes
#endif
],iperf3_cv_header_so_bindtodevice=yes,iperf3_cv_header_so_bindtodevice=no))
if test "x$iperf3_cv_header_so_bindtodevice" = "xyes"; then
AC_DEFINE([HAVE_SO_BINDTODEVICE], [1], [Have SO_BINDTODEVICE sockopt.])
fi
# Check if we need -lrt for clock_gettime # Check if we need -lrt for clock_gettime
AC_SEARCH_LIBS(clock_gettime, [rt posix4]) AC_SEARCH_LIBS(clock_gettime, [rt posix4])
# Check for clock_gettime support # Check for clock_gettime support

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

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.16.2 from Makefile.am. # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@ # @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc. # Copyright (C) 1994-2020 Free Software Foundation, Inc.

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

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.16.2 from Makefile.am. # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@ # @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc. # Copyright (C) 1994-2020 Free Software Foundation, Inc.
@ -479,6 +479,7 @@ am__set_TESTS_bases = \
bases='$(TEST_LOGS)'; \ bases='$(TEST_LOGS)'; \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases` bases=`echo $$bases`
AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
RECHECK_LOGS = $(TEST_LOGS) RECHECK_LOGS = $(TEST_LOGS)
AM_RECURSIVE_TARGETS = check recheck AM_RECURSIVE_TARGETS = check recheck
TEST_SUITE_LOG = test-suite.log TEST_SUITE_LOG = test-suite.log
@ -1565,7 +1566,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
fi; \ fi; \
echo "$${col}$$br$${std}"; \ echo "$${col}$$br$${std}"; \
echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
echo "$${col}$$br$${std}"; \ echo "$${col}$$br$${std}"; \
create_testsuite_report --maybe-color; \ create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \ echo "$$col$$br$$std"; \

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

@ -40,6 +40,7 @@
# define _GNU_SOURCE # define _GNU_SOURCE
#endif #endif
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <net/if.h> // for IFNAMSIZ
#if defined(HAVE_CPUSET_SETAFFINITY) #if defined(HAVE_CPUSET_SETAFFINITY)
#include <sys/param.h> #include <sys/param.h>
@ -258,6 +259,7 @@ struct iperf_test
char *server_hostname; /* -c option */ char *server_hostname; /* -c option */
char *tmp_template; char *tmp_template;
char *bind_address; /* first -B option */ char *bind_address; /* first -B option */
char *bind_dev; /* bind to network device */
TAILQ_HEAD(xbind_addrhead, xbind_entry) xbind_addrs; /* all -X opts */ TAILQ_HEAD(xbind_addrhead, xbind_entry) xbind_addrs; /* all -X opts */
int bind_port; /* --cport option */ int bind_port; /* --cport option */
int server_port; int server_port;

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

@ -139,6 +139,10 @@ CPUs).
.TP .TP
.BR -B ", " --bind " \fIhost\fR" .BR -B ", " --bind " \fIhost\fR"
bind to the specific interface associated with address \fIhost\fR. bind to the specific interface associated with address \fIhost\fR.
.BR --bind-dev " \fIdev\R"
bind to the specified network interface.
This option uses SO_BINDTODEVICE, and may require root permissions.
(Available on Linux and possibly other systems.)
.TP .TP
.BR -V ", " --verbose " " .BR -V ", " --verbose " "
give more detailed output give more detailed output

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

@ -339,6 +339,12 @@ iperf_get_test_bind_address(struct iperf_test *ipt)
return ipt->bind_address; return ipt->bind_address;
} }
char *
iperf_get_test_bind_dev(struct iperf_test *ipt)
{
return ipt->bind_dev;
}
int int
iperf_get_test_udp_counters_64bit(struct iperf_test *ipt) iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)
{ {
@ -661,6 +667,12 @@ iperf_set_test_bind_address(struct iperf_test *ipt, const char *bnd_address)
ipt->bind_address = strdup(bnd_address); ipt->bind_address = strdup(bnd_address);
} }
void
iperf_set_test_bind_dev(struct iperf_test *ipt, char *bnd_dev)
{
ipt->bind_dev = strdup(bnd_dev);
}
void void
iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit) iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)
{ {
@ -894,6 +906,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"bidir", no_argument, NULL, OPT_BIDIRECTIONAL}, {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL},
{"window", required_argument, NULL, 'w'}, {"window", required_argument, NULL, 'w'},
{"bind", required_argument, NULL, 'B'}, {"bind", required_argument, NULL, 'B'},
#if defined(HAVE_SO_BINDTODEVICE)
{"bind-dev", required_argument, NULL, OPT_BIND_DEV},
#endif /* HAVE_SO_BINDTODEVICE */
{"cport", required_argument, NULL, OPT_CLIENT_PORT}, {"cport", required_argument, NULL, OPT_CLIENT_PORT},
{"set-mss", required_argument, NULL, 'M'}, {"set-mss", required_argument, NULL, 'M'},
{"no-delay", no_argument, NULL, 'N'}, {"no-delay", no_argument, NULL, 'N'},
@ -1147,6 +1162,11 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
case 'B': case 'B':
test->bind_address = strdup(optarg); test->bind_address = strdup(optarg);
break; break;
#if defined (HAVE_SO_BINDTODEVICE)
case OPT_BIND_DEV:
test->bind_dev = strdup(optarg);
break;
#endif /* HAVE_SO_BINDTODEVICE */
case OPT_CLIENT_PORT: case OPT_CLIENT_PORT:
portno = atoi(optarg); portno = atoi(optarg);
if (portno < 1 || portno > 65535) { if (portno < 1 || portno > 65535) {
@ -2635,6 +2655,8 @@ iperf_free_test(struct iperf_test *test)
free(test->tmp_template); free(test->tmp_template);
if (test->bind_address) if (test->bind_address)
free(test->bind_address); free(test->bind_address);
if (test->bind_dev)
free(test->bind_dev);
if (!TAILQ_EMPTY(&test->xbind_addrs)) { if (!TAILQ_EMPTY(&test->xbind_addrs)) {
struct xbind_entry *xbe; struct xbind_entry *xbe;

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

@ -80,6 +80,7 @@ typedef uint64_t iperf_size_t;
#define OPT_SERVER_BITRATE_LIMIT 21 #define OPT_SERVER_BITRATE_LIMIT 21
#define OPT_TIMESTAMPS 22 #define OPT_TIMESTAMPS 22
#define OPT_SERVER_SKEW_THRESHOLD 23 #define OPT_SERVER_SKEW_THRESHOLD 23
#define OPT_BIND_DEV 24
/* states */ /* states */
#define TEST_START 1 #define TEST_START 1
@ -408,6 +409,7 @@ enum {
IESETPACING= 140, // Unable to set socket pacing rate IESETPACING= 140, // Unable to set socket pacing rate
IESETBUF2= 141, // Socket buffer size incorrect (written value != read value) IESETBUF2= 141, // Socket buffer size incorrect (written value != read value)
IEAUTHTEST = 142, // Test authorization failed IEAUTHTEST = 142, // Test authorization failed
IEBINDDEV = 143, // Unable to bind-to-device (check perror, maybe permissions?)
/* 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)

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

@ -336,7 +336,7 @@ iperf_connect(struct iperf_test *test)
/* Create and connect the control channel */ /* Create and connect the control channel */
if (test->ctrl_sck < 0) if (test->ctrl_sck < 0)
// Create the control channel using an ephemeral port // Create the control channel using an ephemeral port
test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, 0, test->server_hostname, test->server_port, test->settings->connect_timeout); test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout);
if (test->ctrl_sck < 0) { if (test->ctrl_sck < 0) {
i_errno = IECONNECT; i_errno = IECONNECT;
return -1; return -1;

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

@ -48,6 +48,9 @@
/* Define to 1 if you have the `SetProcessAffinityMask' function. */ /* Define to 1 if you have the `SetProcessAffinityMask' function. */
#undef HAVE_SETPROCESSAFFINITYMASK #undef HAVE_SETPROCESSAFFINITYMASK
/* Have SO_BINDTODEVICE sockopt. */
#undef HAVE_SO_BINDTODEVICE
/* Have SO_MAX_PACING_RATE sockopt. */ /* Have SO_MAX_PACING_RATE sockopt. */
#undef HAVE_SO_MAX_PACING_RATE #undef HAVE_SO_MAX_PACING_RATE

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

@ -105,6 +105,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" -A, --affinity n/n,m set CPU affinity\n" " -A, --affinity n/n,m set CPU affinity\n"
#endif /* HAVE_CPU_AFFINITY */ #endif /* HAVE_CPU_AFFINITY */
" -B, --bind <host> bind to the interface associated with the address <host>\n" " -B, --bind <host> bind to the interface associated with the address <host>\n"
#if defined(HAVE_SO_BINDTODEVICE)
" --bind-dev <dev> bind to the network interface with SO_BINDTODEVICE\n"
#endif /* HAVE_SO_BINDTODEVICE */
" -V, --verbose more detailed output\n" " -V, --verbose more detailed output\n"
" -J, --json output in JSON format\n" " -J, --json output in JSON format\n"
" --logfile f send output to a log file\n" " --logfile f send output to a log file\n"
@ -233,6 +236,9 @@ const char client_port[] =
const char bind_address[] = const char bind_address[] =
"Binding to local address %s\n"; "Binding to local address %s\n";
const char bind_dev[] =
"Binding to local network device %s\n";
const char bind_port[] = const char bind_port[] =
"Binding to local port %s\n"; "Binding to local port %s\n";

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

@ -36,6 +36,7 @@ extern const char seperator_line[];
extern const char server_port[] ; extern const char server_port[] ;
extern const char client_port[] ; extern const char client_port[] ;
extern const char bind_address[] ; extern const char bind_address[] ;
extern const char bind_dev[] ;
extern const char multicast_ttl[] ; extern const char multicast_ttl[] ;
extern const char join_multicast[] ; extern const char join_multicast[] ;
extern const char client_datagram_size[] ; extern const char client_datagram_size[] ;

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

@ -211,6 +211,21 @@ iperf_sctp_listen(struct iperf_test *test)
} }
} }
if (test->bind_dev) {
#if defined(SO_BINDTODEVICE)
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
test->bind_dev, IFNAMSIZ) < 0)
#endif // SO_BINDTODEVICE
{
saved_errno = errno;
close(s);
freeaddrinfo(res);
i_errno = IEBINDDEV;
errno = saved_errno;
return -1;
}
}
#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC ||
test->settings->domain == AF_INET6)) { test->settings->domain == AF_INET6)) {
@ -284,7 +299,7 @@ iperf_sctp_connect(struct iperf_test *test)
#if defined(HAVE_SCTP_H) #if defined(HAVE_SCTP_H)
int s, opt, saved_errno; int s, opt, saved_errno;
char portstr[6]; char portstr[6];
struct addrinfo hints, *local_res, *server_res; struct addrinfo hints, *local_res = NULL, *server_res = NULL;
if (test->bind_address) { if (test->bind_address) {
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
@ -309,7 +324,6 @@ iperf_sctp_connect(struct iperf_test *test)
s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP); s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP);
if (s < 0) { if (s < 0) {
if (test->bind_address)
freeaddrinfo(local_res); freeaddrinfo(local_res);
freeaddrinfo(server_res); freeaddrinfo(server_res);
i_errno = IESTREAMCONNECT; i_errno = IESTREAMCONNECT;
@ -336,6 +350,22 @@ iperf_sctp_connect(struct iperf_test *test)
} }
} }
if (test->bind_dev) {
#if defined(SO_BINDTODEVICE)
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
test->bind_dev, IFNAMSIZ) < 0)
#endif // SO_BINDTODEVICE
{
saved_errno = errno;
close(s);
freeaddrinfo(local_res);
freeaddrinfo(server_res);
i_errno = IEBINDDEV;
errno = saved_errno;
return -1;
}
}
/* /*
* Various ways to bind the local end of the connection. * Various ways to bind the local end of the connection.
* 1. --bind (with or without --cport). * 1. --bind (with or without --cport).

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

@ -70,7 +70,7 @@ int
iperf_server_listen(struct iperf_test *test) iperf_server_listen(struct iperf_test *test)
{ {
retry: retry:
if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
/* If we get "Address family not supported by protocol", that /* If we get "Address family not supported by protocol", that
** probably means we were compiled with IPv6 but the running ** probably means we were compiled with IPv6 but the running
@ -609,7 +609,7 @@ iperf_run_server(struct iperf_test *test)
FD_CLR(test->listener, &test->read_set); FD_CLR(test->listener, &test->read_set);
close(test->listener); close(test->listener);
test->listener = 0; test->listener = 0;
if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
cleanup_server(test); cleanup_server(test);
i_errno = IELISTEN; i_errno = IELISTEN;
return -1; return -1;

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

@ -440,7 +440,7 @@ iperf_udp_accept(struct iperf_test *test)
/* /*
* Create a new "listening" socket to replace the one we were using before. * Create a new "listening" socket to replace the one we were using before.
*/ */
test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port); test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port);
if (test->prot_listener < 0) { if (test->prot_listener < 0) {
i_errno = IESTREAMLISTEN; i_errno = IESTREAMLISTEN;
return -1; return -1;
@ -472,7 +472,7 @@ iperf_udp_listen(struct iperf_test *test)
{ {
int s; int s;
if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) { if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
i_errno = IESTREAMLISTEN; i_errno = IESTREAMLISTEN;
return -1; return -1;
} }
@ -499,7 +499,7 @@ iperf_udp_connect(struct iperf_test *test)
int rc; int rc;
/* Create and bind our local socket. */ /* Create and bind our local socket. */
if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) { if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) {
i_errno = IESTREAMCONNECT; i_errno = IESTREAMCONNECT;
return -1; return -1;
} }

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

@ -317,6 +317,16 @@ get_optional_features(void)
numfeatures++; numfeatures++;
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
#if defined(HAVE_SO_BINDTODEVICE)
if (numfeatures > 0) {
strncat(features, ", ",
sizeof(features) - strlen(features) - 1);
}
strncat(features, "bind to device",
sizeof(features) - strlen(features) - 1);
numfeatures++;
#endif /* HAVE_SO_BINDTODEVICE */
if (numfeatures == 0) { if (numfeatures == 0) {
strncat(features, "None", strncat(features, "None",
sizeof(features) - strlen(features) - 1); sizeof(features) - strlen(features) - 1);

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

@ -25,6 +25,7 @@ Setting test parameters:
.nf .nf
void iperf_set_test_role( struct iperf_test *pt, char role ); void iperf_set_test_role( struct iperf_test *pt, char role );
void iperf_set_test_bind_address( struct iperf_test *t, char *bind_address ); void iperf_set_test_bind_address( struct iperf_test *t, char *bind_address );
void iperf_set_test_bind_dev( struct iperf_test *t, char *bind_dev );
void iperf_set_test_server_hostname( struct iperf_test *t, char *server_host ); void iperf_set_test_server_hostname( struct iperf_test *t, char *server_host );
void iperf_set_test_server_port( struct iperf_test *t, int server_port ); void iperf_set_test_server_port( struct iperf_test *t, int server_port );
void iperf_set_test_duration( struct iperf_test *t, int duration ); void iperf_set_test_duration( struct iperf_test *t, int duration );

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

@ -61,6 +61,7 @@
#include <poll.h> #include <poll.h>
#endif /* HAVE_POLL_H */ #endif /* HAVE_POLL_H */
#include "iperf.h"
#include "iperf_util.h" #include "iperf_util.h"
#include "net.h" #include "net.h"
#include "timer.h" #include "timer.h"
@ -121,9 +122,9 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
/* make connection to server */ /* make connection to server */
int int
netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout) netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout)
{ {
struct addrinfo hints, *local_res, *server_res; struct addrinfo hints, *local_res = NULL, *server_res = NULL;
int s, saved_errno; int s, saved_errno;
if (local) { if (local) {
@ -148,6 +149,21 @@ netdial(int domain, int proto, const char *local, int local_port, const char *se
return -1; return -1;
} }
if (bind_dev) {
#if defined(HAVE_SO_BINDTODEVICE)
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
bind_dev, IFNAMSIZ) < 0)
#endif // HAVE_SO_BINDTODEVICE
{
saved_errno = errno;
close(s);
freeaddrinfo(local_res);
freeaddrinfo(server_res);
errno = saved_errno;
return -1;
}
}
/* Bind the local address if given a name (with or without --cport) */ /* Bind the local address if given a name (with or without --cport) */
if (local) { if (local) {
if (local_port) { if (local_port) {
@ -218,7 +234,7 @@ netdial(int domain, int proto, const char *local, int local_port, const char *se
/***************************************************************/ /***************************************************************/
int int
netannounce(int domain, int proto, const char *local, int port) netannounce(int domain, int proto, const char *local, const char *bind_dev, int port)
{ {
struct addrinfo hints, *res; struct addrinfo hints, *res;
char portstr[6]; char portstr[6];
@ -255,6 +271,20 @@ netannounce(int domain, int proto, const char *local, int port)
return -1; return -1;
} }
if (bind_dev) {
#if defined(HAVE_SO_BINDTODEVICE)
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
bind_dev, IFNAMSIZ) < 0)
#endif // HAVE_SO_BINDTODEVICE
{
saved_errno = errno;
close(s);
freeaddrinfo(res);
errno = saved_errno;
return -1;
}
}
opt = 1; opt = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *) &opt, sizeof(opt)) < 0) { (char *) &opt, sizeof(opt)) < 0) {

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

@ -28,8 +28,8 @@
#define __NET_H #define __NET_H
int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout);
int netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout); int netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout);
int netannounce(int domain, int proto, const char *local, int port); int netannounce(int domain, int proto, const char *local, const char *bind_dev, int port);
int Nread(int fd, char *buf, size_t count, int prot); int Nread(int fd, char *buf, size_t count, int prot);
int Nwrite(int fd, const char *buf, size_t count, int prot) /* __attribute__((hot)) */; int Nwrite(int fd, const char *buf, size_t count, int prot) /* __attribute__((hot)) */;
int has_sendfile(void); int has_sendfile(void);