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