]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/inet.c
network_cmds-596.tar.gz
[apple/network_cmds.git] / netstat.tproj / inet.c
1 /*
2 * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 ** @APPLE_OSREFERENCE_LICENSE_HEADER_END@
26 */
27 /*
28 * Copyright (c) 1983, 1988, 1993, 1995
29 * The Regents of the University of California. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 */
59
60 #include <sys/param.h>
61 #include <sys/queue.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/sysctl.h>
65
66 #include <net/route.h>
67 #include <net/if_arp.h>
68 #include <net/net_perf.h>
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/ip.h>
72 #ifdef INET6
73 #include <netinet/ip6.h>
74 #endif /* INET6 */
75 #include <netinet/in_pcb.h>
76 #include <netinet/ip_icmp.h>
77 #include <netinet/icmp_var.h>
78 #include <netinet/igmp_var.h>
79 #include <netinet/ip_var.h>
80 #include <netinet/tcp.h>
81 #include <netinet/tcpip.h>
82 #include <netinet/tcp_seq.h>
83 #define TCPSTATES
84 #include <netinet/tcp_fsm.h>
85 #include <netinet/tcp_var.h>
86 #include <netinet/udp.h>
87 #include <netinet/udp_var.h>
88
89 #include <arpa/inet.h>
90 #include <err.h>
91 #include <errno.h>
92 #include <netdb.h>
93 #include <stdio.h>
94 #include <stdlib.h>
95 #include <stdint.h>
96 #include <string.h>
97 #include <unistd.h>
98 #include "netstat.h"
99
100 #ifdef __APPLE__
101 #include <TargetConditionals.h>
102 #endif
103
104 #define ROUNDUP64(a) \
105 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
106 #define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
107
108 char *inetname (struct in_addr *);
109 void inetprint (struct in_addr *, int, char *, int);
110 #ifdef INET6
111 extern void inet6print (struct in6_addr *, int, char *, int);
112 static int udp_done, tcp_done;
113 extern int mptcp_done;
114 #endif /* INET6 */
115
116 #ifdef SRVCACHE
117 typedef struct __table_private table_t;
118
119 extern table_t *_nc_table_new(uint32_t n);
120 extern void _nc_table_free(table_t *tin);
121
122 extern void _nc_table_insert(table_t *t, const char *key, void *datum);
123 extern void *_nc_table_find(table_t *t, const char *key);
124 extern void _nc_table_delete(table_t *t, const char *key);
125
126 static table_t *_serv_cache = NULL;
127
128 /*
129 * Read and cache all known services
130 */
131 static void
132 _serv_cache_open()
133 {
134 struct servent *s;
135 char *key, *name, *test;
136
137 if (_serv_cache != NULL) return;
138
139 _serv_cache = _nc_table_new(8192);
140 setservent(0);
141
142 while (NULL != (s = getservent()))
143 {
144 if (s->s_name == NULL) continue;
145 key = NULL;
146 asprintf(&key, "%hu/%s", (unsigned short)ntohs(s->s_port), s->s_proto);
147 name = strdup(s->s_name);
148 test = _nc_table_find(_serv_cache, key);
149 if (test == NULL) _nc_table_insert(_serv_cache, key, name);
150 free(key);
151 }
152
153 endservent();
154 }
155
156 void
157 _serv_cache_close()
158 {
159 _nc_table_free(_serv_cache);
160 _serv_cache = NULL;
161 }
162
163 struct servent *
164 _serv_cache_getservbyport(int port, char *proto)
165 {
166 static struct servent s;
167 char *key;
168 unsigned short p;
169
170 _serv_cache_open();
171
172 memset(&s, 0, sizeof(struct servent));
173 asprintf(&key, "%u/%s", port, (proto == NULL) ? "udp" : proto);
174
175 s.s_name = _nc_table_find(_serv_cache, key);
176 free(key);
177 if (s.s_name == NULL) return NULL;
178
179 p = port;
180 s.s_port = htons(p);
181 s.s_proto = proto;
182 return &s;
183 }
184
185 #endif /* SRVCACHE */
186
187 /*
188 * Print a summary of connections related to an Internet
189 * protocol. For TCP, also give state of connection.
190 * Listening processes (aflag) are suppressed unless the
191 * -a (all) flag is specified.
192 */
193
194 struct xgen_n {
195 u_int32_t xgn_len; /* length of this structure */
196 u_int32_t xgn_kind; /* number of PCBs at this time */
197 };
198
199 #define ALL_XGN_KIND_INP (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_INPCB)
200 #define ALL_XGN_KIND_TCP (ALL_XGN_KIND_INP | XSO_TCPCB)
201
202 void
203 protopr(uint32_t proto, /* for sysctl version we pass proto # */
204 char *name, int af)
205 {
206 int istcp;
207 static int first = 1;
208 char *buf, *next;
209 const char *mibvar;
210 struct xinpgen *xig, *oxig;
211 struct xgen_n *xgn;
212 size_t len;
213 struct xtcpcb_n *tp = NULL;
214 struct xinpcb_n *inp = NULL;
215 struct xsocket_n *so = NULL;
216 struct xsockbuf_n *so_rcv = NULL;
217 struct xsockbuf_n *so_snd = NULL;
218 struct xsockstat_n *so_stat = NULL;
219 int which = 0;
220
221 istcp = 0;
222 switch (proto) {
223 case IPPROTO_TCP:
224 #ifdef INET6
225 if (tcp_done != 0)
226 return;
227 else
228 tcp_done = 1;
229 #endif
230 istcp = 1;
231 mibvar = "net.inet.tcp.pcblist_n";
232 break;
233 case IPPROTO_UDP:
234 #ifdef INET6
235 if (udp_done != 0)
236 return;
237 else
238 udp_done = 1;
239 #endif
240 mibvar = "net.inet.udp.pcblist_n";
241 break;
242 case IPPROTO_DIVERT:
243 mibvar = "net.inet.divert.pcblist_n";
244 break;
245 default:
246 mibvar = "net.inet.raw.pcblist_n";
247 break;
248 }
249 len = 0;
250 if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
251 if (errno != ENOENT)
252 warn("sysctl: %s", mibvar);
253 return;
254 }
255 if ((buf = malloc(len)) == 0) {
256 warn("malloc %lu bytes", (u_long)len);
257 return;
258 }
259 if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
260 warn("sysctl: %s", mibvar);
261 free(buf);
262 return;
263 }
264
265 /*
266 * Bail-out to avoid logic error in the loop below when
267 * there is in fact no more control block to process
268 */
269 if (len <= sizeof(struct xinpgen)) {
270 free(buf);
271 return;
272 }
273
274 oxig = xig = (struct xinpgen *)buf;
275 for (next = buf + ROUNDUP64(xig->xig_len); next < buf + len; next += ROUNDUP64(xgn->xgn_len)) {
276
277 xgn = (struct xgen_n*)next;
278 if (xgn->xgn_len <= sizeof(struct xinpgen))
279 break;
280
281 if ((which & xgn->xgn_kind) == 0) {
282 which |= xgn->xgn_kind;
283 switch (xgn->xgn_kind) {
284 case XSO_SOCKET:
285 so = (struct xsocket_n *)xgn;
286 break;
287 case XSO_RCVBUF:
288 so_rcv = (struct xsockbuf_n *)xgn;
289 break;
290 case XSO_SNDBUF:
291 so_snd = (struct xsockbuf_n *)xgn;
292 break;
293 case XSO_STATS:
294 so_stat = (struct xsockstat_n *)xgn;
295 break;
296 case XSO_INPCB:
297 inp = (struct xinpcb_n *)xgn;
298 break;
299 case XSO_TCPCB:
300 tp = (struct xtcpcb_n *)xgn;
301 break;
302 default:
303 printf("unexpected kind %d\n", xgn->xgn_kind);
304 break;
305 }
306 } else {
307 if (vflag)
308 printf("got %d twice\n", xgn->xgn_kind);
309 }
310
311 if ((istcp && which != ALL_XGN_KIND_TCP) || (!istcp && which != ALL_XGN_KIND_INP))
312 continue;
313 which = 0;
314
315 /* Ignore sockets for protocols other than the desired one. */
316 if (so->xso_protocol != (int)proto)
317 continue;
318
319 /* Ignore PCBs which were freed during copyout. */
320 if (inp->inp_gencnt > oxig->xig_gen)
321 continue;
322
323 if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
324 #ifdef INET6
325 || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
326 #endif /* INET6 */
327 || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
328 #ifdef INET6
329 && (inp->inp_vflag &
330 INP_IPV6) == 0
331 #endif /* INET6 */
332 ))
333 )
334 continue;
335
336 /*
337 * Local address is not an indication of listening socket or
338 * server sockey but just rather the socket has been bound.
339 * That why many UDP sockets were not displayed in the original code.
340 */
341 if (!aflag && istcp && tp->t_state <= TCPS_LISTEN)
342 continue;
343
344 if (Lflag && !so->so_qlimit)
345 continue;
346
347 if (first) {
348 if (!Lflag) {
349 printf("Active Internet connections");
350 if (aflag)
351 printf(" (including servers)");
352 } else
353 printf(
354 "Current listen queue sizes (qlen/incqlen/maxqlen)");
355 putchar('\n');
356 if (Aflag) {
357 printf("%-16.16s ", "Socket");
358 printf("%-9.9s", "Flowhash");
359 }
360 if (Lflag)
361 printf("%-14.14s %-22.22s\n",
362 "Listen", "Local Address");
363 else {
364 printf((Aflag && !Wflag) ?
365 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
366 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
367 "Proto", "Recv-Q", "Send-Q",
368 "Local Address", "Foreign Address",
369 "(state)");
370 if (bflag > 0)
371 printf(" %10.10s %10.10s", "rxbytes", "txbytes");
372 if (prioflag >= 0)
373 printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
374 if (vflag > 0)
375 printf(" %6.6s %6.6s %6.6s %6.6s %6s %10s",
376 "rhiwat", "shiwat", "pid", "epid", "state", "options");
377 printf("\n");
378 }
379 first = 0;
380 }
381 if (Aflag) {
382 if (istcp)
383 printf("%16lx ", (u_long)inp->inp_ppcb);
384 else
385 printf("%16lx ", (u_long)so->so_pcb);
386 printf("%8x ", inp->inp_flowhash);
387 }
388 if (Lflag) {
389 char buf[15];
390
391 snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
392 so->so_incqlen, so->so_qlimit);
393 printf("%-14.14s ", buf);
394 }
395 else {
396 const char *vchar;
397
398 #ifdef INET6
399 if ((inp->inp_vflag & INP_IPV6) != 0)
400 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
401 ? "46" : "6 ";
402 else
403 #endif
404 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
405 ? "4 " : " ";
406
407 printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
408 so_rcv->sb_cc,
409 so_snd->sb_cc);
410 }
411 if (nflag) {
412 if (inp->inp_vflag & INP_IPV4) {
413 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
414 name, 1);
415 if (!Lflag)
416 inetprint(&inp->inp_faddr,
417 (int)inp->inp_fport, name, 1);
418 }
419 #ifdef INET6
420 else if (inp->inp_vflag & INP_IPV6) {
421 inet6print(&inp->in6p_laddr,
422 (int)inp->inp_lport, name, 1);
423 if (!Lflag)
424 inet6print(&inp->in6p_faddr,
425 (int)inp->inp_fport, name, 1);
426 } /* else nothing printed now */
427 #endif /* INET6 */
428 } else if (inp->inp_flags & INP_ANONPORT) {
429 if (inp->inp_vflag & INP_IPV4) {
430 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
431 name, 1);
432 if (!Lflag)
433 inetprint(&inp->inp_faddr,
434 (int)inp->inp_fport, name, 0);
435 }
436 #ifdef INET6
437 else if (inp->inp_vflag & INP_IPV6) {
438 inet6print(&inp->in6p_laddr,
439 (int)inp->inp_lport, name, 1);
440 if (!Lflag)
441 inet6print(&inp->in6p_faddr,
442 (int)inp->inp_fport, name, 0);
443 } /* else nothing printed now */
444 #endif /* INET6 */
445 } else {
446 if (inp->inp_vflag & INP_IPV4) {
447 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
448 name, 0);
449 if (!Lflag)
450 inetprint(&inp->inp_faddr,
451 (int)inp->inp_fport, name,
452 inp->inp_lport !=
453 inp->inp_fport);
454 }
455 #ifdef INET6
456 else if (inp->inp_vflag & INP_IPV6) {
457 inet6print(&inp->in6p_laddr,
458 (int)inp->inp_lport, name, 0);
459 if (!Lflag)
460 inet6print(&inp->in6p_faddr,
461 (int)inp->inp_fport, name,
462 inp->inp_lport !=
463 inp->inp_fport);
464 } /* else nothing printed now */
465 #endif /* INET6 */
466 }
467 if (istcp && !Lflag) {
468 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
469 printf("%-11d", tp->t_state);
470 else {
471 printf("%-11s", tcpstates[tp->t_state]);
472 }
473 }
474 if (!istcp)
475 printf("%-11s", " ");
476 if (bflag > 0) {
477 int i;
478 u_int64_t rxbytes = 0;
479 u_int64_t txbytes = 0;
480
481 for (i = 0; i < SO_TC_STATS_MAX; i++) {
482 rxbytes += so_stat->xst_tc_stats[i].rxbytes;
483 txbytes += so_stat->xst_tc_stats[i].txbytes;
484 }
485
486 printf(" %10llu %10llu", rxbytes, txbytes);
487 }
488 if (prioflag >= 0) {
489 printf(" %10llu %10llu",
490 prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
491 prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
492 }
493 if (vflag > 0) {
494 printf(" %6u %6u %6u %6u 0x%04x 0x%08x",
495 so_rcv->sb_hiwat,
496 so_snd->sb_hiwat,
497 so->so_last_pid,
498 so->so_e_pid,
499 so->so_state,
500 so->so_options);
501 }
502 putchar('\n');
503 }
504 if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
505 if (oxig->xig_count > xig->xig_count) {
506 printf("Some %s sockets may have been deleted.\n",
507 name);
508 } else if (oxig->xig_count < xig->xig_count) {
509 printf("Some %s sockets may have been created.\n",
510 name);
511 } else {
512 printf("Some %s sockets may have been created or deleted",
513 name);
514 }
515 }
516 free(buf);
517 }
518
519 /*
520 * Dump TCP statistics structure.
521 */
522 void
523 tcp_stats(uint32_t off , char *name, int af)
524 {
525 static struct tcpstat ptcpstat;
526 struct tcpstat tcpstat;
527 size_t len = sizeof tcpstat;
528 static uint32_t r_swcsum, pr_swcsum;
529 static uint32_t t_swcsum, pt_swcsum;
530
531 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
532 warn("sysctl: net.inet.tcp.stats");
533 return;
534 }
535
536 #ifdef INET6
537 if (tcp_done != 0 && interval == 0)
538 return;
539 else
540 tcp_done = 1;
541 #endif
542
543 if (interval && vflag > 0)
544 print_time();
545 printf ("%s:\n", name);
546
547 #define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
548 #define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
549 printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
550 #define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
551 printf(m, TCPDIFF(f))
552 #define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
553 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
554 #define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
555 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
556 #define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
557 printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
558
559 p(tcps_sndtotal, "\t%u packet%s sent\n");
560 p2(tcps_sndpack,tcps_sndbyte,
561 "\t\t%u data packet%s (%u byte%s)\n");
562 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
563 "\t\t%u data packet%s (%u byte%s) retransmitted\n");
564 p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
565 p2a(tcps_sndacks, tcps_delack,
566 "\t\t%u ack-only packet%s (%u delayed)\n");
567 p(tcps_sndurg, "\t\t%u URG only packet%s\n");
568 p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
569 p(tcps_sndwinup, "\t\t%u window update packet%s\n");
570 p(tcps_sndctrl, "\t\t%u control packet%s\n");
571 p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
572 p(tcps_synchallenge, "\t\t%u challenge ACK%s sent due to unexpected SYN\n");
573 p(tcps_rstchallenge, "\t\t%u challenge ACK%s sent due to unexpected RST\n");
574 t_swcsum = tcpstat.tcps_snd_swcsum + tcpstat.tcps_snd6_swcsum;
575 if ((t_swcsum - pt_swcsum) || sflag <= 1)
576 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
577 p2(tcps_snd_swcsum, tcps_snd_swcsum_bytes,
578 "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
579 #if INET6
580 p2(tcps_snd6_swcsum, tcps_snd6_swcsum_bytes,
581 "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
582 #endif /* INET6 */
583 p(tcps_rcvtotal, "\t%u packet%s received\n");
584 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
585 p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
586 p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
587 p2(tcps_rcvpack, tcps_rcvbyte,
588 "\t\t%u packet%s (%u byte%s) received in-sequence\n");
589 p2(tcps_rcvduppack, tcps_rcvdupbyte,
590 "\t\t%u completely duplicate packet%s (%u byte%s)\n");
591 p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
592 p(tcps_rcvmemdrop, "\t\t%u received packet%s dropped due to low memory\n");
593 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
594 "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
595 p2(tcps_rcvoopack, tcps_rcvoobyte,
596 "\t\t%u out-of-order packet%s (%u byte%s)\n");
597 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
598 "\t\t%u packet%s (%u byte%s) of data after window\n");
599 p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
600 p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
601 p(tcps_recovered_pkts, "\t\t%u packet%s recovered after loss\n");
602 p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
603 p(tcps_badrst, "\t\t%u bad reset%s\n");
604 p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
605 r_swcsum = tcpstat.tcps_rcv_swcsum + tcpstat.tcps_rcv6_swcsum;
606 if ((r_swcsum - pr_swcsum) || sflag <= 1)
607 printf("\t\t%u checksummed in software\n",
608 (r_swcsum - pr_swcsum));
609 p2(tcps_rcv_swcsum, tcps_rcv_swcsum_bytes,
610 "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
611 #if INET6
612 p2(tcps_rcv6_swcsum, tcps_rcv6_swcsum_bytes,
613 "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
614 #endif /* INET6 */
615 p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
616 p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
617 p(tcps_connattempt, "\t%u connection request%s\n");
618 p(tcps_accepts, "\t%u connection accept%s\n");
619 p(tcps_badsyn, "\t%u bad connection attempt%s\n");
620 p(tcps_listendrop, "\t%u listen queue overflow%s\n");
621 p(tcps_connects, "\t%u connection%s established (including accepts)\n");
622 p2(tcps_closed, tcps_drops,
623 "\t%u connection%s closed (including %u drop%s)\n");
624 p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
625 p(tcps_cachedrttvar,
626 "\t\t%u connection%s updated cached RTT variance on close\n");
627 p(tcps_cachedssthresh,
628 "\t\t%u connection%s updated cached ssthresh on close\n");
629 p(tcps_usedrtt, "\t\t%u connection%s initialized RTT from route cache\n");
630 p(tcps_usedrttvar,
631 "\t\t%u connection%s initialized RTT variance from route cache\n");
632 p(tcps_usedssthresh,
633 "\t\t%u connection%s initialized ssthresh from route cache\n");
634 p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
635 p2(tcps_rttupdated, tcps_segstimed,
636 "\t%u segment%s updated rtt (of %u attempt%s)\n");
637 p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
638 p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
639 p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
640 p(tcps_sndrexmitbad, "\t\t%u unnecessary packet retransmissions%s\n");
641 p(tcps_persisttimeo, "\t%u persist timeout%s\n");
642 p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
643 p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
644 p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
645 p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
646 p(tcps_ka_offload_drops, "\t\t%u connection%s dropped by keepalive offload\n");
647 p(tcps_predack, "\t%u correct ACK header prediction%s\n");
648 p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
649 #ifdef TCP_MAX_SACK
650 /* TCP_MAX_SACK indicates the header has the SACK structures */
651 p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
652 p(tcps_sack_rexmits,
653 "\t%u segment rexmit%s in SACK recovery episodes\n");
654 p(tcps_sack_rexmit_bytes,
655 "\t%u byte rexmit%s in SACK recovery episodes\n");
656 p(tcps_sack_rcv_blocks,
657 "\t%u SACK option%s (SACK blocks) received\n");
658 p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
659 p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
660 #endif /* TCP_MAX_SACK */
661
662 p(tcps_coalesced_pack, "\t%u LRO coalesced packet%s\n");
663 p(tcps_flowtbl_full, "\t\t%u time%s LRO flow table was full\n");
664 p(tcps_flowtbl_collision, "\t\t%u collision%s in LRO flow table\n");
665 p(tcps_lro_twopack, "\t\t%u time%s LRO coalesced 2 packets\n");
666 p(tcps_lro_multpack, "\t\t%u time%s LRO coalesced 3 or 4 packets\n");
667 p(tcps_lro_largepack, "\t\t%u time%s LRO coalesced 5 or more packets\n");
668
669 p(tcps_limited_txt, "\t%u limited transmit%s done\n");
670 p(tcps_early_rexmt, "\t%u early retransmit%s done\n");
671 p(tcps_sack_ackadv, "\t%u time%s cumulative ack advanced along with SACK\n");
672 p(tcps_pto, "\t%u probe timeout%s\n");
673 p(tcps_rto_after_pto, "\t\t%u time%s retransmit timeout triggered after probe\n");
674 p(tcps_probe_if, "\t\t%u time%s probe packets were sent for an interface\n");
675 p(tcps_probe_if_conflict, "\t\t%u time%s couldn't send probe packets for an interface\n");
676 p(tcps_tlp_recovery, "\t\t%u time%s fast recovery after tail loss\n");
677 p(tcps_tlp_recoverlastpkt, "\t\t%u time%s recovered last packet \n");
678 p(tcps_pto_in_recovery, "\t\t%u SACK based rescue retransmit%s\n");
679 p(tcps_ecn_client_setup, "\t%u client connection%s attempted to negotiate ECN\n");
680 p(tcps_ecn_client_success, "\t\t%u client connection%s successfully negotiated ECN\n");
681 p(tcps_ecn_not_supported, "\t\t%u time%s graceful fallback to Non-ECN connection\n");
682 p(tcps_ecn_lost_syn, "\t\t%u time%s lost ECN negotiating SYN, followed by retransmission\n");
683 p(tcps_ecn_server_setup, "\t\t%u server connection%s attempted to negotiate ECN\n");
684 p(tcps_ecn_server_success, "\t\t%u server connection%s successfully negotiated ECN\n");
685 p(tcps_ecn_lost_synack, "\t\t%u time%s lost ECN negotiating SYN-ACK, followed by retransmission\n");
686 p(tcps_ecn_recv_ce, "\t\t%u time%s received congestion experienced (CE) notification\n");
687 p(tcps_ecn_recv_ece, "\t\t%u time%s CWR was sent in response to ECE\n");
688 p(tcps_ecn_sent_ece, "\t\t%u time%s sent ECE notification\n");
689 p(tcps_ecn_conn_recv_ce, "\t\t%u connection%s received CE atleast once\n");
690 p(tcps_ecn_conn_recv_ece, "\t\t%u connection%s received ECE atleast once\n");
691 p(tcps_ecn_conn_plnoce, "\t\t%u connection%s using ECN have seen packet loss but no CE\n");
692 p(tcps_ecn_conn_pl_ce, "\t\t%u connection%s using ECN have seen packet loss and CE\n");
693 p(tcps_ecn_conn_nopl_ce, "\t\t%u connection%s using ECN received CE but no packet loss\n");
694 p(tcps_ecn_fallback_synloss, "\t\t%u connection%s fell back to non-ECN due to SYN-loss\n");
695 p(tcps_ecn_fallback_reorder, "\t\t%u connection%s fell back to non-ECN due to reordering\n");
696 p(tcps_ecn_fallback_ce, "\t\t%u connection%s fell back to non-ECN due to excessive CE-markings\n");
697 p(tcps_ecn_fallback_droprst, "\t\t%u connection%s fell back caused by connection drop due to RST\n");
698 p(tcps_ecn_fallback_droprxmt, "\t\t%u connection%s fell back due to drop after multiple retransmits \n");
699 p(tcps_ecn_fallback_synrst, "\t\t%u connection%s fell back due to RST after SYN\n");
700
701 p(tcps_detect_reordering, "\t%u time%s packet reordering was detected on a connection\n");
702 p(tcps_reordered_pkts, "\t\t%u time%s transmitted packets were reordered\n");
703 p(tcps_delay_recovery, "\t\t%u time%s fast recovery was delayed to handle reordering\n");
704 p(tcps_avoid_rxmt, "\t\t%u time%s retransmission was avoided by delaying recovery\n");
705 p(tcps_unnecessary_rxmt, "\t\t%u retransmission%s not needed \n");
706 p(tcps_tailloss_rto, "\t%u retransmission%s due to tail loss\n");
707 p(tcps_dsack_sent, "\t%u time%s DSACK option was sent\n");
708 p(tcps_dsack_recvd, "\t\t%u time%s DSACK option was received\n");
709 p(tcps_dsack_disable, "\t\t%u time%s DSACK was disabled on a connection\n");
710 p(tcps_dsack_badrexmt, "\t\t%u time%s recovered from bad retransmission using DSACK\n");
711 p(tcps_dsack_ackloss,"\t\t%u time%s ignored DSACK due to ack loss\n");
712 p(tcps_dsack_recvd_old,"\t\t%u time%s ignored old DSACK options\n");
713 p(tcps_pmtudbh_reverted, "\t%u time%s PMTU Blackhole detection, size reverted\n");
714 p(tcps_drop_after_sleep, "\t%u connection%s were dropped after long sleep\n");
715 p(tcps_nostretchack, "\t%u connection%s had stretch ack algorithm disabled\n");
716
717 p(tcps_tfo_cookie_sent,"\t%u time%s a TFO-cookie has been announced\n");
718 p(tcps_tfo_syn_data_rcv,"\t%u SYN%s with data and a valid TFO-cookie have been received\n");
719 p(tcps_tfo_cookie_req_rcv,"\t%u SYN%s with TFO-cookie-request received\n");
720 p(tcps_tfo_cookie_invalid,"\t%u time%s an invalid TFO-cookie has been received\n");
721 p(tcps_tfo_cookie_req,"\t%u time%s we requested a TFO-cookie\n");
722 p(tcps_tfo_cookie_rcv,"\t\t%u time%s the peer announced a TFO-cookie\n");
723 p(tcps_tfo_syn_data_sent,"\t%u time%s we combined SYN with data and a TFO-cookie\n");
724 p(tcps_tfo_syn_data_acked,"\t\t%u time%s our SYN with data has been acknowledged\n");
725 p(tcps_tfo_syn_loss,"\t%u time%s a connection-attempt with TFO fell back to regular TCP\n");
726 p(tcps_tfo_blackhole,"\t%u time%s a TFO-connection blackhole'd\n");
727 p(tcps_tfo_cookie_wrong,"\t%u time%s a TFO-cookie we sent was wrong\n");
728 p(tcps_tfo_no_cookie_rcv,"\t%u time%s did not received a TFO-cookie we asked for\n");
729 p(tcps_tfo_heuristics_disable,"\t%u time%s TFO got disabled due to heuristicsn\n");
730 p(tcps_tfo_sndblackhole,"\t%u time%s TFO got blackholed in the sending direction\n");
731
732 p(tcps_mss_to_default,"\t%u time%s maximum segment size was changed to default\n");
733 p(tcps_mss_to_medium,"\t%u time%s maximum segment size was changed to medium\n");
734 p(tcps_mss_to_low,"\t%u time%s maximum segment size was changed to low\n");
735
736 p(tcps_timer_drift_le_1_ms,"\t%u timer drift%s less or equal to 1 ms\n");
737 p(tcps_timer_drift_le_10_ms,"\t%u timer drift%s less or equal to 10 ms\n");
738 p(tcps_timer_drift_le_20_ms,"\t%u timer drift%s less or equal to 20 ms\n");
739 p(tcps_timer_drift_le_50_ms,"\t%u timer drift%s less or equal to 50 ms\n");
740 p(tcps_timer_drift_le_100_ms,"\t%u timer drift%s less or equal to 100 ms\n");
741 p(tcps_timer_drift_le_200_ms,"\t%u timer drift%s less or equal to 200 ms\n");
742 p(tcps_timer_drift_le_500_ms,"\t%u timer drift%s less or equal to 500 ms\n");
743 p(tcps_timer_drift_le_1000_ms,"\t%u timer drift%s less or equal to 1000 ms\n");
744 p(tcps_timer_drift_gt_1000_ms,"\t%u timer drift%s greater than to 1000 ms\n");
745
746 if (interval > 0) {
747 bcopy(&tcpstat, &ptcpstat, len);
748 pr_swcsum = r_swcsum;
749 pt_swcsum = t_swcsum;
750 }
751
752 #undef TCPDIFF
753 #undef p
754 #undef p1a
755 #undef p2
756 #undef p2a
757 #undef p3
758 }
759
760 /*
761 * Dump MPTCP statistics
762 */
763 void
764 mptcp_stats(uint32_t off , char *name, int af)
765 {
766 static struct tcpstat ptcpstat;
767 struct tcpstat tcpstat;
768 size_t len = sizeof tcpstat;
769
770 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
771 warn("sysctl: net.inet.tcp.stats");
772 return;
773 }
774
775 #ifdef INET6
776 if (mptcp_done != 0 && interval == 0)
777 return;
778 else
779 mptcp_done = 1;
780 #endif
781
782 if (interval && vflag > 0)
783 print_time();
784 printf ("%s:\n", name);
785
786 #define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
787 #define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
788 printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
789 #define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
790 printf(m, MPTCPDIFF(f))
791 #define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
792 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
793 MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
794 #define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
795 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
796 #define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
797 printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
798
799 p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
800 p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
801 p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
802 p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
803 p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
804 p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
805 p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
806 "TCP\n");
807 p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
808 "TCP\n");
809 p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
810 p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
811 p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
812 p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
813 p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
814 p3(tcps_mp_switches, "\t%u subflow switch%s\n");
815 p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n");
816 p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n");
817 p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n");
818 p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n");
819 p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n");
820
821 if (interval > 0) {
822 bcopy(&tcpstat, &ptcpstat, len);
823 }
824
825 #undef MPTCPDIFF
826 #undef p
827 #undef p1a
828 #undef p2
829 #undef p2a
830 #undef p3
831 }
832
833 /*
834 * Dump UDP statistics structure.
835 */
836 void
837 udp_stats(uint32_t off , char *name, int af )
838 {
839 static struct udpstat pudpstat;
840 struct udpstat udpstat;
841 size_t len = sizeof udpstat;
842 uint32_t delivered;
843 static uint32_t r_swcsum, pr_swcsum;
844 static uint32_t t_swcsum, pt_swcsum;
845
846 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
847 warn("sysctl: net.inet.udp.stats");
848 return;
849 }
850
851 #ifdef INET6
852 if (udp_done != 0 && interval == 0)
853 return;
854 else
855 udp_done = 1;
856 #endif
857
858 if (interval && vflag > 0)
859 print_time();
860 printf("%s:\n", name);
861
862 #define UDPDIFF(f) (udpstat.f - pudpstat.f)
863 #define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
864 printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
865 #define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
866 printf(m, UDPDIFF(f))
867 #define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
868 printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
869 p(udps_ipackets, "\t%u datagram%s received\n");
870 p1a(udps_hdrops, "\t\t%u with incomplete header\n");
871 p1a(udps_badlen, "\t\t%u with bad data length field\n");
872 p1a(udps_badsum, "\t\t%u with bad checksum\n");
873 p1a(udps_nosum, "\t\t%u with no checksum\n");
874 r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
875 if ((r_swcsum - pr_swcsum) || sflag <= 1)
876 printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
877 p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
878 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
879 #if INET6
880 p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
881 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
882 #endif /* INET6 */
883 p1a(udps_noport, "\t\t%u dropped due to no socket\n");
884 p(udps_noportbcast,
885 "\t\t%u broadcast/multicast datagram%s undelivered\n");
886 /* the next statistic is cumulative in udps_noportbcast */
887 p(udps_filtermcast,
888 "\t\t%u time%s multicast source filter matched\n");
889 p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
890 p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
891 delivered = UDPDIFF(udps_ipackets) -
892 UDPDIFF(udps_hdrops) -
893 UDPDIFF(udps_badlen) -
894 UDPDIFF(udps_badsum) -
895 UDPDIFF(udps_noport) -
896 UDPDIFF(udps_noportbcast) -
897 UDPDIFF(udps_fullsock);
898 if (delivered || sflag <= 1)
899 printf("\t\t%u delivered\n", delivered);
900 p(udps_opackets, "\t%u datagram%s output\n");
901 t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
902 if ((t_swcsum - pt_swcsum) || sflag <= 1)
903 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
904 p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
905 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
906 #if INET6
907 p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
908 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
909 #endif /* INET6 */
910
911 if (interval > 0) {
912 bcopy(&udpstat, &pudpstat, len);
913 pr_swcsum = r_swcsum;
914 pt_swcsum = t_swcsum;
915 }
916
917 #undef UDPDIFF
918 #undef p
919 #undef p1a
920 #undef p2
921 }
922
923 /*
924 * Dump IP statistics structure.
925 */
926 void
927 ip_stats(uint32_t off , char *name, int af )
928 {
929 static struct ipstat pipstat;
930 struct ipstat ipstat;
931 size_t ipstat_len = sizeof ipstat;
932
933 static net_perf_t pout_net_perf, pin_net_perf;
934 net_perf_t out_net_perf, in_net_perf;
935 size_t out_net_perf_len = sizeof (out_net_perf);
936 size_t in_net_perf_len = sizeof (in_net_perf);
937
938 if (sysctlbyname("net.inet.ip.stats", &ipstat, &ipstat_len, 0, 0) < 0) {
939 warn("sysctl: net.inet.ip.stats");
940 return;
941 }
942
943 if (sysctlbyname("net.inet.ip.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
944 warn("sysctl: net.inet.ip.output_perf_data");
945 bzero(&out_net_perf, out_net_perf_len);
946 }
947
948 if (sysctlbyname("net.inet.ip.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
949 warn("sysctl: net.inet.ip.input_perf_data");
950 bzero(&in_net_perf, in_net_perf_len);
951 }
952
953 if (interval && vflag > 0)
954 print_time();
955 printf("%s:\n", name);
956
957 #define IPDIFF(f) (ipstat.f - pipstat.f)
958 #define p(f, m) if (IPDIFF(f) || sflag <= 1) \
959 printf(m, IPDIFF(f), plural(IPDIFF(f)))
960 #define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
961 printf(m, IPDIFF(f))
962 #define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
963 printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
964
965 p(ips_total, "\t%u total packet%s received\n");
966 p(ips_badsum, "\t\t%u bad header checksum%s\n");
967 p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
968 "\t\t%u header%s (%u byte%s) checksummed in software\n");
969 p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
970 p1a(ips_tooshort, "\t\t%u with data size < data length\n");
971 p1a(ips_adj, "\t\t%u with data size > data length\n");
972 p(ips_adj_hwcsum_clr,
973 "\t\t\t%u packet%s forced to software checksum\n");
974 p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
975 p1a(ips_badhlen, "\t\t%u with header length < data size\n");
976 p1a(ips_badlen, "\t\t%u with data length < header length\n");
977 p1a(ips_badoptions, "\t\t%u with bad options\n");
978 p1a(ips_badvers, "\t\t%u with incorrect version number\n");
979 p(ips_fragments, "\t\t%u fragment%s received\n");
980 p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
981 p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
982 p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
983 p(ips_delivered, "\t\t%u packet%s for this host\n");
984 p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
985 p(ips_forward, "\t\t%u packet%s forwarded");
986 p(ips_fastforward, " (%u packet%s fast forwarded)");
987 if (IPDIFF(ips_forward) || sflag <= 1)
988 putchar('\n');
989 p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
990 p(ips_notmember,
991 "\t\t%u packet%s received for unknown multicast group\n");
992 p(ips_redirectsent, "\t\t%u redirect%s sent\n");
993 p(ips_rxc_collisions, "\t\t%u input packet%s not chained due to collision\n");
994 p(ips_rxc_chained, "\t\t%u input packet%s processed in a chain\n");
995 p(ips_rxc_notchain, "\t\t%u input packet%s unable to chain\n");
996 p(ips_rxc_chainsz_gt2,
997 "\t\t%u input packet chain%s processed with length greater than 2\n");
998 p(ips_rxc_chainsz_gt4,
999 "\t\t%u input packet chain%s processed with length greater than 4\n");
1000 p(ips_rxc_notlist,
1001 "\t\t%u input packet%s did not go through list processing path\n");
1002
1003 #define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
1004 if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
1005 printf("\tInput Performance Stats:\n");
1006 printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
1007 printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
1008 printf("\t\t%f usec per packet\n",
1009 (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
1010 printf("\t\tHistogram:\n");
1011 printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
1012 INPERFDIFF(np_hist1));
1013 printf("\t\t\t %u < x <= %u: %llu\n",
1014 in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
1015 INPERFDIFF(np_hist2));
1016 printf("\t\t\t %u < x <= %u: %llu\n",
1017 in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
1018 INPERFDIFF(np_hist3));
1019 printf("\t\t\t %u < x <= %u: %llu\n",
1020 in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
1021 INPERFDIFF(np_hist4));
1022 printf("\t\t\t %u < x: %llu\n",
1023 in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
1024 }
1025 #undef INPERFDIFF
1026
1027 p(ips_localout, "\t%u packet%s sent from this host\n");
1028 p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
1029 p(ips_odropped,
1030 "\t\t%u output packet%s dropped due to no bufs, etc.\n");
1031 p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
1032 p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
1033 p(ips_ofragments, "\t\t%u fragment%s created\n");
1034 p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
1035 p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
1036 p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
1037 p(ips_pktdropcntrl,
1038 "\t\t%u packet%s dropped due to no bufs for control data\n");
1039 p(ips_necp_policy_drop, "\t\t%u packet%s dropped due to NECP policy\n");
1040 p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
1041 "\t\t%u header%s (%u byte%s) checksummed in software\n");
1042
1043 #define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
1044 if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
1045 printf("\tOutput Performance Stats:\n");
1046 printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
1047 printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
1048 printf("\t\t%f usec per packet\n",
1049 (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
1050 printf("\t\tHistogram:\n");
1051 printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
1052 OUTPERFDIFF(np_hist1));
1053 printf("\t\t\t %u < x <= %u: %llu\n",
1054 out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
1055 OUTPERFDIFF(np_hist2));
1056 printf("\t\t\t %u < x <= %u: %llu\n",
1057 out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
1058 OUTPERFDIFF(np_hist3));
1059 printf("\t\t\t %u < x <= %u: %llu\n",
1060 out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
1061 OUTPERFDIFF(np_hist4));
1062 printf("\t\t\t %u < x: %llu\n",
1063 out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
1064 }
1065 #undef OUTPERFDIFF
1066
1067 if (interval > 0) {
1068 bcopy(&ipstat, &pipstat, ipstat_len);
1069 bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
1070 bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
1071 }
1072
1073 #undef IPDIFF
1074 #undef p
1075 #undef p1a
1076 #undef p2
1077 }
1078
1079 /*
1080 * Dump ARP statistics structure.
1081 */
1082 void
1083 arp_stats(uint32_t off, char *name, int af)
1084 {
1085 static struct arpstat parpstat;
1086 struct arpstat arpstat;
1087 size_t len = sizeof (arpstat);
1088
1089 if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
1090 &len, 0, 0) < 0) {
1091 warn("sysctl: net.link.ether.inet.stats");
1092 return;
1093 }
1094
1095 if (interval && vflag > 0)
1096 print_time();
1097 printf("%s:\n", name);
1098
1099 #define ARPDIFF(f) (arpstat.f - parpstat.f)
1100 #define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
1101 printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
1102 #define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
1103 printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
1104 #define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \
1105 printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f)))
1106
1107 p(txrequests, "\t%u broadast ARP request%s sent\n");
1108 p(txurequests, "\t%u unicast ARP request%s sent\n");
1109 p2(txreplies, "\t%u ARP repl%s sent\n");
1110 p(txannounces, "\t%u ARP announcement%s sent\n");
1111 p(rxrequests, "\t%u ARP request%s received\n");
1112 p2(rxreplies, "\t%u ARP repl%s received\n");
1113 p(received, "\t%u total ARP packet%s received\n");
1114 p(txconflicts, "\t%u ARP conflict probe%s sent\n");
1115 p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
1116 p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
1117 p3(held, "\t%u total packet%s held awaiting ARP repl%s\n");
1118 p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
1119 p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
1120 p2(timeouts, "\t%u ARP entr%s timed out\n");
1121 p(dupips, "\t%u Duplicate IP%s seen\n");
1122
1123 if (interval > 0)
1124 bcopy(&arpstat, &parpstat, len);
1125
1126 #undef ARPDIFF
1127 #undef p
1128 #undef p2
1129 }
1130
1131 static char *icmpnames[] = {
1132 "echo reply",
1133 "#1",
1134 "#2",
1135 "destination unreachable",
1136 "source quench",
1137 "routing redirect",
1138 "#6",
1139 "#7",
1140 "echo",
1141 "router advertisement",
1142 "router solicitation",
1143 "time exceeded",
1144 "parameter problem",
1145 "time stamp",
1146 "time stamp reply",
1147 "information request",
1148 "information request reply",
1149 "address mask request",
1150 "address mask reply",
1151 };
1152
1153 /*
1154 * Dump ICMP statistics.
1155 */
1156 void
1157 icmp_stats(uint32_t off , char *name, int af )
1158 {
1159 static struct icmpstat picmpstat;
1160 struct icmpstat icmpstat;
1161 int i, first;
1162 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
1163 size_t len;
1164
1165 mib[0] = CTL_NET;
1166 mib[1] = PF_INET;
1167 mib[2] = IPPROTO_ICMP;
1168 mib[3] = ICMPCTL_STATS;
1169
1170 len = sizeof icmpstat;
1171 memset(&icmpstat, 0, len);
1172 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
1173 return; /* XXX should complain, but not traditional */
1174
1175 if (interval && vflag > 0)
1176 print_time();
1177 printf("%s:\n", name);
1178
1179 #define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
1180 #define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1181 printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
1182 #define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1183 printf(m, ICMPDIFF(f))
1184
1185 p(icps_error, "\t%u call%s to icmp_error\n");
1186 p(icps_oldicmp,
1187 "\t%u error%s not generated 'cuz old message was icmp\n");
1188 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1189 if (ICMPDIFF(icps_outhist[i]) != 0) {
1190 if (first) {
1191 printf("\tOutput histogram:\n");
1192 first = 0;
1193 }
1194 printf("\t\t%s: %u\n", icmpnames[i],
1195 ICMPDIFF(icps_outhist[i]));
1196 }
1197 p(icps_badcode, "\t%u message%s with bad code fields\n");
1198 p(icps_tooshort, "\t%u message%s < minimum length\n");
1199 p(icps_checksum, "\t%u bad checksum%s\n");
1200 p(icps_badlen, "\t%u message%s with bad length\n");
1201 p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
1202 p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
1203 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1204 if (ICMPDIFF(icps_inhist[i]) != 0) {
1205 if (first) {
1206 printf("\tInput histogram:\n");
1207 first = 0;
1208 }
1209 printf("\t\t%s: %u\n", icmpnames[i],
1210 ICMPDIFF(icps_inhist[i]));
1211 }
1212 p(icps_reflect, "\t%u message response%s generated\n");
1213
1214 #undef ICMPDIFF
1215 #undef p
1216 #undef p1a
1217 mib[3] = ICMPCTL_MASKREPL;
1218 len = sizeof i;
1219 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
1220 return;
1221 printf("\tICMP address mask responses are %sabled\n",
1222 i ? "en" : "dis");
1223
1224 if (interval > 0)
1225 bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
1226 }
1227
1228 /*
1229 * Dump IGMP statistics structure.
1230 */
1231 void
1232 igmp_stats(uint32_t off , char *name, int af )
1233 {
1234 static struct igmpstat_v3 pigmpstat;
1235 struct igmpstat_v3 igmpstat;
1236 size_t len = sizeof igmpstat;
1237
1238 if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
1239 warn("sysctl: net.inet.igmp.v3stats");
1240 return;
1241 }
1242
1243 if (igmpstat.igps_version != IGPS_VERSION_3) {
1244 warnx("%s: version mismatch (%d != %d)", __func__,
1245 igmpstat.igps_version, IGPS_VERSION_3);
1246 }
1247 if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
1248 warnx("%s: size mismatch (%d != %d)", __func__,
1249 igmpstat.igps_len, IGPS_VERSION3_LEN);
1250 }
1251
1252 if (interval && vflag > 0)
1253 print_time();
1254 printf("%s:\n", name);
1255
1256 #define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
1257 #define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1258 printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
1259 #define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1260 printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
1261
1262 p64(igps_rcv_total, "\t%ju message%s received\n");
1263 p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1264 p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
1265 p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1266 py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
1267 py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
1268 py64(igps_rcv_badqueries,
1269 "\t%ju membership quer%s received with invalid field(s)\n");
1270 py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
1271 py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
1272 py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
1273 py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
1274 p64(igps_rcv_reports, "\t%ju membership report%s received\n");
1275 p64(igps_rcv_badreports,
1276 "\t%ju membership report%s received with invalid field(s)\n");
1277 p64(igps_rcv_ourreports,
1278 "\t%ju membership report%s received for groups to which we belong\n");
1279 p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
1280 p64(igps_snd_reports, "\t%ju membership report%s sent\n");
1281
1282 if (interval > 0)
1283 bcopy(&igmpstat, &pigmpstat, len);
1284
1285 #undef IGMPDIFF
1286 #undef p64
1287 #undef py64
1288 }
1289
1290 /*
1291 * Pretty print an Internet address (net address + port).
1292 */
1293 void
1294 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
1295 {
1296 struct servent *sp = 0;
1297 char line[80], *cp;
1298 int width;
1299
1300 if (Wflag)
1301 snprintf(line, sizeof(line), "%s.", inetname(in));
1302 else
1303 snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
1304 cp = index(line, '\0');
1305 if (!numeric_port && port)
1306 #ifdef _SERVICE_CACHE_
1307 sp = _serv_cache_getservbyport(port, proto);
1308 #else
1309 sp = getservbyport((int)port, proto);
1310 #endif
1311 if (sp || port == 0)
1312 snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
1313 else
1314 snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
1315 width = (Aflag && !Wflag) ? 18 : 22;
1316 if (Wflag)
1317 printf("%-*s ", width, line);
1318 else
1319 printf("%-*.*s ", width, width, line);
1320 }
1321
1322 /*
1323 * Construct an Internet address representation.
1324 * If the nflag has been supplied, give
1325 * numeric value, otherwise try for symbolic name.
1326 */
1327 char *
1328 inetname(struct in_addr *inp)
1329 {
1330 register char *cp;
1331 static char line[MAXHOSTNAMELEN];
1332 struct hostent *hp;
1333 struct netent *np;
1334
1335 cp = 0;
1336 if (!nflag && inp->s_addr != INADDR_ANY) {
1337 int net = inet_netof(*inp);
1338 int lna = inet_lnaof(*inp);
1339
1340 if (lna == INADDR_ANY) {
1341 np = getnetbyaddr(net, AF_INET);
1342 if (np)
1343 cp = np->n_name;
1344 }
1345 if (cp == 0) {
1346 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
1347 if (hp) {
1348 cp = hp->h_name;
1349 //### trimdomain(cp, strlen(cp));
1350 }
1351 }
1352 }
1353 if (inp->s_addr == INADDR_ANY)
1354 strlcpy(line, "*", sizeof(line));
1355 else if (cp) {
1356 strlcpy(line, cp, sizeof(line));
1357 } else {
1358 inp->s_addr = ntohl(inp->s_addr);
1359 #define C(x) ((u_int)((x) & 0xff))
1360 snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
1361 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
1362 }
1363 return (line);
1364 }