• Home
  • History
  • Annotate
  • 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
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