• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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@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
has_tcpinfo(void)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
has_tcpinfo_retransmits(void)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
save_tcpinfo(struct iperf_stream * sp,struct iperf_interval_results * irp)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
get_total_retransmits(struct iperf_interval_results * irp)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
get_snd_cwnd(struct iperf_interval_results * irp)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 snd_wnd in octets.
149  */
150 long
get_snd_wnd(struct iperf_interval_results * irp)151 get_snd_wnd(struct iperf_interval_results *irp)
152 {
153 #if !defined(HAVE_TCP_INFO_SND_WND)
154     return -1;
155 #elif defined(linux) && defined(TCP_MD5SIG)
156     return irp->tcpInfo.tcpi_snd_wnd;
157 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
158     return irp->tcpInfo.tcpi_snd_wnd;
159 #elif defined(__NetBSD__) && defined(TCP_INFO)
160     return irp->tcpInfo.tcpi_snd_wnd * irp->tcpInfo.tcpi_snd_mss;
161 #else
162     return -1;
163 #endif
164 }
165 
166 /*************************************************************/
167 /*
168  * Return rtt in usec.
169  */
170 long
get_rtt(struct iperf_interval_results * irp)171 get_rtt(struct iperf_interval_results *irp)
172 {
173 #if defined(linux) && defined(TCP_MD5SIG)
174     return irp->tcpInfo.tcpi_rtt;
175 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
176     return irp->tcpInfo.tcpi_rtt;
177 #elif defined(__NetBSD__) && defined(TCP_INFO)
178     return irp->tcpInfo.tcpi_rtt;
179 #else
180     return -1;
181 #endif
182 }
183 
184 /*************************************************************/
185 /*
186  * Return rttvar in usec.
187  */
188 long
get_rttvar(struct iperf_interval_results * irp)189 get_rttvar(struct iperf_interval_results *irp)
190 {
191 #if defined(linux) && defined(TCP_MD5SIG)
192     return irp->tcpInfo.tcpi_rttvar;
193 #elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
194     return irp->tcpInfo.tcpi_rttvar;
195 #elif defined(__NetBSD__) && defined(TCP_INFO)
196     return irp->tcpInfo.tcpi_rttvar;
197 #else
198     return -1;
199 #endif
200 }
201 
202 /*************************************************************/
203 /*
204  * Return PMTU in bytes.
205  */
206 long
get_pmtu(struct iperf_interval_results * irp)207 get_pmtu(struct iperf_interval_results *irp)
208 {
209 #if defined(linux) && defined(TCP_MD5SIG)
210     return irp->tcpInfo.tcpi_pmtu;
211 #else
212     return -1;
213 #endif
214 }
215 
216 /*************************************************************/
217 void
build_tcpinfo_message(struct iperf_interval_results * r,char * message)218 build_tcpinfo_message(struct iperf_interval_results *r, char *message)
219 {
220 #if defined(linux) && defined(TCP_INFO)
221     sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_snd_ssthresh,
222 	    r->tcpInfo.tcpi_rcv_ssthresh, r->tcpInfo.tcpi_unacked, r->tcpInfo.tcpi_sacked,
223 	    r->tcpInfo.tcpi_lost, r->tcpInfo.tcpi_retrans, r->tcpInfo.tcpi_fackets,
224 	    r->tcpInfo.tcpi_rtt, r->tcpInfo.tcpi_reordering);
225 #endif
226 #if defined(__FreeBSD__) && defined(TCP_INFO)
227     sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd,
228 	    r->tcpInfo.tcpi_rcv_space, r->tcpInfo.tcpi_snd_ssthresh, r->tcpInfo.tcpi_rtt);
229 #endif
230 #if defined(__NetBSD__) && defined(TCP_INFO)
231     sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd,
232 	    r->tcpInfo.tcpi_rcv_space, r->tcpInfo.tcpi_snd_ssthresh, r->tcpInfo.tcpi_rtt);
233 #endif
234 }
235