Index: head/usr.bin/netstat/Makefile =================================================================== --- head/usr.bin/netstat/Makefile (revision 287406) +++ head/usr.bin/netstat/Makefile (revision 287407) @@ -1,44 +1,67 @@ # @(#)Makefile 8.1 (Berkeley) 6/12/93 # $FreeBSD$ .include PROG= netstat -SRCS= if.c inet.c main.c mbuf.c mroute.c netisr.c route.c \ +SRCS= if.c inet.c main.c mbuf.c mroute.c netisr.c nl_symbols.c route.c \ unix.c mroute6.c ipsec.c bpf.c pfkey.c sctp.c \ flowtable.c +DPSRCS= nl_defs.h + +nl_symbols.c: nlist_symbols + awk '\ + BEGIN { \ + print "#include "; \ + print "#include "; \ + print "struct nlist nl[] = {"; \ + } \ + !/^\#/ { printf("\t{ .n_name = \"%s\" },\n", $$2); } \ + END { print "\t{ .n_name = NULL },\n};" } \ + ' < ${.ALLSRC} > ${.TARGET} || rm -f ${.TARGET} +nl_defs.h: nlist_symbols + awk '\ + BEGIN { \ + print "#include "; \ + print "extern struct nlist nl[];"; \ + i = 0; \ + } \ + !/^\#/ { printf("\#define\tN%s\t%s\n", toupper($$2), i++); }' \ + < ${.ALLSRC} > ${.TARGET} || rm -f ${.TARGET} +CLEANFILES+= nl_symbols.c nl_defs.h +CFLAGS+= -I${.OBJDIR} WARNS?= 3 CFLAGS+=-fno-strict-aliasing CFLAGS+=-DIPSEC CFLAGS+=-DSCTP .if ${MK_INET_SUPPORT} != "no" CFLAGS+=-DINET .endif .if ${MK_INET6_SUPPORT} != "no" SRCS+= inet6.c CFLAGS+=-DINET6 .endif .if ${MK_OFED} != "no" CFLAGS+=-DSDP .endif .if ${MK_PF} != "no" CFLAGS+=-DPF .endif BINGRP= kmem BINMODE=2555 LIBADD= kvm memstat xo util .if ${MK_NETGRAPH_SUPPORT} != "no" SRCS+= netgraph.c LIBADD+= netgraph CFLAGS+=-DNETGRAPH .endif .include Index: head/usr.bin/netstat/main.c =================================================================== --- head/usr.bin/netstat/main.c (revision 287406) +++ head/usr.bin/netstat/main.c (revision 287407) @@ -1,898 +1,831 @@ /*- * Copyright (c) 1983, 1988, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -char const copyright[] = +static char const copyright[] = "@(#) Copyright (c) 1983, 1988, 1993\n\ Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #ifdef NETGRAPH #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" +#include "nl_defs.h" #include -static struct nlist nl[] = { -#define N_RTSTAT 0 - { .n_name = "_rtstat" }, -#define N_RTREE 1 - { .n_name = "_rt_tables"}, -#define N_MRTSTAT 2 - { .n_name = "_mrtstat" }, -#define N_MFCHASHTBL 3 - { .n_name = "_mfchashtbl" }, -#define N_VIFTABLE 4 - { .n_name = "_viftable" }, -#define N_NGSOCKS 5 - { .n_name = "_ngsocklist"}, -#define N_IP6STAT 6 - { .n_name = "_ip6stat" }, -#define N_ICMP6STAT 7 - { .n_name = "_icmp6stat" }, -#define N_IPSECSTAT 8 - { .n_name = "_ipsec4stat" }, -#define N_IPSEC6STAT 9 - { .n_name = "_ipsec6stat" }, -#define N_PIM6STAT 10 - { .n_name = "_pim6stat" }, -#define N_MRT6STAT 11 - { .n_name = "_mrt6stat" }, -#define N_MF6CTABLE 12 - { .n_name = "_mf6ctable" }, -#define N_MIF6TABLE 13 - { .n_name = "_mif6table" }, -#define N_PFKEYSTAT 14 - { .n_name = "_pfkeystat" }, -#define N_RTTRASH 15 - { .n_name = "_rttrash" }, -#define N_CARPSTAT 16 - { .n_name = "_carpstats" }, -#define N_PFSYNCSTAT 17 - { .n_name = "_pfsyncstats" }, -#define N_AHSTAT 18 - { .n_name = "_ahstat" }, -#define N_ESPSTAT 19 - { .n_name = "_espstat" }, -#define N_IPCOMPSTAT 20 - { .n_name = "_ipcompstat" }, -#define N_TCPSTAT 21 - { .n_name = "_tcpstat" }, -#define N_UDPSTAT 22 - { .n_name = "_udpstat" }, -#define N_IPSTAT 23 - { .n_name = "_ipstat" }, -#define N_ICMPSTAT 24 - { .n_name = "_icmpstat" }, -#define N_IGMPSTAT 25 - { .n_name = "_igmpstat" }, -#define N_PIMSTAT 26 - { .n_name = "_pimstat" }, -#define N_TCBINFO 27 - { .n_name = "_tcbinfo" }, -#define N_UDBINFO 28 - { .n_name = "_udbinfo" }, -#define N_DIVCBINFO 29 - { .n_name = "_divcbinfo" }, -#define N_RIPCBINFO 30 - { .n_name = "_ripcbinfo" }, -#define N_UNP_COUNT 31 - { .n_name = "_unp_count" }, -#define N_UNP_GENCNT 32 - { .n_name = "_unp_gencnt" }, -#define N_UNP_DHEAD 33 - { .n_name = "_unp_dhead" }, -#define N_UNP_SHEAD 34 - { .n_name = "_unp_shead" }, -#define N_RIP6STAT 36 - { .n_name = "_rip6stat" }, -#define N_SCTPSTAT 36 - { .n_name = "_sctpstat" }, -#define N_MFCTABLESIZE 37 - { .n_name = "_mfctablesize" }, -#define N_ARPSTAT 38 - { .n_name = "_arpstat" }, -#define N_UNP_SPHEAD 39 - { .n_name = "unp_sphead" }, -#define N_SFSTAT 40 - { .n_name = "_sfstat"}, - { .n_name = NULL }, -}; - -struct protox { +static struct protox { int pr_index; /* index into nlist of cb head */ int pr_sindex; /* index into nlist of stat block */ u_char pr_wanted; /* 1 if wanted, 0 otherwise */ void (*pr_cblocks)(u_long, const char *, int, int); /* control blocks printing routine */ void (*pr_stats)(u_long, const char *, int, int); /* statistics printing routine */ void (*pr_istats)(char *); /* per/if statistics printing routine */ const char *pr_name; /* well-known name */ int pr_usesysctl; /* non-zero if we use sysctl, not kvm */ int pr_protocol; } protox[] = { { N_TCBINFO, N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, { N_UDBINFO, N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", 1, IPPROTO_UDP }, #ifdef SCTP { -1, N_SCTPSTAT, 1, sctp_protopr, sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, #endif #ifdef SDP { -1, -1, 1, protopr, NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif { N_DIVCBINFO, -1, 1, protopr, NULL, NULL, "divert", 1, IPPROTO_DIVERT }, { N_RIPCBINFO, N_IPSTAT, 1, protopr, ip_stats, NULL, "ip", 1, IPPROTO_RAW }, { N_RIPCBINFO, N_ICMPSTAT, 1, protopr, icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP }, { N_RIPCBINFO, N_IGMPSTAT, 1, protopr, igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, #ifdef IPSEC - { -1, N_IPSECSTAT, 1, NULL, /* keep as compat */ + { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */ ipsec_stats, NULL, "ipsec", 0, 0}, { -1, N_AHSTAT, 1, NULL, ah_stats, NULL, "ah", 0, 0}, { -1, N_ESPSTAT, 1, NULL, esp_stats, NULL, "esp", 0, 0}, { -1, N_IPCOMPSTAT, 1, NULL, ipcomp_stats, NULL, "ipcomp", 0, 0}, #endif { N_RIPCBINFO, N_PIMSTAT, 1, protopr, pim_stats, NULL, "pim", 1, IPPROTO_PIM }, - { -1, N_CARPSTAT, 1, NULL, + { -1, N_CARPSTATS, 1, NULL, carp_stats, NULL, "carp", 1, 0 }, #ifdef PF - { -1, N_PFSYNCSTAT, 1, NULL, + { -1, N_PFSYNCSTATS, 1, NULL, pfsync_stats, NULL, "pfsync", 1, 0 }, #endif { -1, N_ARPSTAT, 1, NULL, arp_stats, NULL, "arp", 1, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #ifdef INET6 -struct protox ip6protox[] = { +static struct protox ip6protox[] = { { N_TCBINFO, N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, { N_UDBINFO, N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", 1, IPPROTO_UDP }, { N_RIPCBINFO, N_IP6STAT, 1, protopr, ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, { N_RIPCBINFO, N_ICMP6STAT, 1, protopr, icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, #ifdef SDP { -1, -1, 1, protopr, NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, ipsec_stats, NULL, "ipsec6", 0, 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, pim6_stats, NULL, "pim6", 1, 0 }, #endif { -1, N_RIP6STAT, 1, NULL, rip6_stats, NULL, "rip6", 1, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif /*INET6*/ #ifdef IPSEC -struct protox pfkeyprotox[] = { +static struct protox pfkeyprotox[] = { { -1, N_PFKEYSTAT, 1, NULL, pfkey_stats, NULL, "pfkey", 0, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif #ifdef NETGRAPH -struct protox netgraphprotox[] = { - { N_NGSOCKS, -1, 1, netgraphprotopr, +static struct protox netgraphprotox[] = { + { N_NGSOCKLIST, -1, 1, netgraphprotopr, NULL, NULL, "ctrl", 0, 0 }, - { N_NGSOCKS, -1, 1, netgraphprotopr, + { N_NGSOCKLIST, -1, 1, netgraphprotopr, NULL, NULL, "data", 0, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif -struct protox *protoprotox[] = { +static struct protox *protoprotox[] = { protox, #ifdef INET6 ip6protox, #endif #ifdef IPSEC pfkeyprotox, #endif NULL }; static void printproto(struct protox *, const char *, bool *); static void usage(void); static struct protox *name2protox(const char *); static struct protox *knownname(const char *); +static int kresolve_list(struct nlist *_nl); + static kvm_t *kvmd; static char *nlistf = NULL, *memf = NULL; int Aflag; /* show addresses of protocol control block */ int aflag; /* show all sockets (including servers) */ -int Bflag; /* show information about bpf consumers */ +static int Bflag; /* show information about bpf consumers */ int bflag; /* show i/f total bytes in/out */ int dflag; /* show i/f dropped packets */ int gflag; /* show group (multicast) routing or stats */ int hflag; /* show counters in human readable format */ int iflag; /* show interfaces */ int Lflag; /* show size of listen queues */ int mflag; /* show memory stats */ int noutputs = 0; /* how much outputs before we exit */ int numeric_addr; /* show addresses numerically */ int numeric_port; /* show ports numerically */ static int pflag; /* show given protocol */ -int Qflag; /* show netisr information */ +static int Qflag; /* show netisr information */ int rflag; /* show routing tables (or routing stats) */ int Rflag; /* show flow / RSS statistics */ int sflag; /* show protocol statistics */ int Wflag; /* wide display */ int Tflag; /* TCP Information */ int xflag; /* extra information, includes all socket buffer info */ int zflag; /* zero stats */ int interval; /* repeat interval for i/f stats */ char *interface; /* desired i/f for stats, or NULL for all i/fs */ int unit; /* unit number for above */ -int af; /* address family */ +static int af; /* address family */ int live; /* true if we are examining a live system */ int main(int argc, char *argv[]) { struct protox *tp = NULL; /* for printing cblocks & stats */ int ch; int fib = -1; char *endptr; bool first = true; af = AF_UNSPEC; argc = xo_parse_args(argc, argv); while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlM:mN:np:Qq:RrSTsuWw:xz")) != -1) switch(ch) { case '4': #ifdef INET af = AF_INET; #else errx(1, "IPv4 support is not compiled in"); #endif break; case '6': #ifdef INET6 af = AF_INET6; #else errx(1, "IPv6 support is not compiled in"); #endif break; case 'A': Aflag = 1; break; case 'a': aflag = 1; break; case 'B': Bflag = 1; break; case 'b': bflag = 1; break; case 'd': dflag = 1; break; case 'F': fib = strtol(optarg, &endptr, 0); if (*endptr != '\0' || (fib == 0 && (errno == EINVAL || errno == ERANGE))) xo_errx(1, "%s: invalid fib", optarg); break; case 'f': if (strcmp(optarg, "inet") == 0) af = AF_INET; #ifdef INET6 else if (strcmp(optarg, "inet6") == 0) af = AF_INET6; #endif #ifdef IPSEC else if (strcmp(optarg, "pfkey") == 0) af = PF_KEY; #endif else if (strcmp(optarg, "unix") == 0 || strcmp(optarg, "local") == 0) af = AF_UNIX; #ifdef NETGRAPH else if (strcmp(optarg, "ng") == 0 || strcmp(optarg, "netgraph") == 0) af = AF_NETGRAPH; #endif else if (strcmp(optarg, "link") == 0) af = AF_LINK; else { xo_errx(1, "%s: unknown address family", optarg); } break; case 'g': gflag = 1; break; case 'h': hflag = 1; break; case 'I': { char *cp; iflag = 1; for (cp = interface = optarg; isalpha(*cp); cp++) continue; unit = atoi(cp); break; } case 'i': iflag = 1; break; case 'L': Lflag = 1; break; case 'M': memf = optarg; break; case 'm': mflag = 1; break; case 'N': nlistf = optarg; break; case 'n': numeric_addr = numeric_port = 1; break; case 'p': if ((tp = name2protox(optarg)) == NULL) { xo_errx(1, "%s: unknown or uninstrumented " "protocol", optarg); } pflag = 1; break; case 'Q': Qflag = 1; break; case 'q': noutputs = atoi(optarg); if (noutputs != 0) noutputs++; break; case 'r': rflag = 1; break; case 'R': Rflag = 1; break; case 's': ++sflag; break; case 'S': numeric_addr = 1; break; case 'u': af = AF_UNIX; break; case 'W': case 'l': Wflag = 1; break; case 'w': interval = atoi(optarg); iflag = 1; break; case 'T': Tflag = 1; break; case 'x': xflag = 1; break; case 'z': zflag = 1; break; case '?': default: usage(); } argv += optind; argc -= optind; #define BACKWARD_COMPATIBILITY #ifdef BACKWARD_COMPATIBILITY if (*argv) { if (isdigit(**argv)) { interval = atoi(*argv); if (interval <= 0) usage(); ++argv; iflag = 1; } if (*argv) { nlistf = *argv; if (*++argv) memf = *argv; } } #endif /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ live = (nlistf == NULL && memf == NULL); if (!live) { if (setgid(getgid()) != 0) xo_err(-1, "setgid"); } if (xflag && Tflag) xo_errx(1, "-x and -T are incompatible, pick one."); if (Bflag) { if (!live) usage(); bpf_stats(interface); xo_finish(); exit(0); } if (mflag) { if (!live) { if (kread(0, NULL, 0) == 0) mbpr(kvmd, nl[N_SFSTAT].n_value); } else mbpr(NULL, 0); xo_finish(); exit(0); } if (Qflag) { if (!live) { if (kread(0, NULL, 0) == 0) - netisr_stats(kvmd); + netisr_stats(); } else - netisr_stats(NULL); + netisr_stats(); xo_finish(); exit(0); } #if 0 /* * Keep file descriptors open to avoid overhead * of open/close on each call to get* routines. */ sethostent(1); setnetent(1); #else /* * This does not make sense any more with DNS being default over * the files. Doing a setXXXXent(1) causes a tcp connection to be * used for the queries, which is slower. */ #endif if (iflag && !sflag) { xo_open_container("statistics"); intpr(NULL, af); xo_close_container("statistics"); xo_finish(); exit(0); } if (rflag) { xo_open_container("statistics"); if (sflag) { rt_stats(); flowtable_stats(); } else routepr(fib, af); xo_close_container("statistics"); xo_finish(); exit(0); } if (gflag) { xo_open_container("statistics"); if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mrt6_stats(); #endif } else { if (af == AF_INET || af == AF_UNSPEC) mroutepr(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mroute6pr(); #endif } xo_close_container("statistics"); xo_finish(); exit(0); } /* Load all necessary kvm symbols */ kresolve_list(nl); if (tp) { xo_open_container("statistics"); printproto(tp, tp->pr_name, &first); if (!first) xo_close_list("socket"); xo_close_container("statistics"); xo_finish(); exit(0); } xo_open_container("statistics"); if (af == AF_INET || af == AF_UNSPEC) for (tp = protox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) for (tp = ip6protox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /*INET6*/ #ifdef IPSEC if (af == PF_KEY || af == AF_UNSPEC) for (tp = pfkeyprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /*IPSEC*/ #ifdef NETGRAPH if (af == AF_NETGRAPH || af == AF_UNSPEC) for (tp = netgraphprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /* NETGRAPH */ if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value, nl[N_UNP_SPHEAD].n_value, &first); if (!first) xo_close_list("socket"); xo_close_container("statistics"); xo_finish(); exit(0); } /* * Print out protocol statistics or control blocks (per sflag). * If the interface was not specifically requested, and the symbol * is not in the namelist, ignore this one. */ static void printproto(struct protox *tp, const char *name, bool *first) { void (*pr)(u_long, const char *, int, int); u_long off; bool doingdblocks = false; if (sflag) { if (iflag) { if (tp->pr_istats) intpr(tp->pr_istats, af); else if (pflag) xo_message("%s: no per-interface stats routine", tp->pr_name); return; } else { pr = tp->pr_stats; if (!pr) { if (pflag) xo_message("%s: no stats routine", tp->pr_name); return; } if (tp->pr_usesysctl && live) off = 0; else if (tp->pr_sindex < 0) { if (pflag) xo_message("%s: stats routine doesn't " "work on cores", tp->pr_name); return; } else off = nl[tp->pr_sindex].n_value; } } else { doingdblocks = true; pr = tp->pr_cblocks; if (!pr) { if (pflag) xo_message("%s: no PCB routine", tp->pr_name); return; } if (tp->pr_usesysctl && live) off = 0; else if (tp->pr_index < 0) { if (pflag) xo_message("%s: PCB routine doesn't work on " "cores", tp->pr_name); return; } else off = nl[tp->pr_index].n_value; } if (pr != NULL && (off || (live && tp->pr_usesysctl) || af != AF_UNSPEC)) { if (doingdblocks && *first) { xo_open_list("socket"); *first = false; } (*pr)(off, name, af, tp->pr_protocol); } } static int kvmd_init(void) { char errbuf[_POSIX2_LINE_MAX]; if (kvmd != NULL) return (0); kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); if (setgid(getgid()) != 0) xo_err(-1, "setgid"); if (kvmd == NULL) { xo_warnx("kvm not available: %s", errbuf); return (-1); } return (0); } /* * Resolve symbol list, return 0 on success. */ -int +static int kresolve_list(struct nlist *_nl) { if ((kvmd == NULL) && (kvmd_init() != 0)) return (-1); if (_nl[0].n_type != 0) return (0); if (kvm_nlist(kvmd, _nl) < 0) { if (nlistf) xo_errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); else xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); } return (0); +} + +/* + * Wrapper of kvm_dpcpu_setcpu(). + */ +void +kset_dpcpu(u_int cpuid) +{ + + if ((kvmd == NULL) && (kvmd_init() != 0)) + xo_errx(-1, "%s: kvm is not available", __func__); + + if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0) + xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__, + cpuid, kvm_geterr(kvmd)); + return; } /* * Read kernel memory, return 0 on success. */ int kread(u_long addr, void *buf, size_t size) { if (kvmd_init() < 0) return (-1); if (!buf) return (0); if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { xo_warnx("%s", kvm_geterr(kvmd)); return (-1); } return (0); } /* * Read single counter(9). */ uint64_t kread_counter(u_long addr) { if (kvmd_init() < 0) return (-1); return (kvm_counter_u64_fetch(kvmd, addr)); } /* * Read an array of N counters in kernel memory into array of N uint64_t's. */ int kread_counters(u_long addr, void *buf, size_t size) { uint64_t *c; u_long *counters; size_t i, n; if (kvmd_init() < 0) return (-1); if (size % sizeof(uint64_t) != 0) { xo_warnx("kread_counters: invalid counter set size"); return (-1); } n = size / sizeof(uint64_t); if ((counters = malloc(n * sizeof(u_long))) == NULL) xo_err(-1, "malloc"); if (kread(addr, counters, n * sizeof(u_long)) < 0) { free(counters); return (-1); } c = buf; for (i = 0; i < n; i++) c[i] = kvm_counter_u64_fetch(kvmd, counters[i]); free(counters); return (0); } const char * plural(uintmax_t n) { return (n != 1 ? "s" : ""); } const char * plurales(uintmax_t n) { return (n != 1 ? "es" : ""); } const char * pluralies(uintmax_t n) { return (n != 1 ? "ies" : "y"); } /* * Find the protox for the given "well-known" name. */ static struct protox * knownname(const char *name) { struct protox **tpp, *tp; for (tpp = protoprotox; *tpp; tpp++) for (tp = *tpp; tp->pr_name; tp++) if (strcmp(tp->pr_name, name) == 0) return (tp); return (NULL); } /* * Find the protox corresponding to name. */ static struct protox * name2protox(const char *name) { struct protox *tp; char **alias; /* alias from p->aliases */ struct protoent *p; /* * Try to find the name in the list of "well-known" names. If that * fails, check if name is an alias for an Internet protocol. */ if ((tp = knownname(name)) != NULL) return (tp); setprotoent(1); /* make protocol lookup cheaper */ while ((p = getprotoent()) != NULL) { /* assert: name not same as p->name */ for (alias = p->p_aliases; *alias; alias++) if (strcmp(name, *alias) == 0) { endprotoent(); return (knownname(p->p_name)); } } endprotoent(); return (NULL); } static void usage(void) { (void)xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: netstat [-46AaLnRSTWx] [-f protocol_family | -p protocol]\n" " [-M core] [-N system]", " netstat -i | -I interface [-46abdhnW] [-f address_family]\n" " [-M core] [-N system]", " netstat -w wait [-I interface] [-46d] [-M core] [-N system]\n" " [-q howmany]", " netstat -s [-46sz] [-f protocol_family | -p protocol]\n" " [-M core] [-N system]", " netstat -i | -I interface -s [-46s]\n" " [-f protocol_family | -p protocol] [-M core] [-N system]", " netstat -m [-M core] [-N system]", " netstat -B [-z] [-I interface]", " netstat -r [-46AnW] [-F fibnum] [-f address_family]\n" " [-M core] [-N system]", " netstat -rs [-s] [-M core] [-N system]", " netstat -g [-46W] [-f address_family] [-M core] [-N system]", " netstat -gs [-46s] [-f address_family] [-M core] [-N system]", " netstat -Q"); xo_finish(); exit(1); } Index: head/usr.bin/netstat/mroute.c =================================================================== --- head/usr.bin/netstat/mroute.c (revision 287406) +++ head/usr.bin/netstat/mroute.c (revision 287407) @@ -1,477 +1,460 @@ /*- * Copyright (c) 1989 Stephen Deering * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Stephen Deering of Stanford University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)mroute.c 8.2 (Berkeley) 4/28/95 */ #include __FBSDID("$FreeBSD$"); /* * Print multicast routing structures and statistics. * * MROUTING 1.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #define _KERNEL 1 #include #undef _KERNEL #include -#include #include #include #include #include #include #include #include "netstat.h" +#include "nl_defs.h" -/* - * kvm(3) bindings for every needed symbol - */ -static struct nlist mrl[] = { -#define N_MRTSTAT 0 - { .n_name = "_mrtstat" }, -#define N_MFCHASHTBL 1 - { .n_name = "_mfchashtbl" }, -#define N_VIFTABLE 2 - { .n_name = "_viftable" }, -#define N_MFCTABLESIZE 3 - { .n_name = "_mfctablesize" }, - { .n_name = NULL }, -}; - static void print_bw_meter(struct bw_meter *, int *); static void print_mfc(struct mfc *, int, int *); static void print_bw_meter(struct bw_meter *bw_meter, int *banner_printed) { char s1[256], s2[256], s3[256]; struct timeval now, end, delta; gettimeofday(&now, NULL); if (! *banner_printed) { xo_open_list("bandwidth-meter"); xo_emit(" {T:Bandwidth Meters}\n"); xo_emit(" {T:/%-30s}", "Measured(Start|Packets|Bytes)"); xo_emit(" {T:/%s}", "Type"); xo_emit(" {T:/%-30s}", "Thresh(Interval|Packets|Bytes)"); xo_emit(" {T:Remain}"); xo_emit("\n"); *banner_printed = 1; } xo_open_instance("bandwidth-meter"); /* The measured values */ if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) { sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_measured.b_packets); xo_emit("{e:measured-packets/%ju}", (uintmax_t)bw_meter->bm_measured.b_packets); } else sprintf(s1, "?"); if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) { sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_measured.b_bytes); xo_emit("{e:measured-bytes/%ju}", (uintmax_t)bw_meter->bm_measured.b_bytes); } else sprintf(s2, "?"); xo_emit(" {[:-30}{:start-time/%lu.%06lu}|{q:measured-packets/%s}" "|{q:measured-bytes%s}{]:}", (u_long)bw_meter->bm_start_time.tv_sec, (u_long)bw_meter->bm_start_time.tv_usec, s1, s2); /* The type of entry */ xo_emit(" {t:type/%-3s}", (bw_meter->bm_flags & BW_METER_GEQ) ? ">=" : (bw_meter->bm_flags & BW_METER_LEQ) ? "<=" : "?"); /* The threshold values */ if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) { sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_threshold.b_packets); xo_emit("{e:threshold-packets/%ju}", (uintmax_t)bw_meter->bm_threshold.b_packets); } else sprintf(s1, "?"); if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) { sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_threshold.b_bytes); xo_emit("{e:threshold-bytes/%ju}", (uintmax_t)bw_meter->bm_threshold.b_bytes); } else sprintf(s2, "?"); xo_emit(" {[:-30}{:threshold-time/%lu.%06lu}|{q:threshold-packets/%s}" "|{q:threshold-bytes%s}{]:}", (u_long)bw_meter->bm_threshold.b_time.tv_sec, (u_long)bw_meter->bm_threshold.b_time.tv_usec, s1, s2); /* Remaining time */ timeradd(&bw_meter->bm_start_time, &bw_meter->bm_threshold.b_time, &end); if (timercmp(&now, &end, <=)) { timersub(&end, &now, &delta); sprintf(s3, "%lu.%06lu", (u_long)delta.tv_sec, (u_long)delta.tv_usec); } else { /* Negative time */ timersub(&now, &end, &delta); sprintf(s3, "-%lu.06%lu", (u_long)delta.tv_sec, (u_long)delta.tv_usec); } xo_emit(" {:remaining-time/%s}", s3); xo_open_instance("bandwidth-meter"); xo_emit("\n"); } static void print_mfc(struct mfc *m, int maxvif, int *banner_printed) { struct sockaddr_in sin; struct sockaddr *sa = (struct sockaddr *)&sin; struct bw_meter bw_meter, *bwm; int bw_banner_printed; int error; vifi_t vifi; bw_banner_printed = 0; memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; if (! *banner_printed) { xo_open_list("multicast-forwarding-entry"); xo_emit("\n{T:IPv4 Multicast Forwarding Table}\n" " {T:Origin} {T:Group} " " {T:Packets In-Vif} {T:Out-Vifs:Ttls}\n"); *banner_printed = 1; } memcpy(&sin.sin_addr, &m->mfc_origin, sizeof(sin.sin_addr)); xo_emit(" {:origin-address/%-15.15s}", routename(sa, numeric_addr)); memcpy(&sin.sin_addr, &m->mfc_mcastgrp, sizeof(sin.sin_addr)); xo_emit(" {:group-address/%-15.15s}", routename(sa, numeric_addr)); xo_emit(" {:sent-packets/%9lu}", m->mfc_pkt_cnt); xo_emit(" {:parent/%3d} ", m->mfc_parent); xo_open_list("vif-ttl"); for (vifi = 0; vifi <= maxvif; vifi++) { if (m->mfc_ttls[vifi] > 0) { xo_open_instance("vif-ttl"); xo_emit(" {k:vif/%u}:{:ttl/%u}", vifi, m->mfc_ttls[vifi]); xo_close_instance("vif-ttl"); } } xo_close_list("vif-ttl"); xo_emit("\n"); /* * XXX We break the rules and try to use KVM to read the * bandwidth meters, they are not retrievable via sysctl yet. */ bwm = m->mfc_bw_meter; while (bwm != NULL) { error = kread((u_long)bwm, (char *)&bw_meter, sizeof(bw_meter)); if (error) break; print_bw_meter(&bw_meter, &bw_banner_printed); bwm = bw_meter.bm_mfc_next; } if (banner_printed) xo_close_list("bandwidth-meter"); } void mroutepr() { struct sockaddr_in sin; struct sockaddr *sa = (struct sockaddr *)&sin; struct vif viftable[MAXVIFS]; struct vif *v; struct mfc *m; u_long pmfchashtbl, pmfctablesize, pviftbl; int banner_printed; int saved_numeric_addr; size_t len; vifi_t vifi, maxvif; saved_numeric_addr = numeric_addr; numeric_addr = 1; memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; /* * TODO: * The VIF table will move to hanging off the struct if_info for * each IPv4 configured interface. Currently it is statically * allocated, and retrieved either using KVM or an opaque SYSCTL. * * This can't happen until the API documented in multicast(4) * is itself refactored. The historical reason why VIFs use * a separate ifindex space is entirely due to the legacy * capability of the MROUTING code to create IPIP tunnels on * the fly to support DVMRP. When gif(4) became available, this * functionality was deprecated, as PIM does not use it. */ maxvif = 0; pmfchashtbl = pmfctablesize = pviftbl = 0; len = sizeof(viftable); if (live) { if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, 0) < 0) { xo_warn("sysctl: net.inet.ip.viftable"); return; } } else { - kresolve_list(mrl); - pmfchashtbl = mrl[N_MFCHASHTBL].n_value; - pmfctablesize = mrl[N_MFCTABLESIZE].n_value; - pviftbl = mrl[N_VIFTABLE].n_value; + pmfchashtbl = nl[N_MFCHASHTBL].n_value; + pmfctablesize = nl[N_MFCTABLESIZE].n_value; + pviftbl = nl[N_VIFTABLE].n_value; if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) { xo_warnx("No IPv4 MROUTING kernel support."); return; } kread(pviftbl, (char *)viftable, sizeof(viftable)); } banner_printed = 0; for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { if (v->v_lcl_addr.s_addr == 0) continue; maxvif = vifi; if (!banner_printed) { xo_emit("\n{T:IPv4 Virtual Interface Table\n" " Vif Thresh Local-Address " "Remote-Address Pkts-In Pkts-Out}\n"); banner_printed = 1; xo_open_list("vif"); } xo_open_instance("vif"); memcpy(&sin.sin_addr, &v->v_lcl_addr, sizeof(sin.sin_addr)); xo_emit(" {:vif/%2u} {:threshold/%6u} {:route/%-15.15s}", /* opposite math of add_vif() */ vifi, v->v_threshold, routename(sa, numeric_addr)); memcpy(&sin.sin_addr, &v->v_rmt_addr, sizeof(sin.sin_addr)); xo_emit(" {:source/%-15.15s}", (v->v_flags & VIFF_TUNNEL) ? routename(sa, numeric_addr) : ""); xo_emit(" {:received-packets/%9lu} {:sent-packets/%9lu}\n", v->v_pkt_in, v->v_pkt_out); xo_close_instance("vif"); } if (banner_printed) xo_close_list("vif"); else xo_emit("\n{T:IPv4 Virtual Interface Table is empty}\n"); banner_printed = 0; /* * TODO: * The MFC table will move into the AF_INET radix trie in future. * In 8.x, it becomes a dynamically allocated structure referenced * by a hashed LIST, allowing more than 256 entries w/o kernel tuning. * * If retrieved via opaque SYSCTL, the kernel will coalesce it into * a static table for us. * If retrieved via KVM, the hash list pointers must be followed. */ if (live) { struct mfc *mfctable; len = 0; if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL, 0) < 0) { xo_warn("sysctl: net.inet.ip.mfctable"); return; } mfctable = malloc(len); if (mfctable == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return; } if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, 0) < 0) { free(mfctable); xo_warn("sysctl: net.inet.ip.mfctable"); return; } m = mfctable; while (len >= sizeof(*m)) { print_mfc(m++, maxvif, &banner_printed); len -= sizeof(*m); } if (banner_printed) xo_close_list("multicast-forwarding-entry"); if (len != 0) xo_warnx("print_mfc: %lu trailing bytes", (u_long)len); free(mfctable); } else { LIST_HEAD(, mfc) *mfchashtbl; u_long i, mfctablesize; struct mfc mfc; int error; error = kread(pmfctablesize, (char *)&mfctablesize, sizeof(u_long)); if (error) { xo_warn("kread: mfctablesize"); return; } len = sizeof(*mfchashtbl) * mfctablesize; mfchashtbl = malloc(len); if (mfchashtbl == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return; } kread(pmfchashtbl, (char *)&mfchashtbl, len); for (i = 0; i < mfctablesize; i++) { LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) { kread((u_long)m, (char *)&mfc, sizeof(mfc)); print_mfc(m, maxvif, &banner_printed); } } if (banner_printed) xo_close_list("multicast-forwarding-entry"); free(mfchashtbl); } if (!banner_printed) xo_emit("\n{T:IPv4 Multicast Forwarding Table is empty}\n"); xo_emit("\n"); numeric_addr = saved_numeric_addr; } void mrt_stats() { struct mrtstat mrtstat; u_long mstaddr; size_t len = sizeof(mrtstat); - kresolve_list(mrl); - mstaddr = mrl[N_MRTSTAT].n_value; + mstaddr = nl[N_MRTSTAT].n_value; if (mstaddr == 0) { fprintf(stderr, "No IPv4 MROUTING kernel support.\n"); return; } if (live) { if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL, 0) < 0) { xo_warn("sysctl: net.inet.ip.mrtstat failed."); return; } } else kread_counters(mstaddr, &mrtstat, len); xo_emit("{T:IPv4 multicast forwarding}:\n"); #define p(f, m) if (mrtstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)mrtstat.f, plural(mrtstat.f)) #define p2(f, m) if (mrtstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)mrtstat.f, plurales(mrtstat.f)) xo_open_container("multicast-statistics"); p(mrts_mfc_lookups, "\t{:cache-lookups/%ju} " "{N:/multicast forwarding cache lookup%s}\n"); p2(mrts_mfc_misses, "\t{:cache-misses/%ju} " "{N:/multicast forwarding cache miss%s}\n"); p(mrts_upcalls, "\t{:upcalls-total/%ju} " "{N:/upcall%s to multicast routing daemon}\n"); p(mrts_upq_ovflw, "\t{:upcall-overflows/%ju} " "{N:/upcall queue overflow%s}\n"); p(mrts_upq_sockfull, "\t{:upcalls-dropped-full-buffer/%ju} " "{N:/upcall%s dropped due to full socket buffer}\n"); p(mrts_cache_cleanups, "\t{:cache-cleanups/%ju} " "{N:/cache cleanup%s}\n"); p(mrts_no_route, "\t{:dropped-no-origin/%ju} " "{N:/datagram%s with no route for origin}\n"); p(mrts_bad_tunnel, "\t{:dropped-bad-tunnel/%ju} " "{N:/datagram%s arrived with bad tunneling}\n"); p(mrts_cant_tunnel, "\t{:dropped-could-not-tunnel/%ju} " "{N:/datagram%s could not be tunneled}\n"); p(mrts_wrong_if, "\t{:dropped-wrong-incoming-interface/%ju} " "{N:/datagram%s arrived on wrong interface}\n"); p(mrts_drop_sel, "\t{:dropped-selectively/%ju} " "{N:/datagram%s selectively dropped}\n"); p(mrts_q_overflow, "\t{:dropped-queue-overflow/%ju} " "{N:/datagram%s dropped due to queue overflow}\n"); p(mrts_pkt2large, "\t{:dropped-too-large/%ju} " "{N:/datagram%s dropped for being too large}\n"); #undef p2 #undef p } Index: head/usr.bin/netstat/netgraph.c =================================================================== --- head/usr.bin/netstat/netgraph.c (revision 287406) +++ head/usr.bin/netstat/netgraph.c (revision 287407) @@ -1,145 +1,144 @@ /*- * Copyright (c) 1996-1999 Whistle Communications, Inc. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications; * provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include "netstat.h" static int first = 1; static int csock = -1; void netgraphprotopr(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ngpcb *this, *next; struct ngpcb ngpcb; struct socket sockb; int debug = 1; /* If symbol not found, try looking in the KLD module */ if (off == 0) { if (debug) xo_warnx("Error reading symbols from ng_socket.ko"); return; } /* Get pointer to first socket */ kread(off, (char *)&this, sizeof(this)); /* Get my own socket node */ if (csock == -1) NgMkSockNode(NULL, &csock, NULL); for (; this != NULL; this = next) { u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; struct ng_mesg *resp = (struct ng_mesg *) rbuf; struct nodeinfo *ni = (struct nodeinfo *) resp->data; char path[64]; /* Read in ngpcb structure */ kread((u_long)this, (char *)&ngpcb, sizeof(ngpcb)); next = LIST_NEXT(&ngpcb, socks); /* Read in socket structure */ kread((u_long)ngpcb.ng_socket, (char *)&sockb, sizeof(sockb)); /* Check type of socket */ if (strcmp(name, "ctrl") == 0 && ngpcb.type != NG_CONTROL) continue; if (strcmp(name, "data") == 0 && ngpcb.type != NG_DATA) continue; /* Do headline */ if (first) { xo_emit("{T:Netgraph sockets}\n"); if (Aflag) xo_emit("{T:/%-8.8s} ", "PCB"); xo_emit("{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} " "{T:/%-14.14s} {T:/%s}\n", "Type", "Recv-Q", "Send-Q", "Node Address", "#Hooks"); first = 0; } /* Show socket */ if (Aflag) xo_emit("{:address/%8lx} ", (u_long) this); xo_emit("{t:name/%-5.5s} {:receive-bytes-waiting/%6u} " "{:send-byte-waiting/%6u} ", name, sockb.so_rcv.sb_ccc, sockb.so_snd.sb_ccc); /* Get info on associated node */ if (ngpcb.node_id == 0 || csock == -1) goto finish; snprintf(path, sizeof(path), "[%x]:", ngpcb.node_id); if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) goto finish; if (NgRecvMsg(csock, resp, sizeof(rbuf), NULL) < 0) goto finish; /* Display associated node info */ if (*ni->name != '\0') snprintf(path, sizeof(path), "%s:", ni->name); xo_emit("{t:path/%-14.14s} {:hooks/%4d}", path, ni->hooks); finish: xo_emit("\n"); } } Index: head/usr.bin/netstat/netisr.c =================================================================== --- head/usr.bin/netstat/netisr.c (revision 287406) +++ head/usr.bin/netstat/netisr.c (revision 287407) @@ -1,575 +1,507 @@ /*- * Copyright (c) 2010-2011 Juniper Networks, Inc. * All rights reserved. * * This software was developed by Robert N. M. Watson under contract * to Juniper Networks, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #define _WANT_NETISR_INTERNAL #include #include #include -#include #include #include #include #include #include #include #include "netstat.h" +#include "nl_defs.h" /* * Print statistics for the kernel netisr subsystem. */ static u_int bindthreads; static u_int maxthreads; static u_int numthreads; static u_int defaultqlimit; static u_int maxqlimit; static char dispatch_policy[20]; static struct sysctl_netisr_proto *proto_array; static u_int proto_array_len; static struct sysctl_netisr_workstream *workstream_array; static u_int workstream_array_len; static struct sysctl_netisr_work *work_array; static u_int work_array_len; static u_int *nws_array; static u_int maxprot; static void netisr_dispatch_policy_to_string(u_int policy, char *buf, size_t buflen) { const char *str; switch (policy) { case NETISR_DISPATCH_DEFAULT: str = "default"; break; case NETISR_DISPATCH_DEFERRED: str = "deferred"; break; case NETISR_DISPATCH_HYBRID: str = "hybrid"; break; case NETISR_DISPATCH_DIRECT: str = "direct"; break; default: str = "unknown"; break; } snprintf(buf, buflen, "%s", str); } -static void -netisr_load_kvm_uint(kvm_t *kd, const char *name, u_int *p) -{ - struct nlist nl[] = { - { .n_name = name }, - { .n_name = NULL }, - }; - int ret; - - ret = kvm_nlist(kd, nl); - if (ret < 0) - xo_errx(-1, "%s: kvm_nlist(%s): %s", __func__, name, - kvm_geterr(kd)); - if (ret != 0) - xo_errx(-1, "%s: kvm_nlist(%s): unresolved symbol", __func__, - name); - if (kvm_read(kd, nl[0].n_value, p, sizeof(*p)) != sizeof(*p)) - xo_errx(-1, "%s: kvm_read(%s): %s", __func__, name, - kvm_geterr(kd)); -} - /* * Load a nul-terminated string from KVM up to 'limit', guarantee that the * string in local memory is nul-terminated. */ static void -netisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest, u_int limit) +netisr_load_kvm_string(uintptr_t addr, char *dest, u_int limit) { u_int i; for (i = 0; i < limit; i++) { - if (kvm_read(kd, addr + i, &dest[i], sizeof(dest[i])) != - sizeof(dest[i])) - xo_err(-1, "%s: kvm_read: %s", __func__, - kvm_geterr(kd)); + if (kread(addr + i, &dest[i], sizeof(dest[i])) != 0) + xo_errx(-1, "%s: kread()", __func__); if (dest[i] == '\0') break; } dest[limit - 1] = '\0'; } static const char * netisr_proto2name(u_int proto) { u_int i; for (i = 0; i < proto_array_len; i++) { if (proto_array[i].snp_proto == proto) return (proto_array[i].snp_name); } return ("unknown"); } static int netisr_protoispresent(u_int proto) { u_int i; for (i = 0; i < proto_array_len; i++) { if (proto_array[i].snp_proto == proto) return (1); } return (0); } static void -netisr_load_kvm_config(kvm_t *kd) +netisr_load_kvm_config(void) { u_int tmp; - netisr_load_kvm_uint(kd, "_netisr_bindthreads", &bindthreads); - netisr_load_kvm_uint(kd, "_netisr_maxthreads", &maxthreads); - netisr_load_kvm_uint(kd, "_nws_count", &numthreads); + kread(nl[N_NETISR_BINDTHREADS].n_value, &bindthreads, sizeof(u_int)); + kread(nl[N_NETISR_MAXTHREADS].n_value, &maxthreads, sizeof(u_int)); + kread(nl[N_NWS_COUNT].n_value, &numthreads, sizeof(u_int)); + kread(nl[N_NETISR_DEFAULTQLIMIT].n_value, &defaultqlimit, + sizeof(u_int)); + kread(nl[N_NETISR_MAXQLIMIT].n_value, &maxqlimit, sizeof(u_int)); + kread(nl[N_NETISR_DISPATCH_POLICY].n_value, &tmp, sizeof(u_int)); - netisr_load_kvm_uint(kd, "_netisr_defaultqlimit", &defaultqlimit); - netisr_load_kvm_uint(kd, "_netisr_maxqlimit", &maxqlimit); - - netisr_load_kvm_uint(kd, "_netisr_dispatch_policy", &tmp); netisr_dispatch_policy_to_string(tmp, dispatch_policy, sizeof(dispatch_policy)); } static void netisr_load_sysctl_uint(const char *name, u_int *p) { size_t retlen; retlen = sizeof(u_int); if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) xo_err(-1, "%s", name); if (retlen != sizeof(u_int)) xo_errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen); } static void netisr_load_sysctl_string(const char *name, char *p, size_t len) { size_t retlen; retlen = len; if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) xo_err(-1, "%s", name); p[len - 1] = '\0'; } static void netisr_load_sysctl_config(void) { netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads); netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads); netisr_load_sysctl_uint("net.isr.numthreads", &numthreads); netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit); netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit); netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy, sizeof(dispatch_policy)); } static void -netisr_load_kvm_proto(kvm_t *kd) +netisr_load_kvm_proto(void) { - struct nlist nl[] = { -#define NLIST_NETISR_PROTO 0 - { .n_name = "_netisr_proto" }, - { .n_name = NULL }, - }; struct netisr_proto *np_array, *npp; u_int i, protocount; struct sysctl_netisr_proto *snpp; size_t len; - int ret; /* * Kernel compile-time and user compile-time definitions of * NETISR_MAXPROT must match, as we use that to size work arrays. */ - netisr_load_kvm_uint(kd, "_netisr_maxprot", &maxprot); + kread(nl[N_NETISR_MAXPROT].n_value, &maxprot, sizeof(u_int)); if (maxprot != NETISR_MAXPROT) xo_errx(-1, "%s: NETISR_MAXPROT mismatch", __func__); len = maxprot * sizeof(*np_array); np_array = malloc(len); if (np_array == NULL) xo_err(-1, "%s: malloc", __func__); - ret = kvm_nlist(kd, nl); - if (ret < 0) - xo_errx(-1, "%s: kvm_nlist(_netisr_proto): %s", __func__, - kvm_geterr(kd)); - if (ret != 0) - xo_errx(-1, "%s: kvm_nlist(_netisr_proto): unresolved symbol", - __func__); - if (kvm_read(kd, nl[NLIST_NETISR_PROTO].n_value, np_array, len) != - (ssize_t)len) - xo_errx(-1, "%s: kvm_read(_netisr_proto): %s", __func__, - kvm_geterr(kd)); + if (kread(nl[N_NETISR_PROTO].n_value, np_array, len) != 0) + xo_errx(-1, "%s: kread(_netisr_proto)", __func__); /* * Size and allocate memory to hold only live protocols. */ protocount = 0; for (i = 0; i < maxprot; i++) { if (np_array[i].np_name == NULL) continue; protocount++; } proto_array = calloc(protocount, sizeof(*proto_array)); if (proto_array == NULL) err(-1, "malloc"); protocount = 0; for (i = 0; i < maxprot; i++) { npp = &np_array[i]; if (npp->np_name == NULL) continue; snpp = &proto_array[protocount]; snpp->snp_version = sizeof(*snpp); - netisr_load_kvm_string(kd, (uintptr_t)npp->np_name, + netisr_load_kvm_string((uintptr_t)npp->np_name, snpp->snp_name, sizeof(snpp->snp_name)); snpp->snp_proto = i; snpp->snp_qlimit = npp->np_qlimit; snpp->snp_policy = npp->np_policy; snpp->snp_dispatch = npp->np_dispatch; if (npp->np_m2flow != NULL) snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW; if (npp->np_m2cpuid != NULL) snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID; if (npp->np_drainedcpu != NULL) snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU; protocount++; } proto_array_len = protocount; free(np_array); } static void netisr_load_sysctl_proto(void) { size_t len; if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0) xo_err(-1, "net.isr.proto: query len"); if (len % sizeof(*proto_array) != 0) xo_errx(-1, "net.isr.proto: invalid len"); proto_array = malloc(len); if (proto_array == NULL) xo_err(-1, "malloc"); if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0) xo_err(-1, "net.isr.proto: query data"); if (len % sizeof(*proto_array) != 0) xo_errx(-1, "net.isr.proto: invalid len"); proto_array_len = len / sizeof(*proto_array); if (proto_array_len < 1) xo_errx(-1, "net.isr.proto: no data"); if (proto_array[0].snp_version != sizeof(proto_array[0])) xo_errx(-1, "net.isr.proto: invalid version"); } static void -netisr_load_kvm_workstream(kvm_t *kd) +netisr_load_kvm_workstream(void) { - struct nlist nl[] = { -#define NLIST_NWS_ARRAY 0 - { .n_name = "_nws_array" }, - { .n_name = NULL }, - }; struct netisr_workstream nws; struct sysctl_netisr_workstream *snwsp; struct sysctl_netisr_work *snwp; struct netisr_work *nwp; - struct nlist nl_nws[2]; u_int counter, cpuid, proto, wsid; size_t len; - int ret; len = numthreads * sizeof(*nws_array); nws_array = malloc(len); if (nws_array == NULL) xo_err(-1, "malloc"); - ret = kvm_nlist(kd, nl); - if (ret < 0) - xo_errx(-1, "%s: kvm_nlist: %s", __func__, kvm_geterr(kd)); - if (ret != 0) - xo_errx(-1, "%s: kvm_nlist: unresolved symbol", __func__); - if (kvm_read(kd, nl[NLIST_NWS_ARRAY].n_value, nws_array, len) != - (ssize_t)len) - xo_errx(-1, "%s: kvm_read(_nws_array): %s", __func__, - kvm_geterr(kd)); + if (kread(nl[N_NWS_ARRAY].n_value, nws_array, len) != 0) + xo_errx(-1, "%s: kread(_nws_array)", __func__); workstream_array = calloc(numthreads, sizeof(*workstream_array)); if (workstream_array == NULL) xo_err(-1, "calloc"); workstream_array_len = numthreads; work_array = calloc(numthreads * proto_array_len, sizeof(*work_array)); if (work_array == NULL) xo_err(-1, "calloc"); counter = 0; for (wsid = 0; wsid < numthreads; wsid++) { cpuid = nws_array[wsid]; - if (kvm_dpcpu_setcpu(kd, cpuid) < 0) - xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__, - cpuid, kvm_geterr(kd)); - bzero(nl_nws, sizeof(nl_nws)); - nl_nws[0].n_name = "_nws"; - ret = kvm_nlist(kd, nl_nws); - if (ret < 0) - xo_errx(-1, "%s: kvm_nlist looking up nws on CPU " - "%u: %s", __func__, cpuid, kvm_geterr(kd)); - if (ret != 0) - xo_errx(-1, "%s: kvm_nlist(nws): unresolved symbol on " - "CPU %u", __func__, cpuid); - if (kvm_read(kd, nl_nws[0].n_value, &nws, sizeof(nws)) != - sizeof(nws)) - xo_errx(-1, "%s: kvm_read(nw): %s", __func__, - kvm_geterr(kd)); + kset_dpcpu(cpuid); + if (kread(nl[N_NWS].n_value, &nws, sizeof(nws)) != 0) + xo_errx(-1, "%s: kread(nw)", __func__); snwsp = &workstream_array[wsid]; snwsp->snws_version = sizeof(*snwsp); snwsp->snws_wsid = cpuid; snwsp->snws_cpu = cpuid; if (nws.nws_intr_event != NULL) snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR; /* * Extract the CPU's per-protocol work information. */ xo_emit("counting to maxprot: {:maxprot/%u}\n", maxprot); for (proto = 0; proto < maxprot; proto++) { if (!netisr_protoispresent(proto)) continue; nwp = &nws.nws_work[proto]; snwp = &work_array[counter]; snwp->snw_version = sizeof(*snwp); snwp->snw_wsid = cpuid; snwp->snw_proto = proto; snwp->snw_len = nwp->nw_len; snwp->snw_watermark = nwp->nw_watermark; snwp->snw_dispatched = nwp->nw_dispatched; snwp->snw_hybrid_dispatched = nwp->nw_hybrid_dispatched; snwp->snw_qdrops = nwp->nw_qdrops; snwp->snw_queued = nwp->nw_queued; snwp->snw_handled = nwp->nw_handled; counter++; } } work_array_len = counter; } static void netisr_load_sysctl_workstream(void) { size_t len; if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0) xo_err(-1, "net.isr.workstream: query len"); if (len % sizeof(*workstream_array) != 0) xo_errx(-1, "net.isr.workstream: invalid len"); workstream_array = malloc(len); if (workstream_array == NULL) xo_err(-1, "malloc"); if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL, 0) < 0) xo_err(-1, "net.isr.workstream: query data"); if (len % sizeof(*workstream_array) != 0) xo_errx(-1, "net.isr.workstream: invalid len"); workstream_array_len = len / sizeof(*workstream_array); if (workstream_array_len < 1) xo_errx(-1, "net.isr.workstream: no data"); if (workstream_array[0].snws_version != sizeof(workstream_array[0])) xo_errx(-1, "net.isr.workstream: invalid version"); } static void netisr_load_sysctl_work(void) { size_t len; if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0) xo_err(-1, "net.isr.work: query len"); if (len % sizeof(*work_array) != 0) xo_errx(-1, "net.isr.work: invalid len"); work_array = malloc(len); if (work_array == NULL) xo_err(-1, "malloc"); if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0) xo_err(-1, "net.isr.work: query data"); if (len % sizeof(*work_array) != 0) xo_errx(-1, "net.isr.work: invalid len"); work_array_len = len / sizeof(*work_array); if (work_array_len < 1) xo_errx(-1, "net.isr.work: no data"); if (work_array[0].snw_version != sizeof(work_array[0])) xo_errx(-1, "net.isr.work: invalid version"); } static void netisr_print_proto(struct sysctl_netisr_proto *snpp) { char tmp[20]; xo_emit("{[:-6}{k:name/%s}{]:}", snpp->snp_name); xo_emit(" {:protocol/%5u}", snpp->snp_proto); xo_emit(" {:queue-limit/%6u}", snpp->snp_qlimit); xo_emit(" {:policy-type/%6s}", (snpp->snp_policy == NETISR_POLICY_SOURCE) ? "source" : (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" : (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-"); netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp, sizeof(tmp)); xo_emit(" {:policy/%8s}", tmp); xo_emit(" {:flags/%s%s%s}\n", (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ? "C" : "-", (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ? "D" : "-", (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-"); } static void netisr_print_workstream(struct sysctl_netisr_workstream *snwsp) { struct sysctl_netisr_work *snwp; u_int i; xo_open_list("work"); for (i = 0; i < work_array_len; i++) { snwp = &work_array[i]; if (snwp->snw_wsid != snwsp->snws_wsid) continue; xo_open_instance("work"); xo_emit("{t:workstream/%4u} ", snwsp->snws_wsid); xo_emit("{t:cpu/%3u} ", snwsp->snws_cpu); xo_emit("{P: }"); xo_emit("{t:name/%-6s}", netisr_proto2name(snwp->snw_proto)); xo_emit(" {t:length/%5u}", snwp->snw_len); xo_emit(" {t:watermark/%5u}", snwp->snw_watermark); xo_emit(" {t:dispatched/%8ju}", snwp->snw_dispatched); xo_emit(" {t:hybrid-dispatched/%8ju}", snwp->snw_hybrid_dispatched); xo_emit(" {t:queue-drops/%8ju}", snwp->snw_qdrops); xo_emit(" {t:queued/%8ju}", snwp->snw_queued); xo_emit(" {t:handled/%8ju}", snwp->snw_handled); xo_emit("\n"); xo_close_instance("work"); } xo_close_list("work"); } void -netisr_stats(void *kvmd) +netisr_stats(void) { struct sysctl_netisr_workstream *snwsp; struct sysctl_netisr_proto *snpp; - kvm_t *kd = kvmd; u_int i; if (live) { netisr_load_sysctl_config(); netisr_load_sysctl_proto(); netisr_load_sysctl_workstream(); netisr_load_sysctl_work(); } else { - if (kd == NULL) - xo_errx(-1, "netisr_stats: !live but !kd"); - netisr_load_kvm_config(kd); - netisr_load_kvm_proto(kd); - netisr_load_kvm_workstream(kd); /* Also does work. */ + netisr_load_kvm_config(); + netisr_load_kvm_proto(); + netisr_load_kvm_workstream(); /* Also does work. */ } xo_open_container("netisr"); xo_emit("{T:Configuration}:\n"); xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n", "Setting", "Current", "Limit"); xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n", "Thread count", numthreads, maxthreads); xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n", "Default queue limit", defaultqlimit, maxqlimit); xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n", "Dispatch policy", dispatch_policy, "n/a"); xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n", "Threads bound to CPUs", bindthreads ? "enabled" : "disabled", "n/a"); xo_emit("\n"); xo_emit("{T:Protocols}:\n"); xo_emit("{T:/%-6s} {T:/%5s} {T:/%6s} {T:/%-6s} {T:/%-8s} {T:/%-5s}\n", "Name", "Proto", "QLimit", "Policy", "Dispatch", "Flags"); xo_open_list("protocol"); for (i = 0; i < proto_array_len; i++) { xo_open_instance("protocol"); snpp = &proto_array[i]; netisr_print_proto(snpp); xo_close_instance("protocol"); } xo_close_list("protocol"); xo_emit("\n"); xo_emit("{T:Workstreams}:\n"); xo_emit("{T:/%4s} {T:/%3s} ", "WSID", "CPU"); xo_emit("{P:/%2s}", ""); xo_emit("{T:/%-6s} {T:/%5s} {T:/%5s} {T:/%8s} {T:/%8s} {T:/%8s} " "{T:/%8s} {T:/%8s}\n", "Name", "Len", "WMark", "Disp'd", "HDisp'd", "QDrops", "Queued", "Handled"); xo_open_list("workstream"); for (i = 0; i < workstream_array_len; i++) { xo_open_instance("workstream"); snwsp = &workstream_array[i]; netisr_print_workstream(snwsp); xo_close_instance("workstream"); } xo_close_list("workstream"); xo_close_container("netisr"); } Index: head/usr.bin/netstat/netstat.h =================================================================== --- head/usr.bin/netstat/netstat.h (revision 287406) +++ head/usr.bin/netstat/netstat.h (revision 287407) @@ -1,160 +1,159 @@ /*- * Copyright (c) 1992, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)netstat.h 8.2 (Berkeley) 1/4/94 * $FreeBSD$ */ #include #define satosin(sa) ((struct sockaddr_in *)(sa)) #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) extern int Aflag; /* show addresses of protocol control block */ extern int aflag; /* show all sockets (including servers) */ extern int bflag; /* show i/f total bytes in/out */ extern int dflag; /* show i/f dropped packets */ extern int gflag; /* show group (multicast) routing or stats */ extern int hflag; /* show counters in human readable format */ extern int iflag; /* show interfaces */ extern int Lflag; /* show size of listen queues */ extern int mflag; /* show memory stats */ extern int noutputs; /* how much outputs before we exit */ extern int numeric_addr; /* show addresses numerically */ extern int numeric_port; /* show ports numerically */ extern int rflag; /* show routing tables (or routing stats) */ extern int Rflag; /* show flowid / RSS information */ extern int sflag; /* show protocol statistics */ extern int Tflag; /* show TCP control block info */ extern int Wflag; /* wide display */ extern int xflag; /* extended display, includes all socket buffer info */ extern int zflag; /* zero stats */ extern int interval; /* repeat interval for i/f stats */ extern char *interface; /* desired i/f for stats, or NULL for all i/fs */ extern int unit; /* unit number for above */ extern int live; /* true if we are examining a live system */ -struct nlist; int kread(u_long addr, void *buf, size_t size); uint64_t kread_counter(u_long addr); int kread_counters(u_long addr, void *buf, size_t size); -int kresolve_list(struct nlist *); +void kset_dpcpu(u_int); const char *plural(uintmax_t); const char *plurales(uintmax_t); const char *pluralies(uintmax_t); struct sockaddr; struct socket; struct xsocket; int sotoxsocket(struct socket *, struct xsocket *); void protopr(u_long, const char *, int, int); void tcp_stats(u_long, const char *, int, int); void udp_stats(u_long, const char *, int, int); #ifdef SCTP void sctp_protopr(u_long, const char *, int, int); void sctp_stats(u_long, const char *, int, int); #endif void arp_stats(u_long, const char *, int, int); void ip_stats(u_long, const char *, int, int); void icmp_stats(u_long, const char *, int, int); void igmp_stats(u_long, const char *, int, int); void pim_stats(u_long, const char *, int, int); void carp_stats(u_long, const char *, int, int); void pfsync_stats(u_long, const char *, int, int); #ifdef IPSEC void ipsec_stats(u_long, const char *, int, int); void esp_stats(u_long, const char *, int, int); void ah_stats(u_long, const char *, int, int); void ipcomp_stats(u_long, const char *, int, int); #endif #ifdef INET6 void ip6_stats(u_long, const char *, int, int); void ip6_ifstats(char *); void icmp6_stats(u_long, const char *, int, int); void icmp6_ifstats(char *); void pim6_stats(u_long, const char *, int, int); void rip6_stats(u_long, const char *, int, int); void mroute6pr(void); void mrt6_stats(void); struct sockaddr_in6; struct in6_addr; void in6_fillscopeid(struct sockaddr_in6 *); void inet6print(const char *, struct in6_addr *, int, const char *, int); #endif /*INET6*/ #ifdef IPSEC void pfkey_stats(u_long, const char *, int, int); #endif void mbpr(void *, u_long); -void netisr_stats(void *); +void netisr_stats(void); void hostpr(u_long, u_long); void impstats(u_long, u_long); void intpr(void (*)(char *), int); void pr_family(int); void rt_stats(void); void flowtable_stats(void); char *routename(struct sockaddr *, int); const char *netname(struct sockaddr *, struct sockaddr *); char *ns_print(struct sockaddr *); void routepr(int, int); void nsprotopr(u_long, const char *, int, int); void spp_stats(u_long, const char *, int, int); void idp_stats(u_long, const char *, int, int); void nserr_stats(u_long, const char *, int, int); #ifdef NETGRAPH void netgraphprotopr(u_long, const char *, int, int); #endif void unixpr(u_long, u_long, u_long, u_long, u_long, bool *); void esis_stats(u_long, const char *, int, int); void clnp_stats(u_long, const char *, int, int); void cltp_stats(u_long, const char *, int, int); void iso_protopr(u_long, const char *, int, int); void iso_protopr1(u_long, int); void tp_protopr(u_long, const char *, int, int); void tp_inproto(u_long); void tp_stats(caddr_t, caddr_t); void mroutepr(void); void mrt_stats(void); void bpf_stats(char *); Index: head/usr.bin/netstat/nlist_symbols =================================================================== --- head/usr.bin/netstat/nlist_symbols (nonexistent) +++ head/usr.bin/netstat/nlist_symbols (revision 287407) @@ -0,0 +1,54 @@ +# $FreeBSD$ +# +# module_name symbol_name +all _ahstat +all _arpstat +all _carpstats +all _divcbinfo +all _espstat +all _icmp6stat +all _icmpstat +all _igmpstat +all _ip6stat +all _ipcompstat +all _ipsec4stat +all _ipsec6stat +all _ipstat +all _mf6ctable +all _mfchashtbl +all _mfctablesize +all _mif6table +all _mrt6stat +all _mrtstat +all _netisr_bindthreads +all _netisr_defaultqlimit +all _netisr_dispatch_policy +all _netisr_maxprot +all _netisr_maxqlimit +all _netisr_maxthreads +all _netisr_proto +all _ngsocklist +all _nws +all _nws_array +all _nws_count +all _pfkeystat +all _pfsyncstats +all _pim6stat +all _pimstat +all _rip6stat +all _ripcbinfo +all _rtree +all _rtstat +all _rttrash +all _sctpstat +all _sfstat +all _tcbinfo +all _tcpstat +all _udbinfo +all _udpstat +all _unp_count +all _unp_dhead +all _unp_gencnt +all _unp_shead +all _unp_sphead +all _viftable Property changes on: head/usr.bin/netstat/nlist_symbols ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.bin/netstat/route.c =================================================================== --- head/usr.bin/netstat/route.c (revision 287406) +++ head/usr.bin/netstat/route.c (revision 287407) @@ -1,781 +1,768 @@ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include "netstat.h" +#include "nl_defs.h" /* * Definitions for showing gateway flags. */ static struct bits { u_long b_mask; char b_val; const char *b_name; } bits[] = { { RTF_UP, 'U', "up" }, { RTF_GATEWAY, 'G', "gateway" }, { RTF_HOST, 'H', "host" }, { RTF_REJECT, 'R', "reject" }, { RTF_DYNAMIC, 'D', "dynamic" }, { RTF_MODIFIED, 'M', "modified" }, { RTF_DONE, 'd', "done" }, /* Completed -- for routing msgs only */ { RTF_XRESOLVE, 'X', "xresolve" }, { RTF_STATIC, 'S', "static" }, { RTF_PROTO1, '1', "proto1" }, { RTF_PROTO2, '2', "proto2" }, { RTF_PROTO3, '3', "proto3" }, { RTF_BLACKHOLE,'B', "blackhole" }, { RTF_BROADCAST,'b', "broadcast" }, #ifdef RTF_LLINFO { RTF_LLINFO, 'L', "llinfo" }, #endif { 0 , 0, NULL } }; -/* - * kvm(3) bindings for every needed symbol - */ -static struct nlist rl[] = { -#define N_RTSTAT 0 - { .n_name = "_rtstat" }, -#define N_RTTRASH 1 - { .n_name = "_rttrash" }, - { .n_name = NULL }, -}; - struct ifmap_entry { char ifname[IFNAMSIZ]; }; static struct ifmap_entry *ifmap; static int ifmap_size; static struct timespec uptime; static const char *netname4(in_addr_t, in_addr_t); static const char *netname6(struct sockaddr_in6 *, struct sockaddr_in6 *); static void p_rtable_sysctl(int, int); static void p_rtentry_sysctl(const char *name, struct rt_msghdr *); static void p_sockaddr(const char *name, struct sockaddr *, struct sockaddr *, int, int); static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags); static void p_flags(int, const char *); static const char *fmt_flags(int f); static void domask(char *, in_addr_t, u_long); /* * Print routing tables. */ void routepr(int fibnum, int af) { size_t intsize; int numfibs; if (live == 0) return; intsize = sizeof(int); if (fibnum == -1 && sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) fibnum = 0; if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) numfibs = 1; if (fibnum < 0 || fibnum > numfibs - 1) errx(EX_USAGE, "%d: invalid fib", fibnum); /* * Since kernel & userland use different timebase * (time_uptime vs time_second) and we are reading kernel memory * directly we should do rt_expire --> expire_time conversion. */ if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) err(EX_OSERR, "clock_gettime() failed"); xo_open_container("route-information"); xo_emit("{T:Routing tables}"); if (fibnum) xo_emit(" ({L:fib}: {:fib/%d})", fibnum); xo_emit("\n"); p_rtable_sysctl(fibnum, af); xo_close_container("route-information"); } /* * Print address family header before a section of the routing table. */ void pr_family(int af1) { const char *afname; switch (af1) { case AF_INET: afname = "Internet"; break; #ifdef INET6 case AF_INET6: afname = "Internet6"; break; #endif /*INET6*/ case AF_ISO: afname = "ISO"; break; case AF_CCITT: afname = "X.25"; break; case AF_NETGRAPH: afname = "Netgraph"; break; default: afname = NULL; break; } if (afname) xo_emit("\n{k:address-family/%s}:\n", afname); else xo_emit("\n{L:Protocol Family} {k:address-family/%d}:\n", af1); } /* column widths; each followed by one space */ #ifndef INET6 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ #define WID_IF_DEFAULT(af) (Wflag ? 10 : 8) /* width of netif column */ #else #define WID_DST_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) #define WID_GW_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) #define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 10 : 8)) #endif /*INET6*/ static int wid_dst; static int wid_gw; static int wid_flags; static int wid_pksent; static int wid_mtu; static int wid_if; static int wid_expire; /* * Print header for routing table columns. */ static void pr_rthdr(int af1 __unused) { if (Wflag) { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", wid_dst, wid_dst, "Destination", wid_gw, wid_gw, "Gateway", wid_flags, wid_flags, "Flags", wid_pksent, wid_pksent, "Use", wid_mtu, wid_mtu, "Mtu", wid_if, wid_if, "Netif", wid_expire, "Expire"); } else { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*s}\n", wid_dst, wid_dst, "Destination", wid_gw, wid_gw, "Gateway", wid_flags, wid_flags, "Flags", wid_if, wid_if, "Netif", wid_expire, "Expire"); } } static void p_rtable_sysctl(int fibnum, int af) { size_t needed; int mib[7]; char *buf, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa; int fam = AF_UNSPEC, ifindex = 0, size; int need_table_close = false; struct ifaddrs *ifap, *ifa; struct sockaddr_dl *sdl; /* * Retrieve interface list at first * since we need #ifindex -> if_xname match */ if (getifaddrs(&ifap) != 0) err(EX_OSERR, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; ifindex = sdl->sdl_index; if (ifindex >= ifmap_size) { size = roundup(ifindex + 1, 32) * sizeof(struct ifmap_entry); if ((ifmap = realloc(ifmap, size)) == NULL) errx(2, "realloc(%d) failed", size); memset(&ifmap[ifmap_size], 0, size - ifmap_size * sizeof(struct ifmap_entry)); ifmap_size = roundup(ifindex + 1, 32); } if (*ifmap[ifindex].ifname != '\0') continue; strlcpy(ifmap[ifindex].ifname, ifa->ifa_name, IFNAMSIZ); } freeifaddrs(ifap); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = af; mib[4] = NET_RT_DUMP; mib[5] = 0; mib[6] = fibnum; if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum); if ((buf = malloc(needed)) == NULL) errx(2, "malloc(%lu)", (unsigned long)needed); if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); lim = buf + needed; xo_open_container("route-table"); xo_open_list("rt-family"); for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; /* * Peek inside header to determine AF */ sa = (struct sockaddr *)(rtm + 1); /* Only print family first time. */ if (fam != sa->sa_family) { if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } need_table_close = true; fam = sa->sa_family; wid_dst = WID_DST_DEFAULT(fam); wid_gw = WID_GW_DEFAULT(fam); wid_flags = 6; wid_pksent = 8; wid_mtu = 6; wid_if = WID_IF_DEFAULT(fam); wid_expire = 6; xo_open_instance("rt-family"); pr_family(fam); xo_open_list("rt-entry"); pr_rthdr(fam); } p_rtentry_sysctl("rt-entry", rtm); } if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } xo_close_list("rt-family"); xo_close_container("route-table"); free(buf); } static void p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm) { struct sockaddr *sa, *addr[RTAX_MAX]; char buffer[128]; char prettyname[128]; int i; xo_open_instance(name); sa = (struct sockaddr *)(rtm + 1); for (i = 0; i < RTAX_MAX; i++) { if (rtm->rtm_addrs & (1 << i)) addr[i] = sa; sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); } p_sockaddr("destination", addr[RTAX_DST], addr[RTAX_NETMASK], rtm->rtm_flags, wid_dst); p_sockaddr("gateway", addr[RTAX_GATEWAY], NULL, RTF_HOST, wid_gw); snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ", wid_flags); p_flags(rtm->rtm_flags, buffer); if (Wflag) { xo_emit("{t:use/%*lu} ", wid_pksent, rtm->rtm_rmx.rmx_pksent); if (rtm->rtm_rmx.rmx_mtu != 0) xo_emit("{t:mtu/%*lu} ", wid_mtu, rtm->rtm_rmx.rmx_mtu); else xo_emit("{P:/%*s} ", wid_mtu, ""); } memset(prettyname, 0, sizeof(prettyname)); if (rtm->rtm_index < ifmap_size) { strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, sizeof(prettyname)); if (*prettyname == '\0') strlcpy(prettyname, "---", sizeof(prettyname)); } xo_emit("{t:interface-name/%*.*s}", wid_if, wid_if, prettyname); if (rtm->rtm_rmx.rmx_expire) { time_t expire_time; if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) xo_emit(" {:expire-time/%*d}", wid_expire, (int)expire_time); } xo_emit("\n"); xo_close_instance(name); } static void p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, int flags, int width) { const char *cp; char buf[128]; cp = fmt_sockaddr(sa, mask, flags); if (width < 0) { snprintf(buf, sizeof(buf), "{:%s/%%s} ", name); xo_emit(buf, cp); } else { if (Wflag != 0 || numeric_addr) { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%s}{]:} ", -width, name); xo_emit(buf, cp); } else { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%-.*s}{]:} ", -width, name); xo_emit(buf, width, cp); } } } static const char * fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) { static char buf[128]; const char *cp; if (sa == NULL) return ("null"); switch(sa->sa_family) { #ifdef INET6 case AF_INET6: /* * The sa6->sin6_scope_id must be filled here because * this sockaddr is extracted from kmem(4) directly * and has KAME-specific embedded scope id in * sa6->sin6_addr.s6_addr[2]. */ in6_fillscopeid(satosin6(sa)); /* FALLTHROUGH */ #endif /*INET6*/ case AF_INET: if (flags & RTF_HOST) cp = routename(sa, numeric_addr); else if (mask) cp = netname(sa, mask); else cp = netname(sa, NULL); break; case AF_NETGRAPH: { strlcpy(buf, ((struct sockaddr_ng *)sa)->sg_data, sizeof(buf)); cp = buf; break; } case AF_LINK: { #if 0 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; /* Interface route. */ if (sdl->sdl_nlen) cp = sdl->sdl_data; else #endif cp = routename(sa, 1); break; } default: { u_char *s = (u_char *)sa->sa_data, *slim; char *cq, *cqlim; cq = buf; slim = sa->sa_len + (u_char *) sa; cqlim = cq + sizeof(buf) - 6; cq += sprintf(cq, "(%d)", sa->sa_family); while (s < slim && cq < cqlim) { cq += sprintf(cq, " %02x", *s++); if (s < slim) cq += sprintf(cq, "%02x", *s++); } cp = buf; } } return (cp); } static void p_flags(int f, const char *format) { struct bits *p; xo_emit(format, fmt_flags(f)); xo_open_list("flags_pretty"); for (p = bits; p->b_mask; p++) if (p->b_mask & f) xo_emit("{le:flags_pretty/%s}", p->b_name); xo_close_list("flags_pretty"); } static const char * fmt_flags(int f) { static char name[33]; char *flags; struct bits *p = bits; for (flags = name; p->b_mask; p++) if (p->b_mask & f) *flags++ = p->b_val; *flags = '\0'; return (name); } char * routename(struct sockaddr *sa, int flags) { static char line[NI_MAXHOST]; int error, f; f = (flags) ? NI_NUMERICHOST : 0; error = getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, f); if (error) { const void *src; switch (sa->sa_family) { #ifdef INET case AF_INET: src = &satosin(sa)->sin_addr; break; #endif /* INET */ #ifdef INET6 case AF_INET6: src = &satosin6(sa)->sin6_addr; break; #endif /* INET6 */ default: return(line); } inet_ntop(sa->sa_family, src, line, sizeof(line) - 1); return (line); } trimdomain(line, strlen(line)); return (line); } #define NSHIFT(m) ( \ (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 0) static void domask(char *dst, in_addr_t addr __unused, u_long mask) { int b, i; if (mask == 0) { *dst = '\0'; return; } i = 0; for (b = 0; b < 32; b++) if (mask & (1 << b)) { int bb; i = b; for (bb = b+1; bb < 32; bb++) if (!(mask & (1 << bb))) { i = -1; /* noncontig */ break; } break; } if (i == -1) sprintf(dst, "&0x%lx", mask); else sprintf(dst, "/%d", 32-i); } /* * Return the name of the network whose address is given. */ const char * netname(struct sockaddr *sa, struct sockaddr *mask) { switch (sa->sa_family) { case AF_INET: if (mask != NULL) return (netname4(satosin(sa)->sin_addr.s_addr, satosin(mask)->sin_addr.s_addr)); else return (netname4(satosin(sa)->sin_addr.s_addr, INADDR_ANY)); break; #ifdef INET6 case AF_INET6: return (netname6(satosin6(sa), satosin6(mask))); #endif /* INET6 */ default: return (NULL); } } static const char * netname4(in_addr_t in, in_addr_t mask) { char *cp = 0; static char line[MAXHOSTNAMELEN + sizeof("/xx")]; char nline[INET_ADDRSTRLEN]; struct netent *np = 0; in_addr_t i; if (in == INADDR_ANY && mask == 0) { strlcpy(line, "default", sizeof(line)); return (line); } /* It is ok to supply host address. */ in &= mask; i = ntohl(in); if (!numeric_addr && i) { np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); if (np != NULL) { cp = np->n_name; trimdomain(cp, strlen(cp)); } } inet_ntop(AF_INET, &in, nline, sizeof(line)); if (cp != NULL) { if (strcpy(cp, nline) != 0) return (line); strlcpy(line, cp, sizeof(line)); } else strlcpy(line, nline, sizeof(line)); domask(line + strlen(line), i, ntohl(mask)); return (line); } #undef NSHIFT #ifdef INET6 void in6_fillscopeid(struct sockaddr_in6 *sa6) { #if defined(__KAME__) /* * XXX: This is a special workaround for KAME kernels. * sin6_scope_id field of SA should be set in the future. */ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { if (sa6->sin6_scope_id == 0) sa6->sin6_scope_id = ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; } #endif } /* Mask to length table. To check an invalid value, (length + 1) is used. */ static int masktolen[256] = { [0xff] = 8 + 1, [0xfe] = 7 + 1, [0xfc] = 6 + 1, [0xf8] = 5 + 1, [0xf0] = 4 + 1, [0xe0] = 3 + 1, [0xc0] = 2 + 1, [0x80] = 1 + 1, [0x00] = 0 + 1, }; static const char * netname6(struct sockaddr_in6 *sa6, struct sockaddr_in6 *mask) { static char line[NI_MAXHOST + sizeof("/xxx") - 1]; char nline[NI_MAXHOST]; u_char *p, *lim; int masklen, illegal = 0; if (mask) { p = (u_char *)&mask->sin6_addr; for (masklen = 0, lim = p + 16; p < lim; p++) { if (masktolen[*p] > 0) /* -1 is required. */ masklen += masktolen[*p] - 1; else illegal++; } if (illegal) xo_error("illegal prefixlen\n"); } else masklen = 128; if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) return("default"); getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, nline, sizeof(nline), NULL, 0, NI_NUMERICHOST); if (numeric_addr) strlcpy(line, nline, sizeof(line)); else getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), NULL, 0, 0); if (numeric_addr || strcmp(line, nline) == 0) sprintf(&line[strlen(line)], "/%d", masklen); return (line); } #endif /*INET6*/ /* * Print routing statistics */ void rt_stats(void) { struct rtstat rtstat; u_long rtsaddr, rttaddr; int rttrash; - kresolve_list(rl); - - if ((rtsaddr = rl[N_RTSTAT].n_value) == 0) { + if ((rtsaddr = nl[N_RTSTAT].n_value) == 0) { xo_emit("{W:rtstat: symbol not in namelist}\n"); return; } - if ((rttaddr = rl[N_RTTRASH].n_value) == 0) { + if ((rttaddr = nl[N_RTTRASH].n_value) == 0) { xo_emit("{W:rttrash: symbol not in namelist}\n"); return; } kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); xo_emit("{T:routing}:\n"); #define p(f, m) if (rtstat.f || sflag <= 1) \ xo_emit(m, rtstat.f, plural(rtstat.f)) p(rts_badredirect, "\t{:bad-redirects/%hu} " "{N:/bad routing redirect%s}\n"); p(rts_dynamic, "\t{:dynamically-created/%hu} " "{N:/dynamically created route%s}\n"); p(rts_newgateway, "\t{:new-gateways/%hu} " "{N:/new gateway%s due to redirects}\n"); p(rts_unreach, "\t{:unreachable-destination/%hu} " "{N:/destination%s found unreachable}\n"); p(rts_wildcard, "\t{:wildcard-uses/%hu} " "{N:/use%s of a wildcard route}\n"); #undef p if (rttrash || sflag <= 1) xo_emit("\t{:unused-but-not-freed/%u} " "{N:/route%s not in table but not freed}\n", rttrash, plural(rttrash)); }