diff options
author | glebius <glebius@FreeBSD.org> | 2014-03-19 09:36:29 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2014-03-19 09:36:29 +0000 |
commit | 78bde6490528c198cd485385ecb997b6031f1bdb (patch) | |
tree | 6a605ad66fc5de0ab09fc2d971e094c397efb352 | |
parent | 73a339242daca126752a08f5390d85b17a8f0436 (diff) | |
download | FreeBSD-src-78bde6490528c198cd485385ecb997b6031f1bdb.zip FreeBSD-src-78bde6490528c198cd485385ecb997b6031f1bdb.tar.gz |
Merge r259562,r259566,r259638,r259645,r260124 by melifaro:
Switch netstat -rn to use standard API for retrieving list
of routes instead of peeking inside in-kernel radix via kget.
-rw-r--r-- | usr.bin/netstat/if.c | 2 | ||||
-rw-r--r-- | usr.bin/netstat/main.c | 49 | ||||
-rw-r--r-- | usr.bin/netstat/mroute.c | 43 | ||||
-rw-r--r-- | usr.bin/netstat/mroute6.c | 38 | ||||
-rw-r--r-- | usr.bin/netstat/netgraph.c | 51 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 17 | ||||
-rw-r--r-- | usr.bin/netstat/route.c | 365 |
7 files changed, 351 insertions, 214 deletions
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index e0f6e28..46ce775 100644 --- a/usr.bin/netstat/if.c +++ b/usr.bin/netstat/if.c @@ -224,7 +224,7 @@ next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family) * Print a description of the network interfaces. */ void -intpr(int interval, void (*pfunc)(char *)) +intpr(int interval, void (*pfunc)(char *), int af) { struct ifaddrs *ifap, *ifa; struct ifmaddrs *ifmap, *ifma; diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 0876460..dbec760 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -552,41 +552,41 @@ main(int argc, char *argv[]) * used for the queries, which is slower. */ #endif - kread(0, NULL, 0); if (iflag && !sflag) { - intpr(interval, NULL); + intpr(interval, NULL, af); exit(0); } if (rflag) { if (sflag) { - rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); + rt_stats(); flowtable_stats(); } else - routepr(nl[N_RTREE].n_value, fib); + routepr(fib, af); exit(0); } + if (gflag) { if (sflag) { if (af == AF_INET || af == AF_UNSPEC) - mrt_stats(nl[N_MRTSTAT].n_value); + mrt_stats(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) - mrt6_stats(nl[N_MRT6STAT].n_value); + mrt6_stats(); #endif } else { if (af == AF_INET || af == AF_UNSPEC) - mroutepr(nl[N_MFCHASHTBL].n_value, - nl[N_MFCTABLESIZE].n_value, - nl[N_VIFTABLE].n_value); + mroutepr(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) - mroute6pr(nl[N_MF6CTABLE].n_value, - nl[N_MIF6TABLE].n_value); + mroute6pr(); #endif } exit(0); } + /* Load all necessary kvm symbols */ + kresolve_list(nl); + if (tp) { printproto(tp, tp->pr_name); exit(0); @@ -639,7 +639,7 @@ printproto(struct protox *tp, const char *name) if (sflag) { if (iflag) { if (tp->pr_istats) - intpr(interval, tp->pr_istats); + intpr(interval, tp->pr_istats, af); else if (pflag) printf("%s: no per-interface stats routine\n", tp->pr_name); @@ -702,7 +702,23 @@ kvmd_init(void) return (-1); } - if (kvm_nlist(kvmd, nl) < 0) { + return (0); +} + +/* + * Resolve symbol list, return 0 on success. + */ +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) errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); @@ -710,13 +726,6 @@ kvmd_init(void) errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); } - if (nl[0].n_type == 0) { - if (nlistf) - errx(1, "%s: no namelist", nlistf); - else - errx(1, "no namelist"); - } - return (0); } diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c index 7cade4e..3766415 100644 --- a/usr.bin/netstat/mroute.c +++ b/usr.bin/netstat/mroute.c @@ -65,11 +65,26 @@ __FBSDID("$FreeBSD$"); #undef _KERNEL #include <err.h> +#include <nlist.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include "netstat.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 *); @@ -193,11 +208,12 @@ print_mfc(struct mfc *m, int maxvif, int *banner_printed) } void -mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl) +mroutepr() { 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; @@ -221,6 +237,16 @@ mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl) */ maxvif = 0; + kresolve_list(mrl); + pmfchashtbl = mrl[N_MFCHASHTBL].n_value; + pmfctablesize = mrl[N_MFCTABLESIZE].n_value; + pviftbl = mrl[N_VIFTABLE].n_value; + + if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) { + fprintf(stderr, "No IPv4 MROUTING kernel support.\n"); + return; + } + len = sizeof(viftable); if (live) { if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, @@ -338,15 +364,24 @@ mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl) } void -mrt_stats(u_long mstaddr) +mrt_stats() { struct mrtstat mrtstat; - size_t len = sizeof mrtstat; + u_long mstaddr; + size_t len = sizeof(mrtstat); + + kresolve_list(mrl); + mstaddr = mrl[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) { - warn("sysctl: net.inet.ip.mrtstat"); + warn("sysctl: net.inet.ip.mrtstat failed."); return; } } else diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c index c526d7c..ac31f5e 100644 --- a/usr.bin/netstat/mroute6.c +++ b/usr.bin/netstat/mroute6.c @@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <err.h> +#include <nlist.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -95,17 +96,32 @@ __FBSDID("$FreeBSD$"); #include "netstat.h" +/* + * kvm(3) bindings for every needed symbol + */ +static struct nlist mrl[] = { +#define N_MF6CTABLE 0 + { .n_name = "_mf6ctable" }, +#define N_MIF6TABLE 1 + { .n_name = "_mif6table" }, +#define N_MRT6STAT 2 + { .n_name = "_mrt6stat" }, + { .n_name = NULL }, +}; + + #define WID_ORG (Wflag ? 39 : (numeric_addr ? 29 : 18)) /* width of origin column */ #define WID_GRP (Wflag ? 18 : (numeric_addr ? 16 : 18)) /* width of group column */ void -mroute6pr(u_long mfcaddr, u_long mifaddr) +mroute6pr() { struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp; struct mif6 mif6table[MAXMIFS]; struct mf6c mfc; struct rtdetq rte, *rtep; struct mif6 *mifp; + u_long mfcaddr, mifaddr; mifi_t mifi; int i; int banner_printed; @@ -114,6 +130,15 @@ mroute6pr(u_long mfcaddr, u_long mifaddr) long int waitings; size_t len; + kresolve_list(mrl); + mfcaddr = mrl[N_MF6CTABLE].n_value; + mifaddr = mrl[N_MIF6TABLE].n_value; + + if (mfcaddr == 0 || mifaddr == 0) { + fprintf(stderr, "No IPv6 MROUTING kernel support.\n"); + return; + } + len = sizeof(mif6table); if (live) { if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len, @@ -217,11 +242,20 @@ mroute6pr(u_long mfcaddr, u_long mifaddr) } void -mrt6_stats(u_long mstaddr) +mrt6_stats() { struct mrt6stat mrtstat; + u_long mstaddr; size_t len = sizeof mrtstat; + kresolve_list(mrl); + mstaddr = mrl[N_MRT6STAT].n_value; + + if (mstaddr == 0) { + fprintf(stderr, "No IPv6 MROUTING kernel support.\n"); + return; + } + if (live) { if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, NULL, 0) < 0) { diff --git a/usr.bin/netstat/netgraph.c b/usr.bin/netstat/netgraph.c index 3427dd3..95578af 100644 --- a/usr.bin/netstat/netgraph.c +++ b/usr.bin/netstat/netgraph.c @@ -72,53 +72,10 @@ netgraphprotopr(u_long off, const char *name, int af1 __unused, /* If symbol not found, try looking in the KLD module */ if (off == 0) { - const char *const modname = "ng_socket.ko"; -/* XXX We should get "mpath" from "sysctl kern.module_path" */ - const char *mpath[] = { "/", "/boot/", "/modules/", NULL }; - struct nlist sym[] = { { .n_name = "_ngsocklist" }, - { .n_name = NULL } }; - const char **pre; - struct kld_file_stat ks; - int fileid; - - /* Can't do this for core dumps. */ - if (!live) - return; - - /* See if module is loaded */ - if ((fileid = kldfind(modname)) < 0) { - if (debug) - warn("kldfind(%s)", modname); - return; - } - - /* Get module info */ - memset(&ks, 0, sizeof(ks)); - ks.version = sizeof(struct kld_file_stat); - if (kldstat(fileid, &ks) < 0) { - if (debug) - warn("kldstat(%d)", fileid); - return; - } - - /* Get symbol table from module file */ - for (pre = mpath; *pre; pre++) { - char path[MAXPATHLEN]; - - snprintf(path, sizeof(path), "%s%s", *pre, modname); - if (nlist(path, sym) == 0) - break; - } - - /* Did we find it? */ - if (sym[0].n_value == 0) { - if (debug) - warnx("%s not found", modname); - return; - } - - /* Symbol found at load address plus symbol offset */ - off = (u_long) ks.address + sym[0].n_value; + if (debug) + fprintf(stderr, + "Error reading symbols from ng_socket.ko"); + return; } /* Get pointer to first socket */ diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index 44bce94..fd4ec96 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -56,11 +56,12 @@ 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 af; /* address family */ extern int live; /* true if we are examining a live system */ +struct nlist; int kread(u_long addr, void *buf, size_t size); int kread_counters(u_long addr, void *buf, size_t size); +int kresolve_list(struct nlist *); const char *plural(uintmax_t); const char *plurales(uintmax_t); const char *pluralies(uintmax_t); @@ -97,8 +98,8 @@ 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(u_long, u_long); -void mrt6_stats(u_long); +void mroute6pr(void); +void mrt6_stats(void); struct sockaddr_in6; struct in6_addr; @@ -119,11 +120,11 @@ void netisr_stats(void *); void hostpr(u_long, u_long); void impstats(u_long, u_long); -void intpr(int, void (*)(char *)); +void intpr(int, void (*)(char *), int); void pr_rthdr(int); void pr_family(int); -void rt_stats(u_long, u_long); +void rt_stats(void); void flowtable_stats(void); char *ipx_pnet(struct sockaddr *); char *ipx_phost(struct sockaddr *); @@ -136,7 +137,7 @@ char *atalk_print(struct sockaddr *, int); char *atalk_print2(struct sockaddr *, struct sockaddr *, int); char *ipx_print(struct sockaddr *); char *ns_print(struct sockaddr *); -void routepr(u_long, int); +void routepr(int, int); void ipxprotopr(u_long, const char *, int, int); void spx_stats(u_long, const char *, int, int); @@ -166,6 +167,6 @@ void tp_protopr(u_long, const char *, int, int); void tp_inproto(u_long); void tp_stats(caddr_t, caddr_t); -void mroutepr(u_long, u_long, u_long); -void mrt_stats(u_long); +void mroutepr(void); +void mrt_stats(void); void bpf_stats(char *); diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index 4381ffd..75c255f 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -58,8 +58,10 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <arpa/inet.h> +#include <ifaddrs.h> #include <libutil.h> #include <netdb.h> +#include <nlist.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -105,6 +107,19 @@ struct bits { { 0 , 0 } }; +/* + * kvm(3) bindings for every needed symbol + */ +static struct nlist rl[] = { +#define N_RTSTAT 0 + { .n_name = "_rtstat" }, +#define N_RTREE 1 + { .n_name = "_rt_tables"}, +#define N_RTTRASH 2 + { .n_name = "_rttrash" }, + { .n_name = NULL }, +}; + typedef union { long dummy; /* Helps align structure. */ struct sockaddr u_sa; @@ -113,13 +128,19 @@ typedef union { static sa_u pt_u; +struct ifmap_entry { + char ifname[IFNAMSIZ]; +}; + +static struct ifmap_entry *ifmap; +static int ifmap_size; + int do_rtent = 0; struct rtentry rtentry; struct radix_node rnode; struct radix_mask rmask; -struct radix_node_head **rt_tables; -int NewTree = 0; +int NewTree = 1; struct timespec uptime; @@ -127,27 +148,27 @@ static struct sockaddr *kgetsa(struct sockaddr *); static void size_cols(int ef, struct radix_node *rn); static void size_cols_tree(struct radix_node *rn); static void size_cols_rtentry(struct rtentry *rt); -static void p_tree(struct radix_node *); -static void p_rtnode(void); -static void ntreestuff(void); -static void np_rtentry(struct rt_msghdr *); +static void p_rtnode_kvm(void); +static void p_rtable_sysctl(int, int); +static void p_rtable_kvm(int, int ); +static void p_rtree_kvm(struct radix_node *); +static void p_rtentry_sysctl(struct rt_msghdr *); static void p_sockaddr(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 p_rtentry(struct rtentry *); +static void p_rtentry_kvm(struct rtentry *); static void domask(char *, in_addr_t, u_long); /* * Print routing tables. */ void -routepr(u_long rtree, int fibnum) +routepr(int fibnum, int af) { - struct radix_node_head **rnhp, *rnh, head; size_t intsize; - int fam, numfibs; + int numfibs; intsize = sizeof(int); if (fibnum == -1 && @@ -157,10 +178,6 @@ routepr(u_long rtree, int fibnum) numfibs = 1; if (fibnum < 0 || fibnum > numfibs - 1) errx(EX_USAGE, "%d: invalid fib", fibnum); - rt_tables = calloc(numfibs * (AF_MAX+1), - sizeof(struct radix_node_head *)); - if (rt_tables == NULL) - err(EX_OSERR, "memory allocation failed"); /* * Since kernel & userland use different timebase * (time_uptime vs time_second) and we are reading kernel memory @@ -174,55 +191,13 @@ routepr(u_long rtree, int fibnum) printf(" (fib: %d)", fibnum); printf("\n"); - if (Aflag == 0 && NewTree) - ntreestuff(); - else { - if (rtree == 0) { - printf("rt_tables: symbol not in namelist\n"); - return; - } - - if (kread((u_long)(rtree), (char *)(rt_tables), (numfibs * - (AF_MAX+1) * sizeof(struct radix_node_head *))) != 0) - return; - for (fam = 0; fam <= AF_MAX; fam++) { - int tmpfib; - - switch (fam) { - case AF_INET6: - case AF_INET: - tmpfib = fibnum; - break; - default: - tmpfib = 0; - } - rnhp = (struct radix_node_head **)*rt_tables; - /* Calculate the in-kernel address. */ - rnhp += tmpfib * (AF_MAX+1) + fam; - /* Read the in kernel rhn pointer. */ - if (kget(rnhp, rnh) != 0) - continue; - if (rnh == NULL) - continue; - /* Read the rnh data. */ - if (kget(rnh, head) != 0) - continue; - if (fam == AF_UNSPEC) { - if (Aflag && af == 0) { - printf("Netmasks:\n"); - p_tree(head.rnh_treetop); - } - } else if (af == AF_UNSPEC || af == fam) { - size_cols(fam, head.rnh_treetop); - pr_family(fam); - do_rtent = 1; - pr_rthdr(fam); - p_tree(head.rnh_treetop); - } - } - } + if (Aflag == 0 && live != 0 && NewTree) + p_rtable_sysctl(fibnum, af); + else + p_rtable_kvm(fibnum, af); } + /* * Print address family header before a section of the routing table. */ @@ -288,7 +263,7 @@ static int wid_if; static int wid_expire; static void -size_cols(int ef __unused, struct radix_node *rn) +size_cols(int ef, struct radix_node *rn) { wid_dst = WID_DST_DEFAULT(ef); wid_gw = WID_GW_DEFAULT(ef); @@ -299,7 +274,7 @@ size_cols(int ef __unused, struct radix_node *rn) wid_if = WID_IF_DEFAULT(ef); wid_expire = 6; - if (Wflag) + if (Wflag && rn != NULL) size_cols_tree(rn); } @@ -397,27 +372,14 @@ pr_rthdr(int af1) if (Aflag) printf("%-8.8s ","Address"); - if (af1 == AF_INET || Wflag) { - if (Wflag) { - printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*.*s %*s\n", - wid_dst, wid_dst, "Destination", - wid_gw, wid_gw, "Gateway", - wid_flags, wid_flags, "Flags", - wid_refs, wid_refs, "Refs", - wid_use, wid_use, "Use", - wid_mtu, wid_mtu, "Mtu", - wid_if, wid_if, "Netif", - wid_expire, "Expire"); - } else { - printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*s\n", - wid_dst, wid_dst, "Destination", - wid_gw, wid_gw, "Gateway", - wid_flags, wid_flags, "Flags", - wid_refs, wid_refs, "Refs", - wid_use, wid_use, "Use", - wid_if, wid_if, "Netif", - wid_expire, "Expire"); - } + if (Wflag) { + printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*s\n", + wid_dst, wid_dst, "Destination", + wid_gw, wid_gw, "Gateway", + wid_flags, wid_flags, "Flags", + wid_mtu, wid_mtu, "Mtu", + wid_if, wid_if, "Netif", + wid_expire, "Expire"); } else { printf("%-*.*s %-*.*s %-*.*s %*.*s %*s\n", wid_dst, wid_dst, "Destination", @@ -439,8 +401,77 @@ kgetsa(struct sockaddr *dst) return (&pt_u.u_sa); } +/* + * Print kernel routing tables for given fib + * using debugging kvm(3) interface. + */ static void -p_tree(struct radix_node *rn) +p_rtable_kvm(int fibnum, int af) +{ + struct radix_node_head **rnhp, *rnh, head; + struct radix_node_head **rt_tables; + u_long rtree; + int fam, af_size; + + kresolve_list(rl); + if ((rtree = rl[N_RTREE].n_value) == 0) { + printf("rt_tables: symbol not in namelist\n"); + return; + } + + af_size = (AF_MAX + 1) * sizeof(struct radix_node_head *); + rt_tables = calloc(1, af_size); + if (rt_tables == NULL) + err(EX_OSERR, "memory allocation failed"); + + if (kread((u_long)(rtree), (char *)(rt_tables) + fibnum * af_size, + af_size) != 0) + err(EX_OSERR, "error retrieving radix pointers"); + for (fam = 0; fam <= AF_MAX; fam++) { + int tmpfib; + + switch (fam) { + case AF_INET6: + case AF_INET: + tmpfib = fibnum; + break; + default: + tmpfib = 0; + } + rnhp = (struct radix_node_head **)*rt_tables; + /* Calculate the in-kernel address. */ + rnhp += tmpfib * (AF_MAX + 1) + fam; + /* Read the in kernel rhn pointer. */ + if (kget(rnhp, rnh) != 0) + continue; + if (rnh == NULL) + continue; + /* Read the rnh data. */ + if (kget(rnh, head) != 0) + continue; + if (fam == AF_UNSPEC) { + if (Aflag && af == 0) { + printf("Netmasks:\n"); + p_rtree_kvm(head.rnh_treetop); + } + } else if (af == AF_UNSPEC || af == fam) { + size_cols(fam, head.rnh_treetop); + pr_family(fam); + do_rtent = 1; + pr_rthdr(fam); + p_rtree_kvm(head.rnh_treetop); + } + } + + free(rt_tables); +} + +/* + * Print given kernel radix tree using + * debugging kvm(3) interface. + */ +static void +p_rtree_kvm(struct radix_node *rn) { again: @@ -457,9 +488,9 @@ again: rnode.rn_dupedkey ? " =>\n" : "\n"); } else if (do_rtent) { if (kget(rn, rtentry) == 0) { - p_rtentry(&rtentry); + p_rtentry_kvm(&rtentry); if (Aflag) - p_rtnode(); + p_rtnode_kvm(); } } else { p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), @@ -471,18 +502,18 @@ again: } else { if (Aflag && do_rtent) { printf("%-8.8lx ", (u_long)rn); - p_rtnode(); + p_rtnode_kvm(); } rn = rnode.rn_right; - p_tree(rnode.rn_left); - p_tree(rn); + p_rtree_kvm(rnode.rn_left); + p_rtree_kvm(rn); } } char nbuf[20]; static void -p_rtnode(void) +p_rtnode_kvm(void) { struct radix_mask *rm = rnode.rn_mklist; @@ -522,72 +553,137 @@ p_rtnode(void) } static void -ntreestuff(void) +p_rtable_sysctl(int fibnum, int af) { size_t needed; - int mib[6]; + int mib[7]; char *buf, *next, *lim; struct rt_msghdr *rtm; + struct sockaddr *sa; + int fam = 0, ifindex = 0, size; + + 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] = 0; + mib[3] = af; mib[4] = NET_RT_DUMP; mib[5] = 0; - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - err(1, "sysctl: net.route.0.0.dump estimate"); + mib[6] = fibnum; + if (sysctl(mib, 7, NULL, &needed, NULL, 0) < 0) { + err(1, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum); } if ((buf = malloc(needed)) == 0) { errx(2, "malloc(%lu)", (unsigned long)needed); } if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - err(1, "sysctl: net.route.0.0.dump"); + err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; - np_rtentry(rtm); + /* + * Peek inside header to determine AF + */ + sa = (struct sockaddr *)(rtm + 1); + if (fam != sa->sa_family) { + fam = sa->sa_family; + size_cols(fam, NULL); + pr_family(fam); + pr_rthdr(fam); + } + p_rtentry_sysctl(rtm); } } static void -np_rtentry(struct rt_msghdr *rtm) +p_rtentry_sysctl(struct rt_msghdr *rtm) { struct sockaddr *sa = (struct sockaddr *)(rtm + 1); -#ifdef notdef - static int masks_done, banner_printed; -#endif - static int old_af; - int af1 = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; - -#ifdef notdef - /* for the moment, netmasks are skipped over */ - if (!banner_printed) { - printf("Netmasks:\n"); - banner_printed = 1; + char buffer[128]; + char prettyname[128]; + sa_u addr, mask, gw; + unsigned int l; + +#define GETSA(_s, _f) { \ + bzero(&(_s), sizeof(_s)); \ + if (rtm->rtm_addrs & _f) { \ + l = roundup(sa->sa_len, sizeof(long)); \ + memcpy(&(_s), sa, (l > sizeof(_s)) ? sizeof(_s) : l); \ + sa = (struct sockaddr *)((char *)sa + l); \ + } \ +} + + GETSA(addr, RTA_DST); + GETSA(gw, RTA_GATEWAY); + GETSA(mask, RTA_NETMASK); + p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags, wid_dst); + p_sockaddr(&gw.u_sa, NULL, RTF_HOST, wid_gw); + + snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags); + p_flags(rtm->rtm_flags, buffer); + if (Wflag) { + if (rtm->rtm_rmx.rmx_mtu != 0) + printf("%*lu ", wid_mtu, rtm->rtm_rmx.rmx_mtu); + else + printf("%*s ", wid_mtu, ""); } - if (masks_done == 0) { - if (rtm->rtm_addrs != RTA_DST ) { - masks_done = 1; - af1 = sa->sa_family; - } - } else -#endif - af1 = sa->sa_family; - if (af1 != old_af) { - pr_family(af1); - old_af = af1; + + 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)); } - if (rtm->rtm_addrs == RTA_DST) - p_sockaddr(sa, NULL, 0, 36); - else { - p_sockaddr(sa, NULL, rtm->rtm_flags, 16); - sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); - p_sockaddr(sa, NULL, 0, 18); + + printf("%*.*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) + printf(" %*d", wid_expire, (int)expire_time); } - p_flags(rtm->rtm_flags & interesting, "%-6.6s "); + putchar('\n'); } @@ -756,7 +852,7 @@ fmt_flags(int f) } static void -p_rtentry(struct rtentry *rt) +p_rtentry_kvm(struct rtentry *rt) { static struct ifnet ifnet, *lastif; static char buffer[128]; @@ -775,8 +871,10 @@ p_rtentry(struct rtentry *rt) snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags); p_flags(rt->rt_flags, buffer); if (addr.u_sa.sa_family == AF_INET || Wflag) { +#if 0 printf("%*d %*lu ", wid_refs, rt->rt_refcnt, wid_use, rt->rt_use); +#endif if (Wflag) { if (rt->rt_rmx.rmx_mtu != 0) printf("%*lu ", wid_mtu, rt->rt_rmx.rmx_mtu); @@ -1009,16 +1107,19 @@ routename6(struct sockaddr_in6 *sa6) * Print routing statistics */ void -rt_stats(u_long rtsaddr, u_long rttaddr) +rt_stats(void) { struct rtstat rtstat; + u_long rtsaddr, rttaddr; int rttrash; - if (rtsaddr == 0) { + kresolve_list(rl); + + if ((rtsaddr = rl[N_RTSTAT].n_value) == 0) { printf("rtstat: symbol not in namelist\n"); return; } - if (rttaddr == 0) { + if ((rttaddr = rl[N_RTTRASH].n_value) == 0) { printf("rttrash: symbol not in namelist\n"); return; } |