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