summaryrefslogtreecommitdiffstats
path: root/src/tcp_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcp_info.c')
-rw-r--r--src/tcp_info.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/tcp_info.c b/src/tcp_info.c
new file mode 100644
index 0000000..160063c
--- /dev/null
+++ b/src/tcp_info.c
@@ -0,0 +1,234 @@
+/*
+ * iperf, Copyright (c) 2014, 2017, 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.
+ *
+ * If you have questions about your rights to use or distribute this
+ * software, please contact Berkeley Lab's Technology Transfer
+ * Department at TTD@lbl.gov.
+ *
+ * NOTICE. This software is owned by the U.S. Department of Energy.
+ * As such, the U.S. Government has been granted for itself and others
+ * acting on its behalf a paid-up, nonexclusive, irrevocable,
+ * worldwide license in the Software to reproduce, prepare derivative
+ * works, and perform publicly and display publicly. Beginning five
+ * (5) years after the date permission to assert copyright is obtained
+ * from the U.S. Department of Energy, and subject to any subsequent
+ * five (5) year renewals, the U.S. Government is granted for itself
+ * and others acting on its behalf a paid-up, nonexclusive,
+ * irrevocable, worldwide license in the Software to reproduce,
+ * prepare derivative works, distribute copies to the public, perform
+ * publicly and display publicly, and to permit others to do so.
+ *
+ * This code is distributed under a BSD style license, see the LICENSE
+ * file for complete information.
+ */
+
+/*
+ * routines related to collection TCP_INFO using getsockopt()
+ *
+ * Brian Tierney, ESnet (bltierney@es.net)
+ *
+ * Note that this is only really useful on Linux.
+ * XXX: only standard on linux versions 2.4 and later
+ #
+ * FreeBSD has a limited implementation that only includes the following:
+ * tcpi_snd_ssthresh, tcpi_snd_cwnd, tcpi_rcv_space, tcpi_rtt
+ * Based on information on http://wiki.freebsd.org/8.0TODO, I dont think this will be
+ * fixed before v8.1 at the earliest.
+ *
+ * OSX has no support.
+ *
+ * I think MS Windows does support TCP_INFO, but iperf3 does not currently support Windows.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "iperf.h"
+#include "iperf_api.h"
+#include "iperf_locale.h"
+
+/*************************************************************/
+int
+has_tcpinfo(void)
+{
+#if (defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) \
+ && defined(TCP_INFO)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/*************************************************************/
+int
+has_tcpinfo_retransmits(void)
+{
+#if defined(linux) && defined(TCP_MD5SIG)
+ /* TCP_MD5SIG doesn't actually have anything to do with TCP
+ ** retransmits, it just showed up in the same rev of the header
+ ** file. If it's present then struct tcp_info has the
+ ** tcpi_total_retrans field that we need; if not, not.
+ */
+ return 1;
+#else
+#if defined(__FreeBSD__) && __FreeBSD_version >= 600000
+ return 1; /* Should work now */
+#elif (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(TCP_INFO)
+ return 1;
+#else
+ return 0;
+#endif
+#endif
+}
+
+/*************************************************************/
+void
+save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp)
+{
+#if (defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) && \
+ defined(TCP_INFO)
+ socklen_t tcp_info_length = sizeof(struct tcp_info);
+
+ if (getsockopt(sp->socket, IPPROTO_TCP, TCP_INFO, (void *)&irp->tcpInfo, &tcp_info_length) < 0)
+ iperf_err(sp->test, "getsockopt - %s", strerror(errno));
+
+ if (sp->test->debug) {
+ printf("tcpi_snd_cwnd %u tcpi_snd_mss %u tcpi_rtt %u\n",
+ irp->tcpInfo.tcpi_snd_cwnd, irp->tcpInfo.tcpi_snd_mss,
+ irp->tcpInfo.tcpi_rtt);
+ }
+
+#endif
+}
+
+/*************************************************************/
+long
+get_total_retransmits(struct iperf_interval_results *irp)
+{
+#if defined(linux) && defined(TCP_MD5SIG)
+ return irp->tcpInfo.tcpi_total_retrans;
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
+ return irp->tcpInfo.tcpi_snd_rexmitpack;
+#elif (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(TCP_INFO)
+ return irp->tcpInfo.tcpi_snd_rexmitpack;
+#else
+ return -1;
+#endif
+}
+
+/*************************************************************/
+/*
+ * Return snd_cwnd in octets.
+ */
+long
+get_snd_cwnd(struct iperf_interval_results *irp)
+{
+#if defined(linux) && defined(TCP_MD5SIG)
+ return (long)irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
+ return irp->tcpInfo.tcpi_snd_cwnd;
+#elif defined(__NetBSD__) && defined(TCP_INFO)
+ return (long)irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
+#elif defined(__OpenBSD__) && defined(TCP_INFO)
+ return irp->tcpInfo.tcpi_snd_cwnd;
+#else
+ return -1;
+#endif
+}
+
+/*************************************************************/
+/*
+ * Return snd_wnd in octets.
+ */
+long
+get_snd_wnd(struct iperf_interval_results *irp)
+{
+#if !defined(HAVE_TCP_INFO_SND_WND)
+ return -1;
+#elif defined(linux) && defined(TCP_MD5SIG)
+ return irp->tcpInfo.tcpi_snd_wnd;
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
+ return irp->tcpInfo.tcpi_snd_wnd;
+#elif defined(__NetBSD__) && defined(TCP_INFO)
+ return (long)irp->tcpInfo.tcpi_snd_wnd * irp->tcpInfo.tcpi_snd_mss;
+#elif defined(__OpenBSD__) && defined(TCP_INFO)
+ return irp->tcpInfo.tcpi_snd_wnd;
+#else
+ return -1;
+#endif
+}
+
+/*************************************************************/
+/*
+ * Return rtt in usec.
+ */
+long
+get_rtt(struct iperf_interval_results *irp)
+{
+#if defined(linux) && defined(TCP_MD5SIG)
+ return irp->tcpInfo.tcpi_rtt;
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
+ return irp->tcpInfo.tcpi_rtt;
+#elif (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(TCP_INFO)
+ return irp->tcpInfo.tcpi_rtt;
+#else
+ return -1;
+#endif
+}
+
+/*************************************************************/
+/*
+ * Return rttvar in usec.
+ */
+long
+get_rttvar(struct iperf_interval_results *irp)
+{
+#if defined(linux) && defined(TCP_MD5SIG)
+ return irp->tcpInfo.tcpi_rttvar;
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
+ return irp->tcpInfo.tcpi_rttvar;
+#elif (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(TCP_INFO)
+ return irp->tcpInfo.tcpi_rttvar;
+#else
+ return -1;
+#endif
+}
+
+/*************************************************************/
+/*
+ * Return PMTU in bytes.
+ */
+long
+get_pmtu(struct iperf_interval_results *irp)
+{
+#if defined(linux) && defined(TCP_MD5SIG)
+ return irp->tcpInfo.tcpi_pmtu;
+#else
+ return -1;
+#endif
+}
+
+/*************************************************************/
+void
+build_tcpinfo_message(struct iperf_interval_results *r, char *message)
+{
+#if defined(linux) && defined(TCP_INFO)
+ sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_snd_ssthresh,
+ r->tcpInfo.tcpi_rcv_ssthresh, r->tcpInfo.tcpi_unacked, r->tcpInfo.tcpi_sacked,
+ r->tcpInfo.tcpi_lost, r->tcpInfo.tcpi_retrans, r->tcpInfo.tcpi_fackets,
+ r->tcpInfo.tcpi_rtt, r->tcpInfo.tcpi_reordering);
+#endif
+#if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) && defined(TCP_INFO)
+ sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd,
+ r->tcpInfo.tcpi_rcv_space, r->tcpInfo.tcpi_snd_ssthresh, r->tcpInfo.tcpi_rtt);
+#endif
+}