Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IP dont fragment support #1119

Merged
merged 17 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions aclocal.m4
Original file line number Diff line number Diff line change
Expand Up @@ -1081,11 +1081,16 @@ _LT_EOF
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
darwin*)
case ${MACOSX_DEPLOYMENT_TARGET},$host in
10.[[012]],*|,*powerpc*)
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
10.[[012]][[,.]]*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
*)
10.*)
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
Expand Down
52 changes: 48 additions & 4 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -7431,11 +7431,16 @@ $as_echo "$lt_cv_ld_force_load" >&6; }
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
darwin*)
case ${MACOSX_DEPLOYMENT_TARGET},$host in
10.[012],*|,*powerpc*)
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[91]*)
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
10.[012][,.]*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
*)
10.*)
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
Expand Down Expand Up @@ -13976,6 +13981,45 @@ $as_echo "#define HAVE_SO_BINDTODEVICE 1" >>confdefs.h

fi

# Check for IP DF support
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking IP_MTU_DISCOVER or IP_DONTFRAG socket option" >&5
$as_echo_n "checking IP_MTU_DISCOVER or IP_DONTFRAG socket option... " >&6; }
if ${iperf3_cv_header_dontfragment+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#ifdef IP_MTU_DISCOVER
yes
#endif
#ifdef IP_DONTFRAG
yes
#endif
#ifdef IP_DONTFRAGMENT
yes
#endif

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "yes" >/dev/null 2>&1; then :
iperf3_cv_header_dontfragment=yes
else
iperf3_cv_header_dontfragment=no
fi
rm -f conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $iperf3_cv_header_dontfragment" >&5
$as_echo "$iperf3_cv_header_dontfragment" >&6; }
if test "x$iperf3_cv_header_dontfragment" = "xyes"; then

$as_echo "#define HAVE_DONT_FRAGMENT 1" >>confdefs.h

fi

# Check if we need -lrt for clock_gettime
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
$as_echo_n "checking for library containing clock_gettime... " >&6; }
Expand Down
23 changes: 22 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# iperf, Copyright (c) 2014-2020, The Regents of the University of
# iperf, Copyright (c) 2014-2021, 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.
Expand Down Expand Up @@ -237,6 +237,27 @@ if test "x$iperf3_cv_header_so_bindtodevice" = "xyes"; then
AC_DEFINE([HAVE_SO_BINDTODEVICE], [1], [Have SO_BINDTODEVICE sockopt.])
fi

# Check for IP DF support
AC_CACHE_CHECK([IP_MTU_DISCOVER or IP_DONTFRAG socket option],
[iperf3_cv_header_dontfragment],
AC_EGREP_CPP(yes,
[#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#ifdef IP_MTU_DISCOVER
yes
#endif
#ifdef IP_DONTFRAG
yes
#endif
#ifdef IP_DONTFRAGMENT
yes
#endif
],iperf3_cv_header_dontfragment=yes,iperf3_cv_header_dontfragment=no))
if test "x$iperf3_cv_header_dontfragment" = "xyes"; then
AC_DEFINE([HAVE_DONT_FRAGMENT], [1], [Have IP_MTU_DISCOVER/IP_DONTFRAG sockopt.])
fi

# Check if we need -lrt for clock_gettime
AC_SEARCH_LIBS(clock_gettime, [rt posix4])
# Check for clock_gettime support
Expand Down
1 change: 1 addition & 0 deletions src/iperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ struct iperf_settings
iperf_size_t blocks; /* number of blocks (packets) to send */
char unit_format; /* -f */
int num_ostreams; /* SCTP initmsg settings */
int dont_fragment; /* Whether to set IP flag Do-Not_Fragment */
#if defined(HAVE_SSL)
char *authtoken; /* Authentication token */
char *client_username;
Expand Down
6 changes: 5 additions & 1 deletion src/iperf3.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH IPERF3 1 "September 2020" ESnet "User Manuals"
.TH IPERF3 1 "February 2021" ESnet "User Manuals"
.SH NAME
iperf3 \- perform network throughput tests
.SH SYNOPSIS
Expand Down Expand Up @@ -397,6 +397,10 @@ It might help to test and reveal problems in networking gear with hardware
compression (including some WiFi access points), where iperf2 and iperf3
perform differently, just based on payload entropy.
.TP
.BR --dont-fragment
Set the IPv4 Don't Fragment (DF) bit on outgoing packets.
Only applicable to tests doing UDP over IPv4.
.TP
.BR --username " \fIusername\fR"
username to use for authentication to the iperf server (if built with
OpenSSL support).
Expand Down
69 changes: 69 additions & 0 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ iperf_get_test_idle_timeout(struct iperf_test *ipt)
return ipt->settings->idle_timeout;
}

int
iperf_get_dont_fragment(struct iperf_test *ipt)
{
return ipt->settings->dont_fragment;
}

char*
iperf_get_test_congestion_control(struct iperf_test* ipt)
{
Expand Down Expand Up @@ -737,6 +743,12 @@ iperf_set_test_idle_timeout(struct iperf_test* ipt, int to)
ipt->settings->idle_timeout = to;
}

void
iperf_set_dont_fragment(struct iperf_test* ipt, int dnf)
{
ipt->settings->dont_fragment = dnf;
}

void
iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc)
{
Expand Down Expand Up @@ -968,6 +980,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
{"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
{"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
#if defined(HAVE_DONT_FRAGMENT)
{"dont-fragment", no_argument, NULL, OPT_DONT_FRAGMENT},
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
{"username", required_argument, NULL, OPT_CLIENT_USERNAME},
{"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},
Expand Down Expand Up @@ -1381,6 +1396,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
return -1;
#endif
break;
#if defined(HAVE_DONT_FRAGMENT)
case OPT_DONT_FRAGMENT:
test->settings->dont_fragment = 1;
client_flag = 1;
break;
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
case OPT_CLIENT_USERNAME:
client_username = strdup(optarg);
Expand Down Expand Up @@ -1979,6 +2000,10 @@ send_parameters(struct iperf_test *test)
cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
if (test->repeating_payload)
cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
#if defined(HAVE_DONT_FRAGMENT)
if (test->settings->dont_fragment)
cJSON_AddNumberToObject(j, "dont_fragment", test->settings->dont_fragment);
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
/* Send authentication parameters */
if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
Expand Down Expand Up @@ -2087,6 +2112,10 @@ get_parameters(struct iperf_test *test)
iperf_set_test_udp_counters_64bit(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
test->repeating_payload = 1;
#if defined(HAVE_DONT_FRAGMENT)
if ((j_p = cJSON_GetObjectItem(j, "dont_fragment")) != NULL)
test->settings->dont_fragment = j_p->valueint;
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
test->settings->authtoken = strdup(j_p->valuestring);
Expand Down Expand Up @@ -2882,6 +2911,7 @@ iperf_reset_test(struct iperf_test *test)
test->settings->burst = 0;
test->settings->mss = 0;
test->settings->tos = 0;
test->settings->dont_fragment = 0;

#if defined(HAVE_SSL)
if (test->settings->authtoken) {
Expand Down Expand Up @@ -4062,6 +4092,45 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
}
}

#if defined(HAVE_DONT_FRAGMENT)
/* Set Don't Fragment (DF). Only applicable to IPv4/UDP tests. */
if (iperf_get_test_protocol_id(test) == Pudp &&
getsockdomain(sp->socket) == AF_INET &&
iperf_get_dont_fragment(test)) {

/*
* There are multiple implementations of this feature depending on the OS.
* We need to handle separately Linux, UNIX, and Windows, as well as
* the case that DF isn't supported at all (such as on macOS).
*/
#if defined(IP_MTU_DISCOVER) /* Linux version of IP_DONTFRAG */
opt = IP_PMTUDISC_DO;
if (setsockopt(sp->socket, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) < 0) {
i_errno = IESETDONTFRAGMENT;
return -1;
}
#else
#if defined(IP_DONTFRAG) /* UNIX does IP_DONTFRAG */
opt = 1;
if (setsockopt(sp->socket, IPPROTO_IP, IP_DONTFRAG, &opt, sizeof(opt)) < 0) {
i_errno = IESETDONTFRAGMENT;
return -1;
}
#else
#if defined(IP_DONTFRAGMENT) /* Windows does IP_DONTFRAGMENT */
opt = 1;
if (setsockopt(sp->socket, IPPROTO_IP, IP_DONTFRAGMENT, &opt, sizeof(opt)) < 0) {
i_errno = IESETDONTFRAGMENT;
return -1;
}
#else
i_errno = IESETDONTFRAGMENT;
return -1;
#endif /* IP_DONTFRAGMENT */
#endif /* IP_DONTFRAG */
#endif /* IP_MTU_DISCOVER */
}
#endif /* HAVE_DONT_FRAGMENT */
return 0;
}

Expand Down
4 changes: 4 additions & 0 deletions src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ typedef uint64_t iperf_size_t;
#define OPT_SERVER_SKEW_THRESHOLD 23
#define OPT_BIND_DEV 24
#define OPT_IDLE_TIMEOUT 25
#define OPT_DONT_FRAGMENT 26

/* states */
#define TEST_START 1
Expand Down Expand Up @@ -140,6 +141,7 @@ char* iperf_get_extra_data( struct iperf_test* ipt );
char* iperf_get_iperf_version(void);
int iperf_get_test_no_delay( struct iperf_test* ipt );
int iperf_get_test_connect_timeout( struct iperf_test* ipt );
int iperf_get_dont_fragment( struct iperf_test* ipt );
char* iperf_get_test_congestion_control(struct iperf_test* ipt);

/* Setter routines for some fields inside iperf_test. */
Expand Down Expand Up @@ -178,6 +180,7 @@ void iperf_set_test_tos( struct iperf_test* ipt, int tos );
void iperf_set_test_extra_data( struct iperf_test* ipt, const char *dat );
void iperf_set_test_bidirectional( struct iperf_test* ipt, int bidirectional);
void iperf_set_test_no_delay( struct iperf_test* ipt, int no_delay);
void iperf_set_dont_fragment( struct iperf_test* ipt, int dont_fragment );
void iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc);

#if defined(HAVE_SSL)
Expand Down Expand Up @@ -415,6 +418,7 @@ enum {
IEAUTHTEST = 142, // Test authorization failed
IEBINDDEV = 143, // Unable to bind-to-device (check perror, maybe permissions?)
IENOMSG = 144, // No message was received for NO_MSG_RCVD_TIMEOUT time period
IESETDONTFRAGMENT = 145, // Unable to set IP Do-Not-Fragment
/* Stream errors */
IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror)
IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror)
Expand Down
3 changes: 3 additions & 0 deletions src/iperf_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H

/* Have IP_MTU_DISCOVER/IP_DONTFRAG sockopt. */
#undef HAVE_DONT_FRAGMENT

/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H

Expand Down
3 changes: 3 additions & 0 deletions src/iperf_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,9 @@ iperf_strerror(int int_errno)
case IENOMSG:
snprintf(errstr, len, "no message was received for %d seconds", NO_MSG_RCVD_TIMEOUT);
break;
case IESETDONTFRAGMENT:
snprintf(errstr, len, "unable to set IP Do-Not-Fragment flag");
break;
default:
snprintf(errstr, len, "int_errno=%d", int_errno);
perr = 1;
Expand Down
3 changes: 3 additions & 0 deletions src/iperf_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" --udp-counters-64bit use 64-bit counters in UDP test packets\n"
" --repeating-payload use repeating pattern in payload, instead of\n"
" randomized payload (like in iperf2)\n"
#if defined(HAVE_DONT_FRAGMENT)
" --dont-fragment set IPv4 Don't Fragment flag\n"
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
" --username username for authentication\n"
" --rsa-public-key-path path to the RSA public key used to encrypt\n"
Expand Down
10 changes: 10 additions & 0 deletions src/iperf_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,16 @@ get_optional_features(void)
numfeatures++;
#endif /* HAVE_SO_BINDTODEVICE */

#if defined(HAVE_DONT_FRAGMENT)
if (numfeatures > 0) {
strncat(features, ", ",
sizeof(features) - strlen(features) - 1);
}
strncat(features, "support IPv4 don't fragment",
sizeof(features) - strlen(features) - 1);
numfeatures++;
#endif /* HAVE_DONT_FRAGMENT */

if (numfeatures == 0) {
strncat(features, "None",
sizeof(features) - strlen(features) - 1);
Expand Down