]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/inet.c
network_cmds-511.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 if (interval > 0) {
732 bcopy(&tcpstat, &ptcpstat, len);
733 pr_swcsum = r_swcsum;
734 pt_swcsum = t_swcsum;
735 }
736
737 #undef TCPDIFF
738 #undef p
739 #undef p1a
740 #undef p2
741 #undef p2a
742 #undef p3
743 }
744
745 /*
746 * Dump MPTCP statistics
747 */
748 void
749 mptcp_stats(uint32_t off , char *name, int af)
750 {
751 static struct tcpstat ptcpstat;
752 struct tcpstat tcpstat;
753 size_t len = sizeof tcpstat;
754
755 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
756 warn("sysctl: net.inet.tcp.stats");
757 return;
758 }
759
760 #ifdef INET6
761 if (mptcp_done != 0 && interval == 0)
762 return;
763 else
764 mptcp_done = 1;
765 #endif
766
767 if (interval && vflag > 0)
768 print_time();
769 printf ("%s:\n", name);
770
771 #define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
772 #define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
773 printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
774 #define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
775 printf(m, MPTCPDIFF(f))
776 #define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
777 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
778 MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
779 #define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
780 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
781 #define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
782 printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
783
784 p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
785 p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
786 p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
787 p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
788 p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
789 p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
790 p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
791 "TCP\n");
792 p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
793 "TCP\n");
794 p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
795 p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
796 p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
797 p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
798 p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
799 p3(tcps_mp_switches, "\t%u subflow switch%s\n");
800 p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n");
801 p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n");
802 p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n");
803 p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n");
804 p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n");
805
806 if (interval > 0) {
807 bcopy(&tcpstat, &ptcpstat, len);
808 }
809
810 #undef MPTCPDIFF
811 #undef p
812 #undef p1a
813 #undef p2
814 #undef p2a
815 #undef p3
816 }
817
818 /*
819 * Dump UDP statistics structure.
820 */
821 void
822 udp_stats(uint32_t off , char *name, int af )
823 {
824 static struct udpstat pudpstat;
825 struct udpstat udpstat;
826 size_t len = sizeof udpstat;
827 uint32_t delivered;
828 static uint32_t r_swcsum, pr_swcsum;
829 static uint32_t t_swcsum, pt_swcsum;
830
831 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
832 warn("sysctl: net.inet.udp.stats");
833 return;
834 }
835
836 #ifdef INET6
837 if (udp_done != 0 && interval == 0)
838 return;
839 else
840 udp_done = 1;
841 #endif
842
843 if (interval && vflag > 0)
844 print_time();
845 printf("%s:\n", name);
846
847 #define UDPDIFF(f) (udpstat.f - pudpstat.f)
848 #define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
849 printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
850 #define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
851 printf(m, UDPDIFF(f))
852 #define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
853 printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
854 p(udps_ipackets, "\t%u datagram%s received\n");
855 p1a(udps_hdrops, "\t\t%u with incomplete header\n");
856 p1a(udps_badlen, "\t\t%u with bad data length field\n");
857 p1a(udps_badsum, "\t\t%u with bad checksum\n");
858 p1a(udps_nosum, "\t\t%u with no checksum\n");
859 r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
860 if ((r_swcsum - pr_swcsum) || sflag <= 1)
861 printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
862 p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
863 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
864 #if INET6
865 p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
866 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
867 #endif /* INET6 */
868 p1a(udps_noport, "\t\t%u dropped due to no socket\n");
869 p(udps_noportbcast,
870 "\t\t%u broadcast/multicast datagram%s undelivered\n");
871 /* the next statistic is cumulative in udps_noportbcast */
872 p(udps_filtermcast,
873 "\t\t%u time%s multicast source filter matched\n");
874 p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
875 p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
876 delivered = UDPDIFF(udps_ipackets) -
877 UDPDIFF(udps_hdrops) -
878 UDPDIFF(udps_badlen) -
879 UDPDIFF(udps_badsum) -
880 UDPDIFF(udps_noport) -
881 UDPDIFF(udps_noportbcast) -
882 UDPDIFF(udps_fullsock);
883 if (delivered || sflag <= 1)
884 printf("\t\t%u delivered\n", delivered);
885 p(udps_opackets, "\t%u datagram%s output\n");
886 t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
887 if ((t_swcsum - pt_swcsum) || sflag <= 1)
888 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
889 p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
890 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
891 #if INET6
892 p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
893 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
894 #endif /* INET6 */
895
896 if (interval > 0) {
897 bcopy(&udpstat, &pudpstat, len);
898 pr_swcsum = r_swcsum;
899 pt_swcsum = t_swcsum;
900 }
901
902 #undef UDPDIFF
903 #undef p
904 #undef p1a
905 #undef p2
906 }
907
908 /*
909 * Dump IP statistics structure.
910 */
911 void
912 ip_stats(uint32_t off , char *name, int af )
913 {
914 static struct ipstat pipstat;
915 struct ipstat ipstat;
916 size_t ipstat_len = sizeof ipstat;
917
918 static net_perf_t pout_net_perf, pin_net_perf;
919 net_perf_t out_net_perf, in_net_perf;
920 size_t out_net_perf_len = sizeof (out_net_perf);
921 size_t in_net_perf_len = sizeof (in_net_perf);
922
923 if (sysctlbyname("net.inet.ip.stats", &ipstat, &ipstat_len, 0, 0) < 0) {
924 warn("sysctl: net.inet.ip.stats");
925 return;
926 }
927
928 if (sysctlbyname("net.inet.ip.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
929 warn("sysctl: net.inet.ip.output_perf_data");
930 return;
931 }
932
933 if (sysctlbyname("net.inet.ip.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
934 warn("sysctl: net.inet.ip.input_perf_data");
935 return;
936 }
937
938 if (interval && vflag > 0)
939 print_time();
940 printf("%s:\n", name);
941
942 #define IPDIFF(f) (ipstat.f - pipstat.f)
943 #define p(f, m) if (IPDIFF(f) || sflag <= 1) \
944 printf(m, IPDIFF(f), plural(IPDIFF(f)))
945 #define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
946 printf(m, IPDIFF(f))
947 #define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
948 printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
949
950 p(ips_total, "\t%u total packet%s received\n");
951 p(ips_badsum, "\t\t%u bad header checksum%s\n");
952 p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
953 "\t\t%u header%s (%u byte%s) checksummed in software\n");
954 p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
955 p1a(ips_tooshort, "\t\t%u with data size < data length\n");
956 p1a(ips_adj, "\t\t%u with data size > data length\n");
957 p(ips_adj_hwcsum_clr,
958 "\t\t\t%u packet%s forced to software checksum\n");
959 p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
960 p1a(ips_badhlen, "\t\t%u with header length < data size\n");
961 p1a(ips_badlen, "\t\t%u with data length < header length\n");
962 p1a(ips_badoptions, "\t\t%u with bad options\n");
963 p1a(ips_badvers, "\t\t%u with incorrect version number\n");
964 p(ips_fragments, "\t\t%u fragment%s received\n");
965 p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
966 p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
967 p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
968 p(ips_delivered, "\t\t%u packet%s for this host\n");
969 p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
970 p(ips_forward, "\t\t%u packet%s forwarded");
971 p(ips_fastforward, " (%u packet%s fast forwarded)");
972 if (IPDIFF(ips_forward) || sflag <= 1)
973 putchar('\n');
974 p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
975 p(ips_notmember,
976 "\t\t%u packet%s received for unknown multicast group\n");
977 p(ips_redirectsent, "\t\t%u redirect%s sent\n");
978 p(ips_rxc_collisions, "\t\t%u input packet%s not chained due to collision\n");
979 p(ips_rxc_chained, "\t\t%u input packet%s processed in a chain\n");
980 p(ips_rxc_notchain, "\t\t%u input packet%s unable to chain\n");
981 p(ips_rxc_chainsz_gt2,
982 "\t\t%u input packet chain%s processed with length greater than 2\n");
983 p(ips_rxc_chainsz_gt4,
984 "\t\t%u input packet chain%s processed with length greater than 4\n");
985 p(ips_rxc_notlist,
986 "\t\t%u input packet%s did not go through list processing path\n");
987
988 #define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
989 if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
990 printf("\tInput Performance Stats:\n");
991 printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
992 printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
993 printf("\t\t%f usec per packet\n",
994 (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
995 printf("\t\tHistogram:\n");
996 printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
997 INPERFDIFF(np_hist1));
998 printf("\t\t\t %u < x <= %u: %llu\n",
999 in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
1000 INPERFDIFF(np_hist2));
1001 printf("\t\t\t %u < x <= %u: %llu\n",
1002 in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
1003 INPERFDIFF(np_hist3));
1004 printf("\t\t\t %u < x <= %u: %llu\n",
1005 in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
1006 INPERFDIFF(np_hist4));
1007 printf("\t\t\t %u < x: %llu\n",
1008 in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
1009 }
1010 #undef INPERFDIFF
1011
1012 p(ips_localout, "\t%u packet%s sent from this host\n");
1013 p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
1014 p(ips_odropped,
1015 "\t\t%u output packet%s dropped due to no bufs, etc.\n");
1016 p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
1017 p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
1018 p(ips_ofragments, "\t\t%u fragment%s created\n");
1019 p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
1020 p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
1021 p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
1022 p(ips_pktdropcntrl,
1023 "\t\t%u packet%s dropped due to no bufs for control data\n");
1024 p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
1025 "\t\t%u header%s (%u byte%s) checksummed in software\n");
1026
1027 #define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
1028 if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
1029 printf("\tOutput Performance Stats:\n");
1030 printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
1031 printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
1032 printf("\t\t%f usec per packet\n",
1033 (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
1034 printf("\t\tHistogram:\n");
1035 printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
1036 OUTPERFDIFF(np_hist1));
1037 printf("\t\t\t %u < x <= %u: %llu\n",
1038 out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
1039 OUTPERFDIFF(np_hist2));
1040 printf("\t\t\t %u < x <= %u: %llu\n",
1041 out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
1042 OUTPERFDIFF(np_hist3));
1043 printf("\t\t\t %u < x <= %u: %llu\n",
1044 out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
1045 OUTPERFDIFF(np_hist4));
1046 printf("\t\t\t %u < x: %llu\n",
1047 out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
1048 }
1049 #undef OUTPERFDIFF
1050
1051 if (interval > 0) {
1052 bcopy(&ipstat, &pipstat, ipstat_len);
1053 bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
1054 bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
1055 }
1056
1057 #undef IPDIFF
1058 #undef p
1059 #undef p1a
1060 #undef p2
1061 }
1062
1063 /*
1064 * Dump ARP statistics structure.
1065 */
1066 void
1067 arp_stats(uint32_t off, char *name, int af)
1068 {
1069 static struct arpstat parpstat;
1070 struct arpstat arpstat;
1071 size_t len = sizeof (arpstat);
1072
1073 if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
1074 &len, 0, 0) < 0) {
1075 warn("sysctl: net.link.ether.inet.stats");
1076 return;
1077 }
1078
1079 if (interval && vflag > 0)
1080 print_time();
1081 printf("%s:\n", name);
1082
1083 #define ARPDIFF(f) (arpstat.f - parpstat.f)
1084 #define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
1085 printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
1086 #define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
1087 printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
1088 #define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \
1089 printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f)))
1090
1091 p(txrequests, "\t%u broadast ARP request%s sent\n");
1092 p(txurequests, "\t%u unicast ARP request%s sent\n");
1093 p2(txreplies, "\t%u ARP repl%s sent\n");
1094 p(txannounces, "\t%u ARP announcement%s sent\n");
1095 p(rxrequests, "\t%u ARP request%s received\n");
1096 p2(rxreplies, "\t%u ARP repl%s received\n");
1097 p(received, "\t%u total ARP packet%s received\n");
1098 p(txconflicts, "\t%u ARP conflict probe%s sent\n");
1099 p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
1100 p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
1101 p3(held, "\t%u total packet%s held awaiting ARP repl%s\n");
1102 p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
1103 p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
1104 p2(timeouts, "\t%u ARP entr%s timed out\n");
1105 p(dupips, "\t%u Duplicate IP%s seen\n");
1106
1107 if (interval > 0)
1108 bcopy(&arpstat, &parpstat, len);
1109
1110 #undef ARPDIFF
1111 #undef p
1112 #undef p2
1113 }
1114
1115 static char *icmpnames[] = {
1116 "echo reply",
1117 "#1",
1118 "#2",
1119 "destination unreachable",
1120 "source quench",
1121 "routing redirect",
1122 "#6",
1123 "#7",
1124 "echo",
1125 "router advertisement",
1126 "router solicitation",
1127 "time exceeded",
1128 "parameter problem",
1129 "time stamp",
1130 "time stamp reply",
1131 "information request",
1132 "information request reply",
1133 "address mask request",
1134 "address mask reply",
1135 };
1136
1137 /*
1138 * Dump ICMP statistics.
1139 */
1140 void
1141 icmp_stats(uint32_t off , char *name, int af )
1142 {
1143 static struct icmpstat picmpstat;
1144 struct icmpstat icmpstat;
1145 int i, first;
1146 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
1147 size_t len;
1148
1149 mib[0] = CTL_NET;
1150 mib[1] = PF_INET;
1151 mib[2] = IPPROTO_ICMP;
1152 mib[3] = ICMPCTL_STATS;
1153
1154 len = sizeof icmpstat;
1155 memset(&icmpstat, 0, len);
1156 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
1157 return; /* XXX should complain, but not traditional */
1158
1159 if (interval && vflag > 0)
1160 print_time();
1161 printf("%s:\n", name);
1162
1163 #define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
1164 #define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1165 printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
1166 #define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1167 printf(m, ICMPDIFF(f))
1168
1169 p(icps_error, "\t%u call%s to icmp_error\n");
1170 p(icps_oldicmp,
1171 "\t%u error%s not generated 'cuz old message was icmp\n");
1172 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1173 if (ICMPDIFF(icps_outhist[i]) != 0) {
1174 if (first) {
1175 printf("\tOutput histogram:\n");
1176 first = 0;
1177 }
1178 printf("\t\t%s: %u\n", icmpnames[i],
1179 ICMPDIFF(icps_outhist[i]));
1180 }
1181 p(icps_badcode, "\t%u message%s with bad code fields\n");
1182 p(icps_tooshort, "\t%u message%s < minimum length\n");
1183 p(icps_checksum, "\t%u bad checksum%s\n");
1184 p(icps_badlen, "\t%u message%s with bad length\n");
1185 p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
1186 p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
1187 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1188 if (ICMPDIFF(icps_inhist[i]) != 0) {
1189 if (first) {
1190 printf("\tInput histogram:\n");
1191 first = 0;
1192 }
1193 printf("\t\t%s: %u\n", icmpnames[i],
1194 ICMPDIFF(icps_inhist[i]));
1195 }
1196 p(icps_reflect, "\t%u message response%s generated\n");
1197
1198 #undef ICMPDIFF
1199 #undef p
1200 #undef p1a
1201 mib[3] = ICMPCTL_MASKREPL;
1202 len = sizeof i;
1203 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
1204 return;
1205 printf("\tICMP address mask responses are %sabled\n",
1206 i ? "en" : "dis");
1207
1208 if (interval > 0)
1209 bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
1210 }
1211
1212 /*
1213 * Dump IGMP statistics structure.
1214 */
1215 void
1216 igmp_stats(uint32_t off , char *name, int af )
1217 {
1218 static struct igmpstat_v3 pigmpstat;
1219 struct igmpstat_v3 igmpstat;
1220 size_t len = sizeof igmpstat;
1221
1222 if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
1223 warn("sysctl: net.inet.igmp.v3stats");
1224 return;
1225 }
1226
1227 if (igmpstat.igps_version != IGPS_VERSION_3) {
1228 warnx("%s: version mismatch (%d != %d)", __func__,
1229 igmpstat.igps_version, IGPS_VERSION_3);
1230 }
1231 if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
1232 warnx("%s: size mismatch (%d != %d)", __func__,
1233 igmpstat.igps_len, IGPS_VERSION3_LEN);
1234 }
1235
1236 if (interval && vflag > 0)
1237 print_time();
1238 printf("%s:\n", name);
1239
1240 #define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
1241 #define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1242 printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
1243 #define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1244 printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
1245
1246 p64(igps_rcv_total, "\t%ju message%s received\n");
1247 p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1248 p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
1249 p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1250 py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
1251 py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
1252 py64(igps_rcv_badqueries,
1253 "\t%ju membership quer%s received with invalid field(s)\n");
1254 py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
1255 py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
1256 py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
1257 py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
1258 p64(igps_rcv_reports, "\t%ju membership report%s received\n");
1259 p64(igps_rcv_badreports,
1260 "\t%ju membership report%s received with invalid field(s)\n");
1261 p64(igps_rcv_ourreports,
1262 "\t%ju membership report%s received for groups to which we belong\n");
1263 p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
1264 p64(igps_snd_reports, "\t%ju membership report%s sent\n");
1265
1266 if (interval > 0)
1267 bcopy(&igmpstat, &pigmpstat, len);
1268
1269 #undef IGMPDIFF
1270 #undef p64
1271 #undef py64
1272 }
1273
1274 /*
1275 * Pretty print an Internet address (net address + port).
1276 */
1277 void
1278 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
1279 {
1280 struct servent *sp = 0;
1281 char line[80], *cp;
1282 int width;
1283
1284 if (Wflag)
1285 snprintf(line, sizeof(line), "%s.", inetname(in));
1286 else
1287 snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
1288 cp = index(line, '\0');
1289 if (!numeric_port && port)
1290 #ifdef _SERVICE_CACHE_
1291 sp = _serv_cache_getservbyport(port, proto);
1292 #else
1293 sp = getservbyport((int)port, proto);
1294 #endif
1295 if (sp || port == 0)
1296 snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
1297 else
1298 snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
1299 width = (Aflag && !Wflag) ? 18 : 22;
1300 if (Wflag)
1301 printf("%-*s ", width, line);
1302 else
1303 printf("%-*.*s ", width, width, line);
1304 }
1305
1306 /*
1307 * Construct an Internet address representation.
1308 * If the nflag has been supplied, give
1309 * numeric value, otherwise try for symbolic name.
1310 */
1311 char *
1312 inetname(struct in_addr *inp)
1313 {
1314 register char *cp;
1315 static char line[MAXHOSTNAMELEN];
1316 struct hostent *hp;
1317 struct netent *np;
1318
1319 cp = 0;
1320 if (!nflag && inp->s_addr != INADDR_ANY) {
1321 int net = inet_netof(*inp);
1322 int lna = inet_lnaof(*inp);
1323
1324 if (lna == INADDR_ANY) {
1325 np = getnetbyaddr(net, AF_INET);
1326 if (np)
1327 cp = np->n_name;
1328 }
1329 if (cp == 0) {
1330 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
1331 if (hp) {
1332 cp = hp->h_name;
1333 //### trimdomain(cp, strlen(cp));
1334 }
1335 }
1336 }
1337 if (inp->s_addr == INADDR_ANY)
1338 strlcpy(line, "*", sizeof(line));
1339 else if (cp) {
1340 strncpy(line, cp, sizeof(line) - 1);
1341 line[sizeof(line) - 1] = '\0';
1342 } else {
1343 inp->s_addr = ntohl(inp->s_addr);
1344 #define C(x) ((u_int)((x) & 0xff))
1345 snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
1346 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
1347 }
1348 return (line);
1349 }