1 /* $NetBSD: main.c,v 1.72 2009/09/13 02:53:17 elad Exp $ */
4 * Copyright (c) 1983, 1988, 1993
5 * Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\
35 Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
42 __RCSID("$NetBSD: main.c,v 1.72 2009/09/13 02:53:17 elad Exp $");
46 #include <sys/param.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
52 #include <netinet/in.h>
70 { "_mbstat", 0, 0, 0, 0 },
72 { "_ipstat", 0, 0, 0, 0 }, /* not available via kvm */
74 { "_tcbtable", 0, 0, 0, 0 },
76 { "_tcpstat", 0, 0, 0, 0 }, /* not available via kvm */
78 { "_udbtable", 0, 0, 0, 0 },
80 { "_udpstat", 0, 0, 0, 0 }, /* not available via kvm */
82 { "_ifnet", 0, 0, 0, 0 },
84 { "_imp_softc", 0, 0, 0, 0 },
86 { "_icmpstat", 0, 0, 0, 0 }, /* not available via kvm */
88 { "_rtstat", 0, 0, 0, 0 },
90 { "_unixsw", 0, 0, 0, 0 },
92 { "_clnp_stat", 0, 0, 0, 0 },
94 { "_tp_inpcb", 0, 0, 0, 0 },
96 { "_tp_refinfo", 0, 0, 0, 0 },
98 { "_tp_stat", 0, 0, 0, 0 },
100 { "_esis_stat", 0, 0, 0, 0 },
102 { "_nimp", 0, 0, 0, 0 },
104 { "_rt_tables", 0, 0, 0, 0 },
106 { "_cltb", 0, 0, 0, 0 },
107 #define N_CLTPSTAT 19
108 { "_cltpstat", 0, 0, 0, 0 },
110 { "_nfile", 0, 0, 0, 0 },
112 { "_file", 0, 0, 0, 0 },
113 #define N_IGMPSTAT 22
114 { "_igmpstat", 0, 0, 0, 0 }, /* not available via kvm */
115 #define N_MRTPROTO 23
116 { "_ip_mrtproto", 0, 0, 0, 0 },
118 { "_mrtstat", 0, 0, 0, 0 },
119 #define N_MFCHASHTBL 25
120 { "_mfchashtbl", 0, 0, 0, 0 },
122 { "_mfchash", 0, 0, 0, 0 },
123 #define N_VIFTABLE 27
124 { "_viftable", 0, 0, 0, 0 },
126 { "_msize", 0, 0, 0, 0 },
127 #define N_MCLBYTES 29
128 { "_mclbytes", 0, 0, 0, 0 },
130 { "_ddpstat", 0, 0, 0, 0 }, /* not available via kvm */
132 { "_ddpcb", 0, 0, 0, 0 },
134 { "_mbpool", 0, 0, 0, 0 },
136 { "_mclpool", 0, 0, 0, 0 },
138 { "_divcb", 0, 0, 0, 0 },
140 { "_divstat", 0, 0, 0, 0 },
142 { "_ip6stat", 0, 0, 0, 0 }, /* not available via kvm */
143 #define N_TCP6STAT 37
144 { "_tcp6stat", 0, 0, 0, 0 }, /* not available via kvm */
145 #define N_UDP6STAT 38
146 { "_udp6stat", 0, 0, 0, 0 }, /* not available via kvm */
147 #define N_ICMP6STAT 39
148 { "_icmp6stat", 0, 0, 0, 0 }, /* not available via kvm */
149 #define N_IPSECSTAT 40
150 { "_ipsecstat", 0, 0, 0, 0 }, /* not available via kvm */
151 #define N_IPSEC6STAT 41
152 { "_ipsec6stat", 0, 0, 0, 0 }, /* not available via kvm */
153 #define N_PIM6STAT 42
154 { "_pim6stat", 0, 0, 0, 0 }, /* not available via kvm */
155 #define N_MRT6PROTO 43
156 { "_ip6_mrtproto", 0, 0, 0, 0 },
157 #define N_MRT6STAT 44
158 { "_mrt6stat", 0, 0, 0, 0 },
159 #define N_MF6CTABLE 45
160 { "_mf6ctable", 0, 0, 0, 0 },
161 #define N_MIF6TABLE 46
162 { "_mif6table", 0, 0, 0, 0 },
163 #define N_PFKEYSTAT 47
164 { "_pfkeystat", 0, 0, 0, 0 }, /* not available via kvm */
166 { "_arpstat", 0, 0, 0, 0 }, /* not available via kvm */
167 #define N_RIP6STAT 49
168 { "_rip6stat", 0, 0, 0, 0 }, /* not available via kvm */
169 #define N_ARPINTRQ 50
170 { "_arpintrq", 0, 0, 0, 0 },
172 { "_ipintrq", 0, 0, 0, 0 },
173 #define N_IP6INTRQ 52
174 { "_ip6intrq", 0, 0, 0, 0 },
175 #define N_ATINTRQ1 53
176 { "_atintrq1", 0, 0, 0, 0 },
177 #define N_ATINTRQ2 54
178 { "_atintrq2", 0, 0, 0, 0 },
180 { "_nsintrq", 0, 0, 0, 0 },
181 #define N_CLNLINTRQ 56
182 { "_clnlintrq", 0, 0, 0, 0 },
183 #define N_LLCINTRQ 57
184 { "_llcintrq", 0, 0, 0, 0 },
186 { "_hdintrq", 0, 0, 0, 0 },
187 #define N_NATMINTRQ 59
188 { "_natmintrq", 0, 0, 0, 0 },
189 #define N_PPPOEDISCINQ 61
190 { "_ppoediscinq", 0, 0, 0, 0 },
191 #define N_PPPOEINQ 61
192 { "_ppoeinq", 0, 0, 0, 0 },
194 { "_pkintrq", 0, 0, 0, 0 },
195 #define N_HARDCLOCK_TICKS 63
196 { "_hardclock_ticks", 0, 0, 0, 0 },
198 { "_pimstat", 0, 0, 0, 0 },
199 #define N_CARPSTAT 65
200 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */
201 #define N_PFSYNCSTAT 66
202 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */
207 u_char pr_index
; /* index into nlist of cb head */
208 u_char pr_sindex
; /* index into nlist of stat block */
209 u_char pr_wanted
; /* 1 if wanted, 0 otherwise */
210 void (*pr_cblocks
) /* control blocks printing routine */
211 __P((u_long
, const char *));
212 void (*pr_stats
) /* statistics printing routine */
213 __P((u_long
, const char *));
215 __P((const char *)); /* per/if statistics printing routine */
216 void (*pr_dump
) /* PCB state dump routine */
218 const char *pr_name
; /* well-known name */
220 { N_TCBTABLE
, N_TCPSTAT
, 1, protopr
,
221 tcp_stats
, NULL
, tcp_dump
, "tcp" },
222 { N_UDBTABLE
, N_UDPSTAT
, 1, protopr
,
223 udp_stats
, NULL
, 0, "udp" },
224 { -1, N_IPSTAT
, 1, 0,
225 ip_stats
, NULL
, 0, "ip" },
226 { -1, N_ICMPSTAT
, 1, 0,
227 icmp_stats
, NULL
, 0, "icmp" },
228 { -1, N_IGMPSTAT
, 1, 0,
229 igmp_stats
, NULL
, 0, "igmp" },
230 { -1, N_CARPSTAT
, 1, 0,
231 carp_stats
, NULL
, 0, "carp" },
233 { -1, N_IPSECSTAT
, 1, 0,
234 ipsec_switch
, NULL
, 0, "ipsec" },
236 { -1, N_PIMSTAT
, 1, 0,
237 pim_stats
, NULL
, 0, "pim" },
238 { -1, N_PFSYNCSTAT
, 1, 0,
239 pfsync_stats
, NULL
, 0, "pfsync" },
245 struct protox ip6protox
[] = {
246 { -1, N_IP6STAT
, 1, 0,
247 ip6_stats
, ip6_ifstats
, 0, "ip6" },
248 { -1, N_ICMP6STAT
, 1, 0,
249 icmp6_stats
, icmp6_ifstats
, 0, "icmp6" },
251 { N_TCBTABLE
, N_TCP6STAT
, 1, ip6protopr
,
252 tcp6_stats
, NULL
, tcp6_dump
, "tcp6" },
254 { N_TCBTABLE
, N_TCP6STAT
, 1, ip6protopr
,
255 tcp_stats
, NULL
, tcp_dump
, "tcp6" },
257 { N_UDBTABLE
, N_UDP6STAT
, 1, ip6protopr
,
258 udp6_stats
, NULL
, 0, "udp6" },
260 { -1, N_IPSEC6STAT
, 1, 0,
261 ipsec_switch
, NULL
, 0, "ipsec6" },
263 { -1, N_PIM6STAT
, 1, 0,
264 pim6_stats
, NULL
, 0, "pim6" },
265 { -1, N_RIP6STAT
, 1, 0,
266 rip6_stats
, NULL
, 0, "rip6" },
272 struct protox arpprotox
[] = {
273 { -1, N_ARPSTAT
, 1, 0,
274 arp_stats
, NULL
, 0, "arp" },
280 struct protox pfkeyprotox
[] = {
281 { -1, N_PFKEYSTAT
, 1, 0,
282 pfkey_stats
, NULL
, 0, "pfkey" },
289 struct protox atalkprotox
[] = {
290 { N_DDPCB
, N_DDPSTAT
, 1, atalkprotopr
,
291 ddp_stats
, NULL
, 0, "ddp" },
296 struct protox isoprotox
[] = {
297 { ISO_TP
, N_TPSTAT
, 1, iso_protopr
,
298 tp_stats
, NULL
, 0, "tp" },
299 { N_CLTP
, N_CLTPSTAT
, 1, iso_protopr
,
300 cltp_stats
, NULL
, 0, "cltp" },
301 { -1, N_CLNPSTAT
, 1, 0,
302 clnp_stats
, NULL
, 0, "clnp"},
303 { -1, N_ESISSTAT
, 1, 0,
304 esis_stats
, NULL
, 0, "esis"},
310 struct protox
*protoprotox
[] = { protox
,
324 const struct softintrq
{
325 const char *siq_name
;
328 { "arpintrq", N_ARPINTRQ
},
329 { "ipintrq", N_IPINTRQ
},
330 { "ip6intrq", N_IP6INTRQ
},
331 { "atintrq1", N_ATINTRQ1
},
332 { "atintrq2", N_ATINTRQ2
},
333 { "clnlintrq", N_CLNLINTRQ
},
334 { "llcintrq", N_LLCINTRQ
},
335 { "hdintrq", N_HDINTRQ
},
336 { "natmintrq", N_NATMINTRQ
},
337 { "ppoediscinq", N_PPPOEDISCINQ
},
338 { "ppoeinq", N_PPPOEINQ
},
339 { "pkintrq", N_PKINTRQ
},
343 int main
__P((int, char *[]));
344 static void printproto
__P((struct protox
*, const char *));
345 static void print_softintrq
__P((void));
346 static void usage
__P((void));
347 static struct protox
*name2protox
__P((const char *));
348 static struct protox
*knownname
__P((const char *));
349 static void prepare(char *, char *, struct protox
*tp
);
353 int interval
; /* repeat interval for i/f stats */
356 prepare(char *nlistf
, char *memf
, struct protox
*tp
)
358 char buf
[_POSIX2_LINE_MAX
];
361 * Try to figure out if we can use sysctl or not.
363 if (nlistf
!= NULL
&& memf
!= NULL
) {
364 /* Of course, we can't use sysctl with dumps. */
366 errx(EXIT_FAILURE
, "can't use sysctl with dumps");
368 /* If we have -M and -N, we're not dealing with live memory. */
375 (pflag
&& tp
->pr_sindex
== N_TPSTAT
) ||
376 (pflag
&& tp
->pr_sindex
== N_CLTPSTAT
) ||
377 (pflag
&& tp
->pr_sindex
== N_CLNPSTAT
) ||
378 (pflag
&& tp
->pr_sindex
== N_ESISSTAT
) ||
380 (pflag
&& tp
->pr_sindex
== N_PIMSTAT
) ||
382 /* These flags are not yet supported via sysctl(3). */
385 /* We can use sysctl(3). */
389 if (force_sysctl
&& !use_sysctl
) {
390 /* Let the user know what's about to happen. */
391 warnx("forcing sysctl usage even though it might not be "\
398 kvmd
= kvm_openfiles(nlistf
, memf
, NULL
, O_RDONLY
, buf
);
399 (void)setgid(getgid());
401 err(1, "kvm error: %s", buf
);
403 if (kvm_nlist(kvmd
, nl
) < 0 || nl
[0].n_type
== 0) {
405 errx(1, "%s: no namelist", nlistf
);
407 errx(1, "no namelist");
410 (void)setgid(getgid());
419 struct protox
*tp
; /* for printing cblocks & stats */
421 char *nlistf
= NULL
, *memf
= NULL
;
426 (void)setegid(getgid());
431 while ((ch
= getopt(argc
, argv
,
432 "AabBdf:ghI:LliM:mN:nP:p:qrsStuvw:X")) != -1)
450 if (strcmp(optarg
, "inet") == 0)
452 else if (strcmp(optarg
, "inet6") == 0)
454 else if (strcmp(optarg
, "arp") == 0)
456 else if (strcmp(optarg
, "pfkey") == 0)
458 else if (strcmp(optarg
, "unix") == 0
459 || strcmp(optarg
, "local") == 0)
461 else if (strcmp(optarg
, "iso") == 0)
463 else if (strcmp(optarg
, "atalk") == 0)
466 errx(1, "%s: unknown address family",
497 numeric_addr
= numeric_port
= nflag
= 1;
501 pcbaddr
= strtoul(optarg
, &cp
, 16);
502 if (*cp
!= '\0' || errno
== ERANGE
)
503 errx(1, "invalid PCB address %s",
508 if ((tp
= name2protox(optarg
)) == NULL
)
509 errx(1, "%s: unknown or uninstrumented protocol",
535 interval
= atoi(optarg
);
548 #define BACKWARD_COMPATIBILITY
549 #ifdef BACKWARD_COMPATIBILITY
551 if (isdigit((unsigned char)**argv
)) {
552 interval
= atoi(*argv
);
566 prepare(nlistf
, memf
, tp
);
579 mbpr(nl
[N_MBSTAT
].n_value
, nl
[N_MSIZE
].n_value
,
580 nl
[N_MCLBYTES
].n_value
, nl
[N_MBPOOL
].n_value
,
581 nl
[N_MCLPOOL
].n_value
);
586 /* Default to TCP. */
587 tp
= name2protox("tcp");
590 (*tp
->pr_dump
)(pcbaddr
);
592 printf("%s: no PCB dump routine\n", tp
->pr_name
);
596 if (iflag
&& tp
->pr_istats
)
597 intpr(interval
, nl
[N_IFNET
].n_value
, tp
->pr_istats
);
598 else if (tp
->pr_stats
)
599 (*tp
->pr_stats
)(nl
[tp
->pr_sindex
].n_value
,
602 printf("%s: no stats routine\n", tp
->pr_name
);
610 * Keep file descriptors open to avoid overhead
611 * of open/close on each call to get* routines.
619 intpr(interval
, nl
[N_IFNET
].n_value
, NULL
);
624 rt_stats(use_sysctl
? 0 : nl
[N_RTSTAT
].n_value
);
629 routepr(nl
[N_RTREE
].n_value
);
636 if (af
== AF_INET
|| af
== AF_UNSPEC
)
637 mrt_stats(nl
[N_MRTPROTO
].n_value
,
638 nl
[N_MRTSTAT
].n_value
);
640 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
641 mrt6_stats(nl
[N_MRT6PROTO
].n_value
,
642 nl
[N_MRT6STAT
].n_value
);
646 if (af
== AF_INET
|| af
== AF_UNSPEC
)
647 mroutepr(nl
[N_MRTPROTO
].n_value
,
648 nl
[N_MFCHASHTBL
].n_value
,
649 nl
[N_MFCHASH
].n_value
,
650 nl
[N_VIFTABLE
].n_value
);
652 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
653 mroute6pr(nl
[N_MRT6PROTO
].n_value
,
654 nl
[N_MF6CTABLE
].n_value
,
655 nl
[N_MIF6TABLE
].n_value
);
662 if (af
== AF_INET
|| af
== AF_UNSPEC
) {
665 /* ugh, this is O(MN) ... why do we do this? */
666 while ((p
= getprotoent()) != NULL
) {
667 for (tp
= protox
; tp
->pr_name
; tp
++)
668 if (strcmp(tp
->pr_name
, p
->p_name
) == 0)
670 if (tp
->pr_name
== 0 || tp
->pr_wanted
== 0)
672 printproto(tp
, p
->p_name
);
676 for (tp
= protox
; tp
->pr_name
; tp
++)
678 printproto(tp
, tp
->pr_name
);
681 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
682 for (tp
= ip6protox
; tp
->pr_name
; tp
++)
683 printproto(tp
, tp
->pr_name
);
685 if (af
== AF_ARP
|| af
== AF_UNSPEC
)
686 for (tp
= arpprotox
; tp
->pr_name
; tp
++)
687 printproto(tp
, tp
->pr_name
);
689 if (af
== PF_KEY
|| af
== AF_UNSPEC
)
690 for (tp
= pfkeyprotox
; tp
->pr_name
; tp
++)
691 printproto(tp
, tp
->pr_name
);
694 if (af
== AF_APPLETALK
|| af
== AF_UNSPEC
)
695 for (tp
= atalkprotox
; tp
->pr_name
; tp
++)
696 printproto(tp
, tp
->pr_name
);
697 if (af
== AF_ISO
|| af
== AF_UNSPEC
)
698 for (tp
= isoprotox
; tp
->pr_name
; tp
++)
699 printproto(tp
, tp
->pr_name
);
700 if ((af
== AF_LOCAL
|| af
== AF_UNSPEC
) && !sflag
)
701 unixpr(nl
[N_UNIXSW
].n_value
);
707 * Print out protocol statistics or control blocks (per sflag).
708 * If the interface was not specifically requested, and the symbol
709 * is not in the namelist, ignore this one.
716 void (*pr
) __P((u_long
, const char *));
722 intpr(interval
, nl
[N_IFNET
].n_value
,
728 off
= nl
[tp
->pr_sindex
].n_value
;
732 off
= nl
[tp
->pr_index
].n_value
;
734 if (pr
!= NULL
&& ((off
|| af
!= AF_UNSPEC
) || use_sysctl
)) {
740 * Print softintrq status.
745 struct ifqueue intrq
, *ifq
= &intrq
;
746 const struct softintrq
*siq
;
749 for (siq
= softintrq
; siq
->siq_name
!= NULL
; siq
++) {
750 off
= nl
[siq
->siq_index
].n_value
;
754 kread(off
, (char *)ifq
, sizeof(*ifq
));
755 printf("%s:\n", siq
->siq_name
);
756 printf("\tqueue length: %d\n", ifq
->ifq_len
);
757 printf("\tmaximum queue length: %d\n", ifq
->ifq_maxlen
);
758 printf("\tpackets dropped: %d\n", ifq
->ifq_drops
);
763 * Read kernel memory, return 0 on success.
766 kread(addr
, buf
, size
)
772 if (kvm_read(kvmd
, addr
, buf
, size
) != size
) {
773 warnx("%s", kvm_geterr(kvmd
));
784 return (n
!= 1 ? "s" : "");
792 return (n
!= 1 ? "es" : "");
800 kread(nl
[N_HARDCLOCK_TICKS
].n_value
, (char *)&hardticks
,
806 * Find the protox for the given "well-known" name.
808 static struct protox
*
812 struct protox
**tpp
, *tp
;
814 for (tpp
= protoprotox
; *tpp
; tpp
++)
815 for (tp
= *tpp
; tp
->pr_name
; tp
++)
816 if (strcmp(tp
->pr_name
, name
) == 0)
822 * Find the protox corresponding to name.
824 static struct protox
*
829 char **alias
; /* alias from p->aliases */
833 * Try to find the name in the list of "well-known" names. If that
834 * fails, check if name is an alias for an Internet protocol.
836 if ((tp
= knownname(name
)) != NULL
)
839 setprotoent(1); /* make protocol lookup cheaper */
840 while ((p
= getprotoent()) != NULL
) {
841 /* assert: name not same as p->name */
842 for (alias
= p
->p_aliases
; *alias
; alias
++)
843 if (strcmp(name
, *alias
) == 0) {
845 return (knownname(p
->p_name
));
855 const char *progname
= getprogname();
857 (void)fprintf(stderr
,
858 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", progname
);
859 (void)fprintf(stderr
,
860 " %s [-bdgiLmnqrsSv] [-f address_family] [-M core] [-N system]\n",
862 (void)fprintf(stderr
,
863 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname
);
864 (void)fprintf(stderr
,
865 " %s [-p protocol] [-M core] [-N system]\n", progname
);
866 (void)fprintf(stderr
,
867 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname
);
868 (void)fprintf(stderr
,
869 " %s [-p protocol] [-i] [-I Interface] \n", progname
);
870 (void)fprintf(stderr
,
871 " %s [-s] [-f address_family] [-i] [-I Interface]\n", progname
);
872 (void)fprintf(stderr
,
873 " %s [-s] [-B] [-I interface]\n", progname
);