]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/inet.c
network_cmds-543.50.4.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 #if !TARGET_OS_EMBEDDED
358 printf("%-16.16s ", "Socket");
359 #else
360 printf("%-8.8s ", "Socket");
361 #endif
362 printf("%-9.9s", "Flowhash");
363 }
364 if (Lflag)
365 printf("%-14.14s %-22.22s\n",
366 "Listen", "Local Address");
367 else {
368 printf((Aflag && !Wflag) ?
369 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
370 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
371 "Proto", "Recv-Q", "Send-Q",
372 "Local Address", "Foreign Address",
373 "(state)");
374 if (bflag > 0)
375 printf(" %10.10s %10.10s", "rxbytes", "txbytes");
376 if (prioflag >= 0)
377 printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
378 if (vflag > 0)
379 printf(" %6.6s %6.6s %6.6s %6.6s",
380 "rhiwat", "shiwat", "pid", "epid");
381 printf("\n");
382 }
383 first = 0;
384 }
385 if (Aflag) {
386 if (istcp)
387 #if !TARGET_OS_EMBEDDED
388 printf("%16lx ", (u_long)inp->inp_ppcb);
389 #else
390 printf("%8lx ", (u_long)inp->inp_ppcb);
391
392 #endif
393 else
394 #if !TARGET_OS_EMBEDDED
395 printf("%16lx ", (u_long)so->so_pcb);
396 #else
397 printf("%8lx ", (u_long)so->so_pcb);
398 #endif
399 printf("%8x ", inp->inp_flowhash);
400 }
401 if (Lflag) {
402 char buf[15];
403
404 snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
405 so->so_incqlen, so->so_qlimit);
406 printf("%-14.14s ", buf);
407 }
408 else {
409 const char *vchar;
410
411 #ifdef INET6
412 if ((inp->inp_vflag & INP_IPV6) != 0)
413 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
414 ? "46" : "6 ";
415 else
416 #endif
417 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
418 ? "4 " : " ";
419
420 printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
421 so_rcv->sb_cc,
422 so_snd->sb_cc);
423 }
424 if (nflag) {
425 if (inp->inp_vflag & INP_IPV4) {
426 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
427 name, 1);
428 if (!Lflag)
429 inetprint(&inp->inp_faddr,
430 (int)inp->inp_fport, name, 1);
431 }
432 #ifdef INET6
433 else if (inp->inp_vflag & INP_IPV6) {
434 inet6print(&inp->in6p_laddr,
435 (int)inp->inp_lport, name, 1);
436 if (!Lflag)
437 inet6print(&inp->in6p_faddr,
438 (int)inp->inp_fport, name, 1);
439 } /* else nothing printed now */
440 #endif /* INET6 */
441 } else if (inp->inp_flags & INP_ANONPORT) {
442 if (inp->inp_vflag & INP_IPV4) {
443 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
444 name, 1);
445 if (!Lflag)
446 inetprint(&inp->inp_faddr,
447 (int)inp->inp_fport, name, 0);
448 }
449 #ifdef INET6
450 else if (inp->inp_vflag & INP_IPV6) {
451 inet6print(&inp->in6p_laddr,
452 (int)inp->inp_lport, name, 1);
453 if (!Lflag)
454 inet6print(&inp->in6p_faddr,
455 (int)inp->inp_fport, name, 0);
456 } /* else nothing printed now */
457 #endif /* INET6 */
458 } else {
459 if (inp->inp_vflag & INP_IPV4) {
460 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
461 name, 0);
462 if (!Lflag)
463 inetprint(&inp->inp_faddr,
464 (int)inp->inp_fport, name,
465 inp->inp_lport !=
466 inp->inp_fport);
467 }
468 #ifdef INET6
469 else if (inp->inp_vflag & INP_IPV6) {
470 inet6print(&inp->in6p_laddr,
471 (int)inp->inp_lport, name, 0);
472 if (!Lflag)
473 inet6print(&inp->in6p_faddr,
474 (int)inp->inp_fport, name,
475 inp->inp_lport !=
476 inp->inp_fport);
477 } /* else nothing printed now */
478 #endif /* INET6 */
479 }
480 if (istcp && !Lflag) {
481 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
482 printf("%-11d", tp->t_state);
483 else {
484 printf("%-11s", tcpstates[tp->t_state]);
485 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
486 /* Show T/TCP `hidden state' */
487 if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
488 putchar('*');
489 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
490 }
491 }
492 if (!istcp)
493 printf("%-11s", " ");
494 if (bflag > 0) {
495 int i;
496 u_int64_t rxbytes = 0;
497 u_int64_t txbytes = 0;
498
499 for (i = 0; i < SO_TC_STATS_MAX; i++) {
500 rxbytes += so_stat->xst_tc_stats[i].rxbytes;
501 txbytes += so_stat->xst_tc_stats[i].txbytes;
502 }
503
504 printf(" %10llu %10llu", rxbytes, txbytes);
505 }
506 if (prioflag >= 0) {
507 printf(" %10llu %10llu",
508 prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
509 prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
510 }
511 if (vflag > 0) {
512 printf(" %6u %6u %6u %6u",
513 so_rcv->sb_hiwat,
514 so_snd->sb_hiwat,
515 so->so_last_pid,
516 so->so_e_pid);
517 }
518 putchar('\n');
519 }
520 if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
521 if (oxig->xig_count > xig->xig_count) {
522 printf("Some %s sockets may have been deleted.\n",
523 name);
524 } else if (oxig->xig_count < xig->xig_count) {
525 printf("Some %s sockets may have been created.\n",
526 name);
527 } else {
528 printf("Some %s sockets may have been created or deleted",
529 name);
530 }
531 }
532 free(buf);
533 }
534
535 /*
536 * Dump TCP statistics structure.
537 */
538 void
539 tcp_stats(uint32_t off , char *name, int af)
540 {
541 static struct tcpstat ptcpstat;
542 struct tcpstat tcpstat;
543 size_t len = sizeof tcpstat;
544 static uint32_t r_swcsum, pr_swcsum;
545 static uint32_t t_swcsum, pt_swcsum;
546
547 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
548 warn("sysctl: net.inet.tcp.stats");
549 return;
550 }
551
552 #ifdef INET6
553 if (tcp_done != 0 && interval == 0)
554 return;
555 else
556 tcp_done = 1;
557 #endif
558
559 if (interval && vflag > 0)
560 print_time();
561 printf ("%s:\n", name);
562
563 #define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
564 #define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
565 printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
566 #define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
567 printf(m, TCPDIFF(f))
568 #define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
569 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
570 #define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
571 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
572 #define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
573 printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
574
575 p(tcps_sndtotal, "\t%u packet%s sent\n");
576 p2(tcps_sndpack,tcps_sndbyte,
577 "\t\t%u data packet%s (%u byte%s)\n");
578 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
579 "\t\t%u data packet%s (%u byte%s) retransmitted\n");
580 p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
581 p2a(tcps_sndacks, tcps_delack,
582 "\t\t%u ack-only packet%s (%u delayed)\n");
583 p(tcps_sndurg, "\t\t%u URG only packet%s\n");
584 p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
585 p(tcps_sndwinup, "\t\t%u window update packet%s\n");
586 p(tcps_sndctrl, "\t\t%u control packet%s\n");
587 p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
588 t_swcsum = tcpstat.tcps_snd_swcsum + tcpstat.tcps_snd6_swcsum;
589 if ((t_swcsum - pt_swcsum) || sflag <= 1)
590 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
591 p2(tcps_snd_swcsum, tcps_snd_swcsum_bytes,
592 "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
593 #if INET6
594 p2(tcps_snd6_swcsum, tcps_snd6_swcsum_bytes,
595 "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
596 #endif /* INET6 */
597 p(tcps_rcvtotal, "\t%u packet%s received\n");
598 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
599 p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
600 p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
601 p2(tcps_rcvpack, tcps_rcvbyte,
602 "\t\t%u packet%s (%u byte%s) received in-sequence\n");
603 p2(tcps_rcvduppack, tcps_rcvdupbyte,
604 "\t\t%u completely duplicate packet%s (%u byte%s)\n");
605 p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
606 p(tcps_rcvmemdrop, "\t\t%u received packet%s dropped due to low memory\n");
607 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
608 "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
609 p2(tcps_rcvoopack, tcps_rcvoobyte,
610 "\t\t%u out-of-order packet%s (%u byte%s)\n");
611 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
612 "\t\t%u packet%s (%u byte%s) of data after window\n");
613 p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
614 p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
615 p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
616 p(tcps_badrst, "\t\t%u bad reset%s\n");
617 p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
618 r_swcsum = tcpstat.tcps_rcv_swcsum + tcpstat.tcps_rcv6_swcsum;
619 if ((r_swcsum - pr_swcsum) || sflag <= 1)
620 printf("\t\t%u checksummed in software\n",
621 (r_swcsum - pr_swcsum));
622 p2(tcps_rcv_swcsum, tcps_rcv_swcsum_bytes,
623 "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
624 #if INET6
625 p2(tcps_rcv6_swcsum, tcps_rcv6_swcsum_bytes,
626 "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
627 #endif /* INET6 */
628 p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
629 p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
630 p(tcps_connattempt, "\t%u connection request%s\n");
631 p(tcps_accepts, "\t%u connection accept%s\n");
632 p(tcps_badsyn, "\t%u bad connection attempt%s\n");
633 p(tcps_listendrop, "\t%u listen queue overflow%s\n");
634 p(tcps_connects, "\t%u connection%s established (including accepts)\n");
635 p2(tcps_closed, tcps_drops,
636 "\t%u connection%s closed (including %u drop%s)\n");
637 p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
638 p(tcps_cachedrttvar,
639 "\t\t%u connection%s updated cached RTT variance on close\n");
640 p(tcps_cachedssthresh,
641 "\t\t%u connection%s updated cached ssthresh on close\n");
642 p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
643 p2(tcps_rttupdated, tcps_segstimed,
644 "\t%u segment%s updated rtt (of %u attempt%s)\n");
645 p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
646 p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
647 p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
648 p(tcps_persisttimeo, "\t%u persist timeout%s\n");
649 p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
650 p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
651 p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
652 p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
653 p(tcps_predack, "\t%u correct ACK header prediction%s\n");
654 p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
655 #ifdef TCP_MAX_SACK
656 /* TCP_MAX_SACK indicates the header has the SACK structures */
657 p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
658 p(tcps_sack_rexmits,
659 "\t%u segment rexmit%s in SACK recovery episodes\n");
660 p(tcps_sack_rexmit_bytes,
661 "\t%u byte rexmit%s in SACK recovery episodes\n");
662 p(tcps_sack_rcv_blocks,
663 "\t%u SACK option%s (SACK blocks) received\n");
664 p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
665 p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
666 #endif /* TCP_MAX_SACK */
667
668 p(tcps_coalesced_pack, "\t%u LRO coalesced packet%s\n");
669 p(tcps_flowtbl_full, "\t\t%u time%s LRO flow table was full\n");
670 p(tcps_flowtbl_collision, "\t\t%u collision%s in LRO flow table\n");
671 p(tcps_lro_twopack, "\t\t%u time%s LRO coalesced 2 packets\n");
672 p(tcps_lro_multpack, "\t\t%u time%s LRO coalesced 3 or 4 packets\n");
673 p(tcps_lro_largepack, "\t\t%u time%s LRO coalesced 5 or more packets\n");
674
675 p(tcps_limited_txt, "\t%u limited transmit%s done\n");
676 p(tcps_early_rexmt, "\t%u early retransmit%s done\n");
677 p(tcps_sack_ackadv, "\t%u time%s cumulative ack advanced along with SACK\n");
678 p(tcps_pto, "\t%u probe timeout%s\n");
679 p(tcps_rto_after_pto, "\t\t%u time%s retransmit timeout triggered after probe\n");
680 p(tcps_probe_if, "\t\t%u time%s probe packets were sent for an interface\n");
681 p(tcps_probe_if_conflict, "\t\t%u time%s couldn't send probe packets for an interface\n");
682 p(tcps_tlp_recovery, "\t\t%u time%s fast recovery after tail loss\n");
683 p(tcps_tlp_recoverlastpkt, "\t\t%u time%s recovered last packet \n");
684 p(tcps_pto_in_recovery, "\t\t%u SACK based rescue retransmit%s\n");
685 p(tcps_ecn_client_setup, "\t%u client connection%s attempted to negotiate ECN\n");
686 p(tcps_ecn_client_success, "\t\t%u client connection%s successfully negotiated ECN\n");
687 p(tcps_ecn_not_supported, "\t\t%u time%s graceful fallback to Non-ECN connection\n");
688 p(tcps_ecn_lost_syn, "\t\t%u time%s lost ECN negotiating SYN, followed by retransmission\n");
689 p(tcps_ecn_server_setup, "\t\t%u server connection%s attempted to negotiate ECN\n");
690 p(tcps_ecn_server_success, "\t\t%u server connection%s successfully negotiated ECN\n");
691 p(tcps_ecn_lost_synack, "\t\t%u time%s lost ECN negotiating SYN-ACK, followed by retransmission\n");
692 p(tcps_ecn_recv_ce, "\t\t%u time%s received congestion experienced (CE) notification\n");
693 p(tcps_ecn_recv_ece, "\t\t%u time%s CWR was sent in response to ECE\n");
694 p(tcps_ecn_sent_ece, "\t\t%u time%s sent ECE notification\n");
695 p(tcps_ecn_conn_recv_ce, "\t\t%u connection%s received CE atleast once\n");
696 p(tcps_ecn_conn_recv_ece, "\t\t%u connection%s received ECE atleast once\n");
697 p(tcps_ecn_conn_plnoce, "\t\t%u connection%s using ECN have seen packet loss but no CE\n");
698 p(tcps_ecn_conn_pl_ce, "\t\t%u connection%s using ECN have seen packet loss and CE\n");
699 p(tcps_ecn_conn_nopl_ce, "\t\t%u connection%s using ECN received CE but no packet loss\n");
700 p(tcps_ecn_fallback_synloss, "\t\t%u connection%s fell back to non-ECN due to SYN-loss\n");
701 p(tcps_ecn_fallback_reorder, "\t\t%u connection%s fell back to non-ECN due to reordering\n");
702 p(tcps_ecn_fallback_ce, "\t\t%u connection%s fell back to non-ECN due to excessive CE-markings\n");
703 p(tcps_detect_reordering, "\t%u time%s packet reordering was detected on a connection\n");
704 p(tcps_reordered_pkts, "\t\t%u time%s transmitted packets were reordered\n");
705 p(tcps_delay_recovery, "\t\t%u time%s fast recovery was delayed to handle reordering\n");
706 p(tcps_avoid_rxmt, "\t\t%u time%s retransmission was avoided by delaying recovery\n");
707 p(tcps_unnecessary_rxmt, "\t\t%u retransmission%s not needed \n");
708 p(tcps_dsack_sent, "\t%u time%s DSACK option was sent\n");
709 p(tcps_dsack_recvd, "\t\t%u time%s DSACK option was received\n");
710 p(tcps_dsack_disable, "\t\t%u time%s DSACK was disabled on a connection\n");
711 p(tcps_dsack_badrexmt, "\t\t%u time%s recovered from bad retransmission using DSACK\n");
712 p(tcps_dsack_ackloss,"\t\t%u time%s ignored DSACK due to ack loss\n");
713 p(tcps_dsack_recvd_old,"\t\t%u time%s ignored old DSACK options\n");
714 p(tcps_pmtudbh_reverted, "\t%u time%s PMTU Blackhole detection, size reverted\n");
715 p(tcps_drop_after_sleep, "\t%u connection%s were dropped after long sleep\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_mss_to_default,"\t%u time%s maximum segment size was changed to default\n");
728 p(tcps_mss_to_medium,"\t%u time%s maximum segment size was changed to medium\n");
729 p(tcps_mss_to_low,"\t%u time%s maximum segment size was changed to low\n");
730
731 p(tcps_timer_drift_le_1_ms,"\t%u timer drift%s less or equal to 1 ms\n");
732 p(tcps_timer_drift_le_10_ms,"\t%u timer drift%s less or equal to 10 ms\n");
733 p(tcps_timer_drift_le_20_ms,"\t%u timer drift%s less or equal to 20 ms\n");
734 p(tcps_timer_drift_le_50_ms,"\t%u timer drift%s less or equal to 50 ms\n");
735 p(tcps_timer_drift_le_100_ms,"\t%u timer drift%s less or equal to 100 ms\n");
736 p(tcps_timer_drift_le_200_ms,"\t%u timer drift%s less or equal to 200 ms\n");
737 p(tcps_timer_drift_le_500_ms,"\t%u timer drift%s less or equal to 500 ms\n");
738 p(tcps_timer_drift_le_1000_ms,"\t%u timer drift%s less or equal to 1000 ms\n");
739 p(tcps_timer_drift_gt_1000_ms,"\t%u timer drift%s greater than to 1000 ms\n");
740
741 if (interval > 0) {
742 bcopy(&tcpstat, &ptcpstat, len);
743 pr_swcsum = r_swcsum;
744 pt_swcsum = t_swcsum;
745 }
746
747 #undef TCPDIFF
748 #undef p
749 #undef p1a
750 #undef p2
751 #undef p2a
752 #undef p3
753 }
754
755 /*
756 * Dump MPTCP statistics
757 */
758 void
759 mptcp_stats(uint32_t off , char *name, int af)
760 {
761 static struct tcpstat ptcpstat;
762 struct tcpstat tcpstat;
763 size_t len = sizeof tcpstat;
764
765 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
766 warn("sysctl: net.inet.tcp.stats");
767 return;
768 }
769
770 #ifdef INET6
771 if (mptcp_done != 0 && interval == 0)
772 return;
773 else
774 mptcp_done = 1;
775 #endif
776
777 if (interval && vflag > 0)
778 print_time();
779 printf ("%s:\n", name);
780
781 #define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
782 #define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
783 printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
784 #define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
785 printf(m, MPTCPDIFF(f))
786 #define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
787 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
788 MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
789 #define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
790 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
791 #define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
792 printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
793
794 p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
795 p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
796 p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
797 p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
798 p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
799 p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
800 p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
801 "TCP\n");
802 p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
803 "TCP\n");
804 p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
805 p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
806 p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
807 p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
808 p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
809 p3(tcps_mp_switches, "\t%u subflow switch%s\n");
810 p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n");
811 p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n");
812 p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n");
813 p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n");
814 p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n");
815
816 if (interval > 0) {
817 bcopy(&tcpstat, &ptcpstat, len);
818 }
819
820 #undef MPTCPDIFF
821 #undef p
822 #undef p1a
823 #undef p2
824 #undef p2a
825 #undef p3
826 }
827
828 /*
829 * Dump UDP statistics structure.
830 */
831 void
832 udp_stats(uint32_t off , char *name, int af )
833 {
834 static struct udpstat pudpstat;
835 struct udpstat udpstat;
836 size_t len = sizeof udpstat;
837 uint32_t delivered;
838 static uint32_t r_swcsum, pr_swcsum;
839 static uint32_t t_swcsum, pt_swcsum;
840
841 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
842 warn("sysctl: net.inet.udp.stats");
843 return;
844 }
845
846 #ifdef INET6
847 if (udp_done != 0 && interval == 0)
848 return;
849 else
850 udp_done = 1;
851 #endif
852
853 if (interval && vflag > 0)
854 print_time();
855 printf("%s:\n", name);
856
857 #define UDPDIFF(f) (udpstat.f - pudpstat.f)
858 #define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
859 printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
860 #define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
861 printf(m, UDPDIFF(f))
862 #define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
863 printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
864 p(udps_ipackets, "\t%u datagram%s received\n");
865 p1a(udps_hdrops, "\t\t%u with incomplete header\n");
866 p1a(udps_badlen, "\t\t%u with bad data length field\n");
867 p1a(udps_badsum, "\t\t%u with bad checksum\n");
868 p1a(udps_nosum, "\t\t%u with no checksum\n");
869 r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
870 if ((r_swcsum - pr_swcsum) || sflag <= 1)
871 printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
872 p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
873 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
874 #if INET6
875 p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
876 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
877 #endif /* INET6 */
878 p1a(udps_noport, "\t\t%u dropped due to no socket\n");
879 p(udps_noportbcast,
880 "\t\t%u broadcast/multicast datagram%s undelivered\n");
881 /* the next statistic is cumulative in udps_noportbcast */
882 p(udps_filtermcast,
883 "\t\t%u time%s multicast source filter matched\n");
884 p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
885 p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
886 delivered = UDPDIFF(udps_ipackets) -
887 UDPDIFF(udps_hdrops) -
888 UDPDIFF(udps_badlen) -
889 UDPDIFF(udps_badsum) -
890 UDPDIFF(udps_noport) -
891 UDPDIFF(udps_noportbcast) -
892 UDPDIFF(udps_fullsock);
893 if (delivered || sflag <= 1)
894 printf("\t\t%u delivered\n", delivered);
895 p(udps_opackets, "\t%u datagram%s output\n");
896 t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
897 if ((t_swcsum - pt_swcsum) || sflag <= 1)
898 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
899 p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
900 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
901 #if INET6
902 p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
903 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
904 #endif /* INET6 */
905
906 if (interval > 0) {
907 bcopy(&udpstat, &pudpstat, len);
908 pr_swcsum = r_swcsum;
909 pt_swcsum = t_swcsum;
910 }
911
912 #undef UDPDIFF
913 #undef p
914 #undef p1a
915 #undef p2
916 }
917
918 /*
919 * Dump IP statistics structure.
920 */
921 void
922 ip_stats(uint32_t off , char *name, int af )
923 {
924 static struct ipstat pipstat;
925 struct ipstat ipstat;
926 size_t ipstat_len = sizeof ipstat;
927
928 static net_perf_t pout_net_perf, pin_net_perf;
929 net_perf_t out_net_perf, in_net_perf;
930 size_t out_net_perf_len = sizeof (out_net_perf);
931 size_t in_net_perf_len = sizeof (in_net_perf);
932
933 if (sysctlbyname("net.inet.ip.stats", &ipstat, &ipstat_len, 0, 0) < 0) {
934 warn("sysctl: net.inet.ip.stats");
935 return;
936 }
937
938 if (sysctlbyname("net.inet.ip.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
939 warn("sysctl: net.inet.ip.output_perf_data");
940 return;
941 }
942
943 if (sysctlbyname("net.inet.ip.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
944 warn("sysctl: net.inet.ip.input_perf_data");
945 return;
946 }
947
948 if (interval && vflag > 0)
949 print_time();
950 printf("%s:\n", name);
951
952 #define IPDIFF(f) (ipstat.f - pipstat.f)
953 #define p(f, m) if (IPDIFF(f) || sflag <= 1) \
954 printf(m, IPDIFF(f), plural(IPDIFF(f)))
955 #define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
956 printf(m, IPDIFF(f))
957 #define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
958 printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
959
960 p(ips_total, "\t%u total packet%s received\n");
961 p(ips_badsum, "\t\t%u bad header checksum%s\n");
962 p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
963 "\t\t%u header%s (%u byte%s) checksummed in software\n");
964 p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
965 p1a(ips_tooshort, "\t\t%u with data size < data length\n");
966 p1a(ips_adj, "\t\t%u with data size > data length\n");
967 p(ips_adj_hwcsum_clr,
968 "\t\t\t%u packet%s forced to software checksum\n");
969 p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
970 p1a(ips_badhlen, "\t\t%u with header length < data size\n");
971 p1a(ips_badlen, "\t\t%u with data length < header length\n");
972 p1a(ips_badoptions, "\t\t%u with bad options\n");
973 p1a(ips_badvers, "\t\t%u with incorrect version number\n");
974 p(ips_fragments, "\t\t%u fragment%s received\n");
975 p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
976 p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
977 p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
978 p(ips_delivered, "\t\t%u packet%s for this host\n");
979 p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
980 p(ips_forward, "\t\t%u packet%s forwarded");
981 p(ips_fastforward, " (%u packet%s fast forwarded)");
982 if (IPDIFF(ips_forward) || sflag <= 1)
983 putchar('\n');
984 p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
985 p(ips_notmember,
986 "\t\t%u packet%s received for unknown multicast group\n");
987 p(ips_redirectsent, "\t\t%u redirect%s sent\n");
988 p(ips_rxc_collisions, "\t\t%u input packet%s not chained due to collision\n");
989 p(ips_rxc_chained, "\t\t%u input packet%s processed in a chain\n");
990 p(ips_rxc_notchain, "\t\t%u input packet%s unable to chain\n");
991 p(ips_rxc_chainsz_gt2,
992 "\t\t%u input packet chain%s processed with length greater than 2\n");
993 p(ips_rxc_chainsz_gt4,
994 "\t\t%u input packet chain%s processed with length greater than 4\n");
995 p(ips_rxc_notlist,
996 "\t\t%u input packet%s did not go through list processing path\n");
997
998 #define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
999 if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
1000 printf("\tInput Performance Stats:\n");
1001 printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
1002 printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
1003 printf("\t\t%f usec per packet\n",
1004 (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
1005 printf("\t\tHistogram:\n");
1006 printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
1007 INPERFDIFF(np_hist1));
1008 printf("\t\t\t %u < x <= %u: %llu\n",
1009 in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
1010 INPERFDIFF(np_hist2));
1011 printf("\t\t\t %u < x <= %u: %llu\n",
1012 in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
1013 INPERFDIFF(np_hist3));
1014 printf("\t\t\t %u < x <= %u: %llu\n",
1015 in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
1016 INPERFDIFF(np_hist4));
1017 printf("\t\t\t %u < x: %llu\n",
1018 in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
1019 }
1020 #undef INPERFDIFF
1021
1022 p(ips_localout, "\t%u packet%s sent from this host\n");
1023 p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
1024 p(ips_odropped,
1025 "\t\t%u output packet%s dropped due to no bufs, etc.\n");
1026 p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
1027 p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
1028 p(ips_ofragments, "\t\t%u fragment%s created\n");
1029 p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
1030 p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
1031 p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
1032 p(ips_pktdropcntrl,
1033 "\t\t%u packet%s dropped due to no bufs for control data\n");
1034 p(ips_necp_policy_drop, "\t\t%u packet%s dropped due to NECP policy\n");
1035 p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
1036 "\t\t%u header%s (%u byte%s) checksummed in software\n");
1037
1038 #define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
1039 if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
1040 printf("\tOutput Performance Stats:\n");
1041 printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
1042 printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
1043 printf("\t\t%f usec per packet\n",
1044 (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
1045 printf("\t\tHistogram:\n");
1046 printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
1047 OUTPERFDIFF(np_hist1));
1048 printf("\t\t\t %u < x <= %u: %llu\n",
1049 out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
1050 OUTPERFDIFF(np_hist2));
1051 printf("\t\t\t %u < x <= %u: %llu\n",
1052 out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
1053 OUTPERFDIFF(np_hist3));
1054 printf("\t\t\t %u < x <= %u: %llu\n",
1055 out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
1056 OUTPERFDIFF(np_hist4));
1057 printf("\t\t\t %u < x: %llu\n",
1058 out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
1059 }
1060 #undef OUTPERFDIFF
1061
1062 if (interval > 0) {
1063 bcopy(&ipstat, &pipstat, ipstat_len);
1064 bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
1065 bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
1066 }
1067
1068 #undef IPDIFF
1069 #undef p
1070 #undef p1a
1071 #undef p2
1072 }
1073
1074 /*
1075 * Dump ARP statistics structure.
1076 */
1077 void
1078 arp_stats(uint32_t off, char *name, int af)
1079 {
1080 static struct arpstat parpstat;
1081 struct arpstat arpstat;
1082 size_t len = sizeof (arpstat);
1083
1084 if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
1085 &len, 0, 0) < 0) {
1086 warn("sysctl: net.link.ether.inet.stats");
1087 return;
1088 }
1089
1090 if (interval && vflag > 0)
1091 print_time();
1092 printf("%s:\n", name);
1093
1094 #define ARPDIFF(f) (arpstat.f - parpstat.f)
1095 #define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
1096 printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
1097 #define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
1098 printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
1099 #define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \
1100 printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f)))
1101
1102 p(txrequests, "\t%u broadast ARP request%s sent\n");
1103 p(txurequests, "\t%u unicast ARP request%s sent\n");
1104 p2(txreplies, "\t%u ARP repl%s sent\n");
1105 p(txannounces, "\t%u ARP announcement%s sent\n");
1106 p(rxrequests, "\t%u ARP request%s received\n");
1107 p2(rxreplies, "\t%u ARP repl%s received\n");
1108 p(received, "\t%u total ARP packet%s received\n");
1109 p(txconflicts, "\t%u ARP conflict probe%s sent\n");
1110 p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
1111 p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
1112 p3(held, "\t%u total packet%s held awaiting ARP repl%s\n");
1113 p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
1114 p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
1115 p2(timeouts, "\t%u ARP entr%s timed out\n");
1116 p(dupips, "\t%u Duplicate IP%s seen\n");
1117
1118 if (interval > 0)
1119 bcopy(&arpstat, &parpstat, len);
1120
1121 #undef ARPDIFF
1122 #undef p
1123 #undef p2
1124 }
1125
1126 static char *icmpnames[] = {
1127 "echo reply",
1128 "#1",
1129 "#2",
1130 "destination unreachable",
1131 "source quench",
1132 "routing redirect",
1133 "#6",
1134 "#7",
1135 "echo",
1136 "router advertisement",
1137 "router solicitation",
1138 "time exceeded",
1139 "parameter problem",
1140 "time stamp",
1141 "time stamp reply",
1142 "information request",
1143 "information request reply",
1144 "address mask request",
1145 "address mask reply",
1146 };
1147
1148 /*
1149 * Dump ICMP statistics.
1150 */
1151 void
1152 icmp_stats(uint32_t off , char *name, int af )
1153 {
1154 static struct icmpstat picmpstat;
1155 struct icmpstat icmpstat;
1156 int i, first;
1157 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
1158 size_t len;
1159
1160 mib[0] = CTL_NET;
1161 mib[1] = PF_INET;
1162 mib[2] = IPPROTO_ICMP;
1163 mib[3] = ICMPCTL_STATS;
1164
1165 len = sizeof icmpstat;
1166 memset(&icmpstat, 0, len);
1167 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
1168 return; /* XXX should complain, but not traditional */
1169
1170 if (interval && vflag > 0)
1171 print_time();
1172 printf("%s:\n", name);
1173
1174 #define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
1175 #define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1176 printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
1177 #define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1178 printf(m, ICMPDIFF(f))
1179
1180 p(icps_error, "\t%u call%s to icmp_error\n");
1181 p(icps_oldicmp,
1182 "\t%u error%s not generated 'cuz old message was icmp\n");
1183 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1184 if (ICMPDIFF(icps_outhist[i]) != 0) {
1185 if (first) {
1186 printf("\tOutput histogram:\n");
1187 first = 0;
1188 }
1189 printf("\t\t%s: %u\n", icmpnames[i],
1190 ICMPDIFF(icps_outhist[i]));
1191 }
1192 p(icps_badcode, "\t%u message%s with bad code fields\n");
1193 p(icps_tooshort, "\t%u message%s < minimum length\n");
1194 p(icps_checksum, "\t%u bad checksum%s\n");
1195 p(icps_badlen, "\t%u message%s with bad length\n");
1196 p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
1197 p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
1198 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1199 if (ICMPDIFF(icps_inhist[i]) != 0) {
1200 if (first) {
1201 printf("\tInput histogram:\n");
1202 first = 0;
1203 }
1204 printf("\t\t%s: %u\n", icmpnames[i],
1205 ICMPDIFF(icps_inhist[i]));
1206 }
1207 p(icps_reflect, "\t%u message response%s generated\n");
1208
1209 #undef ICMPDIFF
1210 #undef p
1211 #undef p1a
1212 mib[3] = ICMPCTL_MASKREPL;
1213 len = sizeof i;
1214 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
1215 return;
1216 printf("\tICMP address mask responses are %sabled\n",
1217 i ? "en" : "dis");
1218
1219 if (interval > 0)
1220 bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
1221 }
1222
1223 /*
1224 * Dump IGMP statistics structure.
1225 */
1226 void
1227 igmp_stats(uint32_t off , char *name, int af )
1228 {
1229 static struct igmpstat_v3 pigmpstat;
1230 struct igmpstat_v3 igmpstat;
1231 size_t len = sizeof igmpstat;
1232
1233 if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
1234 warn("sysctl: net.inet.igmp.v3stats");
1235 return;
1236 }
1237
1238 if (igmpstat.igps_version != IGPS_VERSION_3) {
1239 warnx("%s: version mismatch (%d != %d)", __func__,
1240 igmpstat.igps_version, IGPS_VERSION_3);
1241 }
1242 if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
1243 warnx("%s: size mismatch (%d != %d)", __func__,
1244 igmpstat.igps_len, IGPS_VERSION3_LEN);
1245 }
1246
1247 if (interval && vflag > 0)
1248 print_time();
1249 printf("%s:\n", name);
1250
1251 #define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
1252 #define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1253 printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
1254 #define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1255 printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
1256
1257 p64(igps_rcv_total, "\t%ju message%s received\n");
1258 p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1259 p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
1260 p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1261 py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
1262 py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
1263 py64(igps_rcv_badqueries,
1264 "\t%ju membership quer%s received with invalid field(s)\n");
1265 py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
1266 py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
1267 py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
1268 py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
1269 p64(igps_rcv_reports, "\t%ju membership report%s received\n");
1270 p64(igps_rcv_badreports,
1271 "\t%ju membership report%s received with invalid field(s)\n");
1272 p64(igps_rcv_ourreports,
1273 "\t%ju membership report%s received for groups to which we belong\n");
1274 p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
1275 p64(igps_snd_reports, "\t%ju membership report%s sent\n");
1276
1277 if (interval > 0)
1278 bcopy(&igmpstat, &pigmpstat, len);
1279
1280 #undef IGMPDIFF
1281 #undef p64
1282 #undef py64
1283 }
1284
1285 /*
1286 * Pretty print an Internet address (net address + port).
1287 */
1288 void
1289 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
1290 {
1291 struct servent *sp = 0;
1292 char line[80], *cp;
1293 int width;
1294
1295 if (Wflag)
1296 snprintf(line, sizeof(line), "%s.", inetname(in));
1297 else
1298 snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
1299 cp = index(line, '\0');
1300 if (!numeric_port && port)
1301 #ifdef _SERVICE_CACHE_
1302 sp = _serv_cache_getservbyport(port, proto);
1303 #else
1304 sp = getservbyport((int)port, proto);
1305 #endif
1306 if (sp || port == 0)
1307 snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
1308 else
1309 snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
1310 width = (Aflag && !Wflag) ? 18 : 22;
1311 if (Wflag)
1312 printf("%-*s ", width, line);
1313 else
1314 printf("%-*.*s ", width, width, line);
1315 }
1316
1317 /*
1318 * Construct an Internet address representation.
1319 * If the nflag has been supplied, give
1320 * numeric value, otherwise try for symbolic name.
1321 */
1322 char *
1323 inetname(struct in_addr *inp)
1324 {
1325 register char *cp;
1326 static char line[MAXHOSTNAMELEN];
1327 struct hostent *hp;
1328 struct netent *np;
1329
1330 cp = 0;
1331 if (!nflag && inp->s_addr != INADDR_ANY) {
1332 int net = inet_netof(*inp);
1333 int lna = inet_lnaof(*inp);
1334
1335 if (lna == INADDR_ANY) {
1336 np = getnetbyaddr(net, AF_INET);
1337 if (np)
1338 cp = np->n_name;
1339 }
1340 if (cp == 0) {
1341 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
1342 if (hp) {
1343 cp = hp->h_name;
1344 //### trimdomain(cp, strlen(cp));
1345 }
1346 }
1347 }
1348 if (inp->s_addr == INADDR_ANY)
1349 strlcpy(line, "*", sizeof(line));
1350 else if (cp) {
1351 strncpy(line, cp, sizeof(line) - 1);
1352 line[sizeof(line) - 1] = '\0';
1353 } else {
1354 inp->s_addr = ntohl(inp->s_addr);
1355 #define C(x) ((u_int)((x) & 0xff))
1356 snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
1357 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
1358 }
1359 return (line);
1360 }