From 92c91554100177d48b219f2d8f599eb94b30bdd2 Mon Sep 17 00:00:00 2001 From: David Bar-On <61089727+davidBar-On@users.noreply.github.com> Date: Fri, 2 Aug 2024 23:45:10 +0300 Subject: [PATCH] Add SCTP information to --json output (#1731) * Add SCTP information to --json output * Fix compile error when SCTP is not supported --- src/iperf.h | 11 +++++++++++ src/iperf_api.c | 40 ++++++++++++++++++++++++++++++++++++-- src/iperf_sctp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++---- src/iperf_sctp.h | 6 ++++++ 4 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 527e549ed..f297587d1 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -83,6 +83,14 @@ typedef atomic_uint_fast64_t atomic_iperf_size_t; typedef unsigned int uint #endif // __vxworks or __VXWORKS__ +struct iperf_sctp_info +{ + long rtt; + long pmtu; + uint32_t wnd; + uint32_t cwnd; +}; + struct iperf_interval_results { atomic_iperf_size_t bytes_transferred; /* bytes transferred in this interval */ @@ -107,6 +115,9 @@ struct iperf_interval_results /* Just placeholders, never accessed. */ char *tcpInfo; #endif +#if defined(HAVE_SCTP_H) + struct iperf_sctp_info sctp_info; +#endif /* HAVE_SCTP_H */ long interval_retrans; long snd_cwnd; long snd_wnd; diff --git a/src/iperf_api.c b/src/iperf_api.c index 0ff71675d..daa157cac 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -3362,8 +3362,14 @@ iperf_stats_callback(struct iperf_test *test) struct iperf_interval_results *irp, temp; struct iperf_time temp_time; iperf_size_t total_interval_bytes_transferred = 0; +#if defined(HAVE_SCTP_H) + struct iperf_sctp_info sctp_info; +#endif /* HAVE_SCTP_H */ temp.omitted = test->omitting; + temp.rtt = 0; + temp.rttvar = 0; + temp.pmtu = 0; SLIST_FOREACH(sp, &test->streams, streams) { rp = sp->result; temp.bytes_transferred = sp->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval; @@ -3431,6 +3437,36 @@ iperf_stats_callback(struct iperf_test *test) temp.outoforder_packets = sp->outoforder_packets; temp.cnt_error = sp->cnt_error; } + +#if defined(HAVE_SCTP_H) + if (test->protocol->id == Psctp) { + if (iperf_sctp_get_info(sp, &sctp_info) >= 0) {; + temp.pmtu = sctp_info.pmtu; + temp.rtt = sctp_info.rtt; + temp.snd_cwnd = sctp_info.cwnd; + temp.snd_wnd = sctp_info.wnd; + if (temp.snd_cwnd > rp->stream_max_snd_cwnd) { + rp->stream_max_snd_cwnd = temp.snd_cwnd; + } + if (temp.snd_wnd > rp->stream_max_snd_wnd) { + rp->stream_max_snd_wnd = temp.snd_wnd; + } + if (temp.rtt >= 0) { + temp.rtt = sctp_info.rtt; + if (temp.rtt > rp->stream_max_rtt) { + rp->stream_max_rtt = temp.rtt; + } + if (rp->stream_min_rtt == 0 || + temp.rtt < rp->stream_min_rtt) { + rp->stream_min_rtt = temp.rtt; + } + rp->stream_sum_rtt += temp.rtt; + rp->stream_count_rtt++; + } + } + } +#endif /* HAVE_SCTP_H */ + add_to_interval_list(rp, &temp); rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0; } @@ -3871,7 +3907,7 @@ iperf_print_results(struct iperf_test *test) } unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { - if (test->sender_has_retransmits) { + if (test->sender_has_retransmits || test->protocol->id == Psctp) { /* Sender summary, TCP and SCTP with retransmits. */ if (test->json_output) cJSON_AddItemToObject(json_summary_stream, report_sender, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_snd_wnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_snd_wnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender)); @@ -4322,7 +4358,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * et = iperf_time_in_secs(&temp_time); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { - if (test->sender_has_retransmits == 1 && sp->sender) { + if ((test->sender_has_retransmits == 1 || test->protocol->id == Psctp) && sp->sender) { /* Interval, TCP with retransmits. */ if (test->json_output) cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d snd_wnd: %d rtt: %d rttvar: %d pmtu: %d omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->snd_wnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender)); diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c index 104083281..9a61bba44 100644 --- a/src/iperf_sctp.c +++ b/src/iperf_sctp.c @@ -39,10 +39,6 @@ #include #include -#ifdef HAVE_NETINET_SCTP_H -#include -#endif /* HAVE_NETINET_SCTP_H */ - #include "iperf.h" #include "iperf_api.h" #include "iperf_sctp.h" @@ -734,3 +730,49 @@ iperf_sctp_bindx(struct iperf_test *test, int s, int is_server) return -1; #endif /* HAVE_SCTP_H */ } + + +/* iperf_sctp_get_rtt + * + * Get SCTP stream RTT. + * Assuming that iperf3 supports only one-toone SCTP associassion, and not one-to-many associassion. + * + * Main resouses used are RFC-6458, man pages for SCTP, + * https://docs.oracle.com/cd/E19253-01/817-4415/sockets-199/index.html. + * + */ +int +iperf_sctp_get_info(struct iperf_stream *sp, struct iperf_sctp_info *sctp_info) +{ +#if defined(HAVE_SCTP_H) + struct sctp_status status; + socklen_t len; + sctp_assoc_t assoc_id; + int rc = 0; + + if (sp->test->protocol->id != Psctp) { + rc = -1; + } else { +#ifdef SCTP_FUTURE_ASSOC + assoc_id = SCTP_FUTURE_ASSOC; +#else + assoc_id = 0; +#endif + len = sizeof(status); + rc = sctp_opt_info(sp->socket, assoc_id, SCTP_STATUS, &status, &len); + if (rc < 0) { + if (sp->test->debug_level >= DEBUG_LEVEL_ERROR) + iperf_err(sp->test, "sctp_opt_info get SCTP_STATUS for socket %d failed with errno %d - %s", sp->socket, errno, strerror(errno)); + } else { + sctp_info->wnd = status.sstat_rwnd; + sctp_info->rtt = status.sstat_primary.spinfo_srtt; + sctp_info->pmtu = status.sstat_primary.spinfo_mtu; + sctp_info->cwnd = status.sstat_primary.spinfo_cwnd; + } + } + + return rc; +#else + return -1; +#endif /* HAVE_SCTP_H */ +} diff --git a/src/iperf_sctp.h b/src/iperf_sctp.h index 764c410df..cbe24c934 100644 --- a/src/iperf_sctp.h +++ b/src/iperf_sctp.h @@ -27,6 +27,10 @@ #ifndef IPERF_SCTP_H #define IPERF_SCTP_H +#ifdef HAVE_NETINET_SCTP_H +#include +#endif /* HAVE_NETINET_SCTP_H */ + /** * iperf_sctp_accept -- accepts a new SCTP connection * on sctp_listener_socket for SCTP data and param/result @@ -65,4 +69,6 @@ int iperf_sctp_init(struct iperf_test *test); int iperf_sctp_bindx(struct iperf_test *test, int s, int is_server); +int iperf_sctp_get_info(struct iperf_stream *sp, struct iperf_sctp_info *sctp_info); + #endif