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