diff options
Diffstat (limited to 'src/tcp_info.c')
-rw-r--r-- | src/tcp_info.c | 234 |
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 +} |