Home | History | Annotate | Download | only in src
      1 /*
      2  * iperf, Copyright (c) 2014, 2017, The Regents of the University of
      3  * California, through Lawrence Berkeley National Laboratory (subject
      4  * to receipt of any required approvals from the U.S. Dept. of
      5  * Energy).  All rights reserved.
      6  *
      7  * If you have questions about your rights to use or distribute this
      8  * software, please contact Berkeley Lab's Technology Transfer
      9  * Department at TTD (at) lbl.gov.
     10  *
     11  * NOTICE.  This software is owned by the U.S. Department of Energy.
     12  * As such, the U.S. Government has been granted for itself and others
     13  * acting on its behalf a paid-up, nonexclusive, irrevocable,
     14  * worldwide license in the Software to reproduce, prepare derivative
     15  * works, and perform publicly and display publicly.  Beginning five
     16  * (5) years after the date permission to assert copyright is obtained
     17  * from the U.S. Department of Energy, and subject to any subsequent
     18  * five (5) year renewals, the U.S. Government is granted for itself
     19  * and others acting on its behalf a paid-up, nonexclusive,
     20  * irrevocable, worldwide license in the Software to reproduce,
     21  * prepare derivative works, distribute copies to the public, perform
     22  * publicly and display publicly, and to permit others to do so.
     23  *
     24  * This code is distributed under a BSD style license, see the LICENSE
     25  * file for complete information.
     26  */
     27 
     28 /*
     29  * routines related to collection TCP_INFO using getsockopt()
     30  *
     31  * Brian Tierney, ESnet  (bltierney (at) es.net)
     32  *
     33  * Note that this is only really useful on Linux.
     34  * XXX: only standard on linux versions 2.4 and later
     35  #
     36  * FreeBSD has a limitted implementation that only includes the following:
     37  *   tcpi_snd_ssthresh, tcpi_snd_cwnd, tcpi_rcv_space, tcpi_rtt
     38  * Based on information on http://wiki.freebsd.org/8.0TODO, I dont think this will be
     39  * fixed before v8.1 at the earliest.
     40  *
     41  * OSX has no support.
     42  *
     43  * I think MS Windows does support TCP_INFO, but iperf3 does not currently support Windows.
     44  */
     45 
     46 #include <stdio.h>
     47 #include <stdlib.h>
     48 #include <sys/param.h>
     49 #include <sys/types.h>
     50 #include <sys/socket.h>
     51 #include <string.h>
     52 #include <netinet/in.h>
     53 #include <errno.h>
     54 
     55 #include "iperf.h"
     56 #include "iperf_api.h"
     57 #include "iperf_locale.h"
     58 
     59 /*************************************************************/
     60 int
     61 has_tcpinfo(void)
     62 {
     63 #if (defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)) \
     64 	&& defined(TCP_INFO)
     65     return 1;
     66 #else
     67     return 0;
     68 #endif
     69 }
     70 
     71 /*************************************************************/
     72 int
     73 has_tcpinfo_retransmits(void)
     74 {
     75 #if defined(linux) && defined(TCP_MD5SIG)
     76     /* TCP_MD5SIG doesn't actually have anything to do with TCP
     77     ** retransmits, it just showed up in the same rev of the header
     78     ** file.  If it's present then struct tcp_info has the
     79     ** tcpi_total_retrans field that we need; if not, not.
     80     */
     81     return 1;
     82 #else
     83 #if defined(__FreeBSD__) && __FreeBSD_version >= 600000
     84     return 1; /* Should work now */
     85 #elif defined(__NetBSD__) && defined(TCP_INFO)
     86     return 1;
     87 #else
     88     return 0;
     89 #endif
     90 #endif
     91 }
     92 
     93 /*************************************************************/
     94 void
     95 save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp)
     96 {
     97 #if (defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)) && \
     98 	defined(TCP_INFO)
     99     socklen_t tcp_info_length = sizeof(struct tcp_info);
    100 
    101     if (getsockopt(sp->socket, IPPROTO_TCP, TCP_INFO, (void *)&irp->tcpInfo, &tcp_info_length) < 0)
    102 	iperf_err(sp->test, "getsockopt - %s", strerror(errno));
    103 
    104     if (sp->test->debug) {
    105 	printf("tcpi_snd_cwnd %u tcpi_snd_mss %u tcpi_rtt %u\n",
    106 	       irp->tcpInfo.tcpi_snd_cwnd, irp->tcpInfo.tcpi_snd_mss,
    107 	       irp->tcpInfo.tcpi_rtt);
    108     }
    109 
    110 #endif
    111 }
    112 
    113 /*************************************************************/
    114 long
    115 get_total_retransmits(struct iperf_interval_results *irp)
    116 {
    117 #if defined(linux) && defined(TCP_MD5SIG)
    118     return irp->tcpInfo.tcpi_total_retrans;
    119 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
    120     return irp->tcpInfo.tcpi_snd_rexmitpack;
    121 #elif defined(__NetBSD__) && defined(TCP_INFO)
    122     return irp->tcpInfo.tcpi_snd_rexmitpack;
    123 #else
    124     return -1;
    125 #endif
    126 }
    127 
    128 /*************************************************************/
    129 /*
    130  * Return snd_cwnd in octets.
    131  */
    132 long
    133 get_snd_cwnd(struct iperf_interval_results *irp)
    134 {
    135 #if defined(linux) && defined(TCP_MD5SIG)
    136     return irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
    137 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
    138     return irp->tcpInfo.tcpi_snd_cwnd;
    139 #elif defined(__NetBSD__) && defined(TCP_INFO)
    140     return irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
    141 #else
    142     return -1;
    143 #endif
    144 }
    145 
    146 /*************************************************************/
    147 /*
    148  * Return rtt in usec.
    149  */
    150 long
    151 get_rtt(struct iperf_interval_results *irp)
    152 {
    153 #if defined(linux) && defined(TCP_MD5SIG)
    154     return irp->tcpInfo.tcpi_rtt;
    155 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
    156     return irp->tcpInfo.tcpi_rtt;
    157 #elif defined(__NetBSD__) && defined(TCP_INFO)
    158     return irp->tcpInfo.tcpi_rtt;
    159 #else
    160     return -1;
    161 #endif
    162 }
    163 
    164 /*************************************************************/
    165 /*
    166  * Return rttvar in usec.
    167  */
    168 long
    169 get_rttvar(struct iperf_interval_results *irp)
    170 {
    171 #if defined(linux) && defined(TCP_MD5SIG)
    172     return irp->tcpInfo.tcpi_rttvar;
    173 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
    174     return irp->tcpInfo.tcpi_rttvar;
    175 #elif defined(__NetBSD__) && defined(TCP_INFO)
    176     return irp->tcpInfo.tcpi_rttvar;
    177 #else
    178     return -1;
    179 #endif
    180 }
    181 
    182 /*************************************************************/
    183 /*
    184  * Return PMTU in bytes.
    185  */
    186 long
    187 get_pmtu(struct iperf_interval_results *irp)
    188 {
    189 #if defined(linux) && defined(TCP_MD5SIG)
    190     return irp->tcpInfo.tcpi_pmtu;
    191 #else
    192     return -1;
    193 #endif
    194 }
    195 
    196 /*************************************************************/
    197 void
    198 build_tcpinfo_message(struct iperf_interval_results *r, char *message)
    199 {
    200 #if defined(linux)
    201     sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_snd_ssthresh,
    202 	    r->tcpInfo.tcpi_rcv_ssthresh, r->tcpInfo.tcpi_unacked, r->tcpInfo.tcpi_sacked,
    203 	    r->tcpInfo.tcpi_lost, r->tcpInfo.tcpi_retrans, r->tcpInfo.tcpi_fackets,
    204 	    r->tcpInfo.tcpi_rtt, r->tcpInfo.tcpi_reordering);
    205 #endif
    206 #if defined(__FreeBSD__)
    207     sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd,
    208 	    r->tcpInfo.tcpi_rcv_space, r->tcpInfo.tcpi_snd_ssthresh, r->tcpInfo.tcpi_rtt);
    209 #endif
    210 #if defined(__NetBSD__) && defined(TCP_INFO)
    211     sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd,
    212 	    r->tcpInfo.tcpi_rcv_space, r->tcpInfo.tcpi_snd_ssthresh, r->tcpInfo.tcpi_rtt);
    213 #endif
    214 }
    215