1 /* $NetBSD: main.c,v 1.95 2014/11/12 03:34:59 christos 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.95 2014/11/12 03:34:59 christos Exp $");
46 #include <sys/param.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
52 #include <netinet/in.h>
72 { "_mbstat", 0, 0, 0, 0 },
74 { "_ipstat", 0, 0, 0, 0 }, /* not available via kvm */
76 { "_tcbtable", 0, 0, 0, 0 },
78 { "_tcpstat", 0, 0, 0, 0 }, /* not available via kvm */
80 { "_udbtable", 0, 0, 0, 0 },
82 { "_udpstat", 0, 0, 0, 0 }, /* not available via kvm */
83 #define N_IFNET_LIST 6
84 { "_ifnet_list", 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 { "_rt_tables", 0, 0, 0, 0 },
94 { "_nfile", 0, 0, 0, 0 },
96 { "_igmpstat", 0, 0, 0, 0 }, /* not available via kvm */
98 { "_ip_mrtproto", 0, 0, 0, 0 },
100 { "_mrtstat", 0, 0, 0, 0 },
101 #define N_MFCHASHTBL 15
102 { "_mfchashtbl", 0, 0, 0, 0 },
104 { "_mfchash", 0, 0, 0, 0 },
105 #define N_VIFTABLE 17
106 { "_viftable", 0, 0, 0, 0 },
108 { "_msize", 0, 0, 0, 0 },
109 #define N_MCLBYTES 19
110 { "_mclbytes", 0, 0, 0, 0 },
112 { "_ddpstat", 0, 0, 0, 0 }, /* not available via kvm */
114 { "_ddpcb", 0, 0, 0, 0 },
116 { "_mbpool", 0, 0, 0, 0 },
118 { "_mclpool", 0, 0, 0, 0 },
120 { "_ip6stat", 0, 0, 0, 0 }, /* not available via kvm */
121 #define N_TCP6STAT 25
122 { "_tcp6stat", 0, 0, 0, 0 }, /* not available via kvm */
123 #define N_UDP6STAT 26
124 { "_udp6stat", 0, 0, 0, 0 }, /* not available via kvm */
125 #define N_ICMP6STAT 27
126 { "_icmp6stat", 0, 0, 0, 0 }, /* not available via kvm */
127 #define N_IPSECSTAT 28
128 { "_ipsecstat", 0, 0, 0, 0 }, /* not available via kvm */
129 #define N_IPSEC6STAT 29
130 { "_ipsec6stat", 0, 0, 0, 0 }, /* not available via kvm */
131 #define N_PIM6STAT 30
132 { "_pim6stat", 0, 0, 0, 0 }, /* not available via kvm */
133 #define N_MRT6PROTO 31
134 { "_ip6_mrtproto", 0, 0, 0, 0 },
135 #define N_MRT6STAT 32
136 { "_mrt6stat", 0, 0, 0, 0 },
137 #define N_MF6CTABLE 33
138 { "_mf6ctable", 0, 0, 0, 0 },
139 #define N_MIF6TABLE 34
140 { "_mif6table", 0, 0, 0, 0 },
141 #define N_PFKEYSTAT 35
142 { "_pfkeystat", 0, 0, 0, 0 }, /* not available via kvm */
144 { "_arpstat", 0, 0, 0, 0 }, /* not available via kvm */
145 #define N_RIP6STAT 37
146 { "_rip6stat", 0, 0, 0, 0 }, /* not available via kvm */
147 #define N_ARPINTRQ 38
148 { "_arpintrq", 0, 0, 0, 0 },
150 { "_ipintrq", 0, 0, 0, 0 },
151 #define N_IP6INTRQ 40
152 { "_ip6intrq", 0, 0, 0, 0 },
153 #define N_ATINTRQ1 41
154 { "_atintrq1", 0, 0, 0, 0 },
155 #define N_ATINTRQ2 42
156 { "_atintrq2", 0, 0, 0, 0 },
158 { "_nsintrq", 0, 0, 0, 0 },
159 #define N_LLCINTRQ 44
160 { "_llcintrq", 0, 0, 0, 0 },
162 { "_hdintrq", 0, 0, 0, 0 },
163 #define N_NATMINTRQ 46
164 { "_natmintrq", 0, 0, 0, 0 },
165 #define N_PPPOEDISCINQ 47
166 { "_ppoediscinq", 0, 0, 0, 0 },
167 #define N_PPPOEINQ 48
168 { "_ppoeinq", 0, 0, 0, 0 },
170 { "_pkintrq", 0, 0, 0, 0 },
171 #define N_HARDCLOCK_TICKS 50
172 { "_hardclock_ticks", 0, 0, 0, 0 },
174 { "_pimstat", 0, 0, 0, 0 },
175 #define N_CARPSTAT 52
176 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */
177 #define N_PFSYNCSTAT 53
178 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */
183 u_char pr_index
; /* index into nlist of cb head */
184 u_char pr_sindex
; /* index into nlist of stat block */
185 u_char pr_wanted
; /* 1 if wanted, 0 otherwise */
186 void (*pr_cblocks
) /* control blocks printing routine */
187 __P((u_long
, const char *));
188 void (*pr_stats
) /* statistics printing routine */
189 __P((u_long
, const char *));
191 __P((const char *)); /* per/if statistics printing routine */
192 void (*pr_dump
) /* PCB state dump routine */
193 __P((u_long
, const char *, u_long
));
194 const char *pr_name
; /* well-known name */
196 { N_TCBTABLE
, N_TCPSTAT
, 1, protopr
,
197 tcp_stats
, NULL
, tcp_dump
, "tcp" },
198 { N_UDBTABLE
, N_UDPSTAT
, 1, protopr
,
199 udp_stats
, NULL
, 0, "udp" },
200 { -1, N_IPSTAT
, 1, 0,
201 ip_stats
, NULL
, 0, "ip" },
202 { -1, N_ICMPSTAT
, 1, 0,
203 icmp_stats
, NULL
, 0, "icmp" },
204 { -1, N_IGMPSTAT
, 1, 0,
205 igmp_stats
, NULL
, 0, "igmp" },
206 { -1, N_CARPSTAT
, 1, 0,
207 carp_stats
, NULL
, 0, "carp" },
209 { -1, N_IPSECSTAT
, 1, 0,
210 fast_ipsec_stats
, NULL
, 0, "ipsec" },
212 { -1, N_PIMSTAT
, 1, 0,
213 pim_stats
, NULL
, 0, "pim" },
214 { -1, N_PFSYNCSTAT
, 1, 0,
215 pfsync_stats
, NULL
, 0, "pfsync" },
221 struct protox ip6protox
[] = {
222 { -1, N_IP6STAT
, 1, 0,
223 ip6_stats
, ip6_ifstats
, 0, "ip6" },
224 { -1, N_ICMP6STAT
, 1, 0,
225 icmp6_stats
, icmp6_ifstats
, 0, "icmp6" },
227 { N_TCBTABLE
, N_TCP6STAT
, 1, ip6protopr
,
228 tcp6_stats
, NULL
, tcp6_dump
, "tcp6" },
230 { N_TCBTABLE
, N_TCP6STAT
, 1, ip6protopr
,
231 tcp_stats
, NULL
, tcp6_dump
, "tcp6" },
233 { N_UDBTABLE
, N_UDP6STAT
, 1, ip6protopr
,
234 udp6_stats
, NULL
, 0, "udp6" },
236 { -1, N_IPSEC6STAT
, 1, 0,
237 fast_ipsec_stats
, NULL
, 0, "ipsec6" },
239 { -1, N_PIM6STAT
, 1, 0,
240 pim6_stats
, NULL
, 0, "pim6" },
241 { -1, N_RIP6STAT
, 1, 0,
242 rip6_stats
, NULL
, 0, "rip6" },
248 struct protox arpprotox
[] = {
249 { -1, N_ARPSTAT
, 1, 0,
250 arp_stats
, NULL
, 0, "arp" },
256 struct protox pfkeyprotox
[] = {
257 { -1, N_PFKEYSTAT
, 1, 0,
258 pfkey_stats
, NULL
, 0, "pfkey" },
265 struct protox atalkprotox
[] = {
266 { N_DDPCB
, N_DDPSTAT
, 1, atalkprotopr
,
267 ddp_stats
, NULL
, 0, "ddp" },
273 struct protox
*protoprotox
[] = { protox
,
286 const struct softintrq
{
287 const char *siq_name
;
290 { "arpintrq", N_ARPINTRQ
},
291 { "ipintrq", N_IPINTRQ
},
292 { "ip6intrq", N_IP6INTRQ
},
293 { "atintrq1", N_ATINTRQ1
},
294 { "atintrq2", N_ATINTRQ2
},
295 { "llcintrq", N_LLCINTRQ
},
296 { "hdintrq", N_HDINTRQ
},
297 { "natmintrq", N_NATMINTRQ
},
298 { "ppoediscinq", N_PPPOEDISCINQ
},
299 { "ppoeinq", N_PPPOEINQ
},
300 { "pkintrq", N_PKINTRQ
},
304 int main
__P((int, char *[]));
305 static void printproto
__P((struct protox
*, const char *));
306 static void print_softintrq
__P((void));
307 __dead
static void usage(void);
308 static struct protox
*name2protox
__P((const char *));
309 static struct protox
*knownname
__P((const char *));
310 static void prepare(const char *, const char *, struct protox
*tp
);
311 static kvm_t
*prepare_kvmd(const char *, const char *, char *);
313 static kvm_t
*kvmd
= NULL
;
315 int interval
; /* repeat interval for i/f stats */
316 static const char *nlistf
= NULL
, *memf
= NULL
;
321 char buf
[_POSIX2_LINE_MAX
];
325 if ((kvmd
= prepare_kvmd(nlistf
, memf
, buf
)) == NULL
)
326 errx(1, "kvm error: %s", buf
);
331 prepare_kvmd(const char *nf
, const char *mf
, char *errbuf
)
336 k
= kvm_openfiles(nf
, mf
, NULL
, O_RDONLY
, errbuf
);
337 (void)setgid(getgid());
342 prepare(const char *nf
, const char *mf
, struct protox
*tp
)
344 char buf
[_POSIX2_LINE_MAX
];
346 * Try to figure out if we can use sysctl or not.
348 if (nf
!= NULL
|| mf
!= NULL
) {
349 /* Of course, we can't use sysctl with dumps. */
351 errx(EXIT_FAILURE
, "can't use sysctl with dumps");
354 * If we have -M or -N, we're not dealing with live memory
355 * or want to use kvm interface explicitly. It is sometimes
356 * useful to dig inside of kernel without extending
357 * sysctl interface (i.e., without rebuilding kernel).
365 (pflag
&& tp
->pr_sindex
== N_PIMSTAT
) ||
367 /* These flags are not yet supported via sysctl(3). */
370 /* We can use sysctl(3). */
374 if (force_sysctl
&& !use_sysctl
) {
375 /* Let the user know what's about to happen. */
376 warnx("forcing sysctl usage even though it might not be "\
385 kvmd
= prepare_kvmd(nf
, mf
, buf
);
390 errx(1, "kvm error: %s", buf
);
391 if (kvm_nlist(kvmd
, nl
) < 0 || nl
[0].n_type
== 0) {
393 errx(1, "%s: no namelist", nf
);
395 errx(1, "no namelist");
398 (void)setgid(getgid());
402 main(int argc
, char *argv
[])
405 struct protox
*tp
; /* for printing cblocks & stats */
408 char *afname
, *afnames
;
412 if (prog_init() == -1)
413 err(1, "init failed");
414 force_sysctl
= 1; /* cheap trick */
418 (void)setegid(getgid());
424 while ((ch
= getopt(argc
, argv
,
425 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1)
476 numeric_addr
= numeric_port
= nflag
= RT_NFLAG
;
480 pcbaddr
= strtoul(optarg
, &cp
, 16);
481 if (*cp
!= '\0' || errno
== ERANGE
)
482 errx(1, "invalid PCB address %s",
487 if ((tp
= name2protox(optarg
)) == NULL
)
488 errx(1, "%s: unknown or uninstrumented protocol",
520 interval
= atoi(optarg
);
533 #define BACKWARD_COMPATIBILITY
534 #ifdef BACKWARD_COMPATIBILITY
536 if (isdigit((unsigned char)**argv
)) {
537 interval
= atoi(*argv
);
551 prepare(nlistf
, memf
, tp
);
564 mbpr(nl
[N_MBSTAT
].n_value
, nl
[N_MSIZE
].n_value
,
565 nl
[N_MCLBYTES
].n_value
, nl
[N_MBPOOL
].n_value
,
566 nl
[N_MCLPOOL
].n_value
);
571 /* Default to TCP. */
572 tp
= name2protox("tcp");
575 (*tp
->pr_dump
)(nl
[tp
->pr_index
].n_value
, tp
->pr_name
,
578 printf("%s: no PCB dump routine\n", tp
->pr_name
);
582 if (iflag
&& tp
->pr_istats
)
583 intpr(interval
, nl
[N_IFNET_LIST
].n_value
, tp
->pr_istats
);
584 else if (tp
->pr_stats
)
585 (*tp
->pr_stats
)(nl
[tp
->pr_sindex
].n_value
,
588 printf("%s: no stats routine\n", tp
->pr_name
);
596 * Keep file descriptors open to avoid overhead
597 * of open/close on each call to get* routines.
602 * If -f was used afnames != NULL, loop over the address families.
603 * Otherwise do this at least once (with af == AF_UNSPEC).
607 if (afnames
!= NULL
) {
608 afname
= strsep(&afnames
, ",");
610 break; /* Exit early */
611 if (strcmp(afname
, "inet") == 0)
613 else if (strcmp(afname
, "inet6") == 0)
615 else if (strcmp(afname
, "arp") == 0)
617 else if (strcmp(afname
, "pfkey") == 0)
619 else if (strcmp(afname
, "unix") == 0
620 || strcmp(afname
, "local") == 0)
622 else if (strcmp(afname
, "atalk") == 0)
624 else if (strcmp(afname
, "mpls") == 0)
627 warnx("%s: unknown address family",
637 intpr(interval
, nl
[N_IFNET_LIST
].n_value
, NULL
);
642 rt_stats(use_sysctl
? 0 : nl
[N_RTSTAT
].n_value
);
646 nflag
|tagflag
|vflag
|Lflag
, 0, ~0);
648 routepr(nl
[N_RTREE
].n_value
);
655 if (af
== AF_INET
|| af
== AF_UNSPEC
)
656 mrt_stats(nl
[N_MRTPROTO
].n_value
,
657 nl
[N_MRTSTAT
].n_value
);
659 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
660 mrt6_stats(nl
[N_MRT6PROTO
].n_value
,
661 nl
[N_MRT6STAT
].n_value
);
665 if (af
== AF_INET
|| af
== AF_UNSPEC
)
666 mroutepr(nl
[N_MRTPROTO
].n_value
,
667 nl
[N_MFCHASHTBL
].n_value
,
668 nl
[N_MFCHASH
].n_value
,
669 nl
[N_VIFTABLE
].n_value
);
671 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
672 mroute6pr(nl
[N_MRT6PROTO
].n_value
,
673 nl
[N_MF6CTABLE
].n_value
,
674 nl
[N_MIF6TABLE
].n_value
);
681 if (af
== AF_INET
|| af
== AF_UNSPEC
) {
684 /* ugh, this is O(MN) ... why do we do this? */
685 while ((p
= getprotoent()) != NULL
) {
686 for (tp
= protox
; tp
->pr_name
; tp
++)
687 if (strcmp(tp
->pr_name
, p
->p_name
) == 0)
689 if (tp
->pr_name
== 0 || tp
->pr_wanted
== 0)
691 printproto(tp
, p
->p_name
);
695 for (tp
= protox
; tp
->pr_name
; tp
++)
697 printproto(tp
, tp
->pr_name
);
700 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
701 for (tp
= ip6protox
; tp
->pr_name
; tp
++)
702 printproto(tp
, tp
->pr_name
);
704 if (af
== AF_ARP
|| af
== AF_UNSPEC
)
705 for (tp
= arpprotox
; tp
->pr_name
; tp
++)
706 printproto(tp
, tp
->pr_name
);
708 if (af
== PF_KEY
|| af
== AF_UNSPEC
)
709 for (tp
= pfkeyprotox
; tp
->pr_name
; tp
++)
710 printproto(tp
, tp
->pr_name
);
713 if (af
== AF_APPLETALK
|| af
== AF_UNSPEC
)
714 for (tp
= atalkprotox
; tp
->pr_name
; tp
++)
715 printproto(tp
, tp
->pr_name
);
716 if ((af
== AF_LOCAL
|| af
== AF_UNSPEC
) && !sflag
)
717 unixpr(nl
[N_UNIXSW
].n_value
);
719 } while (afnames
!= NULL
&& afname
!= NULL
);
724 * Print out protocol statistics or control blocks (per sflag).
725 * If the interface was not specifically requested, and the symbol
726 * is not in the namelist, ignore this one.
729 printproto(struct protox
*tp
, const char *name
)
731 void (*pr
) __P((u_long
, const char *));
737 intpr(interval
, nl
[N_IFNET_LIST
].n_value
,
743 off
= nl
[tp
->pr_sindex
].n_value
;
747 off
= nl
[tp
->pr_index
].n_value
;
749 if (pr
!= NULL
&& ((off
|| af
!= AF_UNSPEC
) || use_sysctl
)) {
755 * Print softintrq status.
758 print_softintrq(void)
760 struct ifqueue intrq
, *ifq
= &intrq
;
761 const struct softintrq
*siq
;
764 for (siq
= softintrq
; siq
->siq_name
!= NULL
; siq
++) {
765 off
= nl
[siq
->siq_index
].n_value
;
769 kread(off
, (char *)ifq
, sizeof(*ifq
));
770 printf("%s:\n", siq
->siq_name
);
771 printf("\tqueue length: %d\n", ifq
->ifq_len
);
772 printf("\tmaximum queue length: %d\n", ifq
->ifq_maxlen
);
773 printf("\tpackets dropped: %d\n", ifq
->ifq_drops
);
778 * Read kernel memory, return 0 on success.
781 kread(u_long addr
, char *buf
, int size
)
784 if (kvm_read(kvmd
, addr
, buf
, size
) != size
) {
785 warnx("%s", kvm_geterr(kvmd
));
795 return (n
!= 1 ? "s" : "");
802 return (n
!= 1 ? "es" : "");
810 kread(nl
[N_HARDCLOCK_TICKS
].n_value
, (char *)&hardticks
,
816 * Find the protox for the given "well-known" name.
818 static struct protox
*
819 knownname(const char *name
)
821 struct protox
**tpp
, *tp
;
823 for (tpp
= protoprotox
; *tpp
; tpp
++)
824 for (tp
= *tpp
; tp
->pr_name
; tp
++)
825 if (strcmp(tp
->pr_name
, name
) == 0)
831 * Find the protox corresponding to name.
833 static struct protox
*
834 name2protox(const char *name
)
837 char **alias
; /* alias from p->aliases */
841 * Try to find the name in the list of "well-known" names. If that
842 * fails, check if name is an alias for an Internet protocol.
844 if ((tp
= knownname(name
)) != NULL
)
847 setprotoent(1); /* make protocol lookup cheaper */
848 while ((p
= getprotoent()) != NULL
) {
849 /* assert: name not same as p->name */
850 for (alias
= p
->p_aliases
; *alias
; alias
++)
851 if (strcmp(name
, *alias
) == 0) {
853 return (knownname(p
->p_name
));
863 const char *progname
= getprogname();
865 (void)fprintf(stderr
,
866 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname
);
867 (void)fprintf(stderr
,
868 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n",
870 (void)fprintf(stderr
,
871 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname
);
872 (void)fprintf(stderr
,
873 " %s [-p protocol] [-M core] [-N system]\n", progname
);
874 (void)fprintf(stderr
,
875 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname
);
876 (void)fprintf(stderr
,
877 " %s [-p protocol] [-i] [-I Interface] \n", progname
);
878 (void)fprintf(stderr
,
879 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname
);
880 (void)fprintf(stderr
,
881 " %s [-s] [-B] [-I interface]\n", progname
);