Skip to content
Open
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
10 changes: 10 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -16895,6 +16895,16 @@ then :
printf '%s\n' "#define HAVE_STRUCT_SCTP_ASSOC_VALUE 1" >>confdefs.h


fi

ac_fn_c_check_type "$LINENO" "struct sctp_sack_info" "ac_cv_type_struct_sctp_sack_info" "#include <netinet/sctp.h>
"
if test "x$ac_cv_type_struct_sctp_sack_info" = xyes
then :

printf '%s\n' "#define HAVE_STRUCT_SCTP_SACK_INFO 1" >>confdefs.h


fi

fi
Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ AC_CHECK_HEADERS([netinet/sctp.h],
AC_DEFINE([HAVE_SCTP_H], [1], [Have SCTP support.])
AC_SEARCH_LIBS(sctp_bindx, [sctp])
AC_CHECK_TYPES([struct sctp_assoc_value], [], [],
[[#include <netinet/sctp.h>]])
AC_CHECK_TYPES([struct sctp_sack_info], [], [],
[[#include <netinet/sctp.h>]]),
[],
[#ifdef HAVE_SYS_SOCKET_H
Expand Down
1 change: 1 addition & 0 deletions src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ enum {
IESETCNTLKACOUNT = 158, // Unable to set/get socket keepalive TCP number of retries (TCP_KEEPCNT) option
IEPTHREADSIGMASK=159, // Unable to initialize sub thread signal mask (check perror)
IESERVERTESTDURATIONEXPIRED = 160, // Server test duration expired
IESETSCTPDELAYEDSACK = 161, // Unable to set SCTP_DELAYED_SACK (check perror)
/* 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 @@ -117,6 +117,9 @@
/* Define to 1 if the system has the type 'struct sctp_assoc_value'. */
#undef HAVE_STRUCT_SCTP_ASSOC_VALUE

/* Define to 1 if the system has the type 'struct sctp_sack_info'. */
#undef HAVE_STRUCT_SCTP_SACK_INFO

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

Expand Down
4 changes: 4 additions & 0 deletions src/iperf_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,10 @@ iperf_strerror(int int_errno)
snprintf(errstr, len, "unable to set SCTP_DISABLE_FRAGMENTS");
perr = 1;
break;
case IESETSCTPDELAYEDSACK:
snprintf(errstr, len, "unable to set SCTP_DELAYED_SACK");
perr = 1;
break;
case IESETSCTPNSTREAM:
snprintf(errstr, len, "unable to set SCTP_INIT num of SCTP streams\n");
perr = 1;
Expand Down
105 changes: 105 additions & 0 deletions src/iperf_sctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,38 @@ iperf_sctp_accept(struct iperf_test * test)
return -1;
}

if (test->no_delay) {
int opt = 1;
if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) {
i_errno = IESETNODELAY;
close(s);
return -1;
}
}

#ifdef HAVE_STRUCT_SCTP_SACK_INFO
/*
* Apply SCTP_DELAYED_SACK on the accepted association. On Linux the
* SCTP_DELAYED_SACK setting on the listener does NOT propagate to
* accepted associations, so the per-association setting must be applied
* here for the receiver-side fix to take effect. ENOPROTOOPT is
* non-fatal so this is safe on platforms without support.
*/
{
struct sctp_sack_info sack;
memset(&sack, 0, sizeof(sack));
sack.sack_assoc_id = 0;
sack.sack_delay = 0;
sack.sack_freq = 1;
if (setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, &sack, sizeof(sack)) < 0 &&
errno != ENOPROTOOPT) {
i_errno = IESETSCTPDELAYEDSACK;
close(s);
return -1;
}
}
#endif /* HAVE_STRUCT_SCTP_SACK_INFO */

if (Nread(s, cookie, COOKIE_SIZE, Psctp) < 0) {
i_errno = IERECVCOOKIE;
close(s);
Expand Down Expand Up @@ -248,6 +280,52 @@ iperf_sctp_listen(struct iperf_test *test)
return -1;
}

if (test->no_delay) {
opt = 1;
if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
close(s);
freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETNODELAY;
return -1;
}
}

#ifdef HAVE_STRUCT_SCTP_SACK_INFO
/*
* Disable SCTP delayed-SACK on future accepted associations. With the
* default sack_freq=2/sack_delay=200ms, a sender that writes blocks
* producing exactly one DATA chunk stalls for 200 ms waiting for a SACK
* that the receiver is in turn delaying. iperf3 is a throughput
* benchmark, so request an immediate SACK on every packet. On Linux
* the endpoint default set here does not propagate to accepted
* associations -- iperf_sctp_accept() repeats the call on the per-
* association socket. ENOPROTOOPT (platform without support) is
* non-fatal.
*/
{
struct sctp_sack_info sack;
memset(&sack, 0, sizeof(sack));
#ifdef SCTP_FUTURE_ASSOC
sack.sack_assoc_id = SCTP_FUTURE_ASSOC;
#else
sack.sack_assoc_id = 0;
#endif
sack.sack_delay = 0;
sack.sack_freq = 1;
if (setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, &sack, sizeof(sack)) < 0 &&
errno != ENOPROTOOPT) {
saved_errno = errno;
close(s);
freeaddrinfo(res);
errno = saved_errno;
i_errno = IESETSCTPDELAYEDSACK;
return -1;
}
}
#endif /* HAVE_STRUCT_SCTP_SACK_INFO */

/* servers must call sctp_bindx() _instead_ of bind() */
if (!TAILQ_EMPTY(&test->xbind_addrs)) {
if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER)) {
Expand Down Expand Up @@ -541,6 +619,33 @@ iperf_sctp_connect(struct iperf_test *test)
return -1;
}

#ifdef HAVE_STRUCT_SCTP_SACK_INFO
/*
* Disable SCTP delayed-SACK on this association (see iperf_sctp_listen()
* for rationale). Applied here as well so that --reverse, which makes
* the client the receiver, still gets immediate SACKs. The socket is
* already connected and 1:1-style, so sack_assoc_id=0 unambiguously
* targets the current association on every platform (RFC 6458 §8.1).
* ENOPROTOOPT is treated as non-fatal.
*/
{
struct sctp_sack_info sack;
memset(&sack, 0, sizeof(sack));
sack.sack_assoc_id = 0;
sack.sack_delay = 0;
sack.sack_freq = 1;
if (setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, &sack, sizeof(sack)) < 0 &&
errno != ENOPROTOOPT) {
saved_errno = errno;
close(s);
freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETSCTPDELAYEDSACK;
return -1;
}
}
#endif /* HAVE_STRUCT_SCTP_SACK_INFO */

freeaddrinfo(server_res);
return s;
#else
Expand Down