Author: melifaro Date: Fri Dec 20 00:17:26 2013 New Revision: 259638 URL: http://svnweb.freebsd.org/changeset/base/259638
Log: Use more fine-grained kvm(3) symbol lookup: routing code retrieves only necessary symbols needed per subsystem. Main kvm(3) init is now delayed as much as possbile. This finally fixes performance issues reported in kern/167204. Some non-working code (ng_socket.ko symbol addresses calculation) removed. Some global variables eliminated. PR: kern/167204 MFC after: 4 weeks Modified: head/usr.bin/netstat/if.c head/usr.bin/netstat/main.c head/usr.bin/netstat/mroute.c head/usr.bin/netstat/mroute6.c head/usr.bin/netstat/netgraph.c head/usr.bin/netstat/netstat.h head/usr.bin/netstat/route.c Modified: head/usr.bin/netstat/if.c ============================================================================== --- head/usr.bin/netstat/if.c Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/if.c Fri Dec 20 00:17:26 2013 (r259638) @@ -223,7 +223,7 @@ next_ifma(struct ifmaddrs *ifma, const c * 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; Modified: head/usr.bin/netstat/main.c ============================================================================== --- head/usr.bin/netstat/main.c Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/main.c Fri Dec 20 00:17:26 2013 (r259638) @@ -319,7 +319,6 @@ int gflag; /* show group (multicast) ro int hflag; /* show counters in human readable format */ int iflag; /* show interfaces */ int Lflag; /* show size of listen queues */ -int Mflag; /* read statistics from core */ int mflag; /* show memory stats */ int noutputs = 0; /* how much outputs before we exit */ int numeric_addr; /* show addresses numerically */ @@ -425,7 +424,6 @@ main(int argc, char *argv[]) Lflag = 1; break; case 'M': - Mflag = 1; memf = optarg; break; case 'm': @@ -554,40 +552,40 @@ 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(); 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); @@ -640,7 +638,7 @@ printproto(struct protox *tp, const char 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); @@ -703,7 +701,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)); @@ -711,13 +725,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); } Modified: head/usr.bin/netstat/mroute.c ============================================================================== --- head/usr.bin/netstat/mroute.c Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/mroute.c Fri Dec 20 00:17:26 2013 (r259638) @@ -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 } 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 pmfc */ 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 pmfc } 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 Modified: head/usr.bin/netstat/mroute6.c ============================================================================== --- head/usr.bin/netstat/mroute6.c Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/mroute6.c Fri Dec 20 00:17:26 2013 (r259638) @@ -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) { Modified: head/usr.bin/netstat/netgraph.c ============================================================================== --- head/usr.bin/netstat/netgraph.c Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/netgraph.c Fri Dec 20 00:17:26 2013 (r259638) @@ -72,53 +72,10 @@ netgraphprotopr(u_long off, const char * /* 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 */ Modified: head/usr.bin/netstat/netstat.h ============================================================================== --- head/usr.bin/netstat/netstat.h Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/netstat.h Fri Dec 20 00:17:26 2013 (r259638) @@ -40,7 +40,6 @@ extern int gflag; /* show group (multica 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; /* read statistics from core */ extern int mflag; /* show memory stats */ extern int noutputs; /* how much outputs before we exit */ extern int numeric_addr; /* show addresses numerically */ @@ -57,11 +56,12 @@ extern int interval; /* repeat interval 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); @@ -98,8 +98,8 @@ void icmp6_stats(u_long, const char *, i 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; @@ -120,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); char *ipx_pnet(struct sockaddr *); char *ipx_phost(struct sockaddr *); char *ns_phost(struct sockaddr *); @@ -136,7 +136,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 +166,6 @@ void tp_protopr(u_long, const char *, in 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 *); Modified: head/usr.bin/netstat/route.c ============================================================================== --- head/usr.bin/netstat/route.c Fri Dec 20 00:09:14 2013 (r259637) +++ head/usr.bin/netstat/route.c Fri Dec 20 00:17:26 2013 (r259638) @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <ifaddrs.h> #include <libutil.h> #include <netdb.h> +#include <nlist.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -106,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; @@ -151,9 +165,10 @@ static void domask(char *, in_addr_t, u_ * Print routing tables. */ void -routepr(u_long rtree, int fibnum) +routepr(int fibnum, int af) { struct radix_node_head **rnhp, *rnh, head; + u_long rtree; size_t intsize; int fam, numfibs; @@ -165,10 +180,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 @@ -182,14 +193,20 @@ routepr(u_long rtree, int fibnum) printf(" (fib: %d)", fibnum); printf("\n"); - if (Aflag == 0 && Mflag == 0 && NewTree) + if (Aflag == 0 && live != 0 && NewTree) ntreestuff(fibnum, af); else { - if (rtree == 0) { + kresolve_list(rl); + if ((rtree = rl[N_RTREE].n_value) == 0) { printf("rt_tables: symbol not in namelist\n"); return; } + rt_tables = calloc(numfibs * (AF_MAX + 1), + sizeof(struct radix_node_head *)); + if (rt_tables == NULL) + err(EX_OSERR, "memory allocation failed"); + if (kread((u_long)(rtree), (char *)(rt_tables), (numfibs * (AF_MAX+1) * sizeof(struct radix_node_head *))) != 0) return; @@ -572,14 +589,14 @@ ntreestuff(int fibnum, int af) mib[5] = 0; mib[6] = fibnum; if (sysctl(mib, 7, NULL, &needed, NULL, 0) < 0) { - err(1, "sysctl: net.route.0.0.dump estimate"); + 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) { @@ -1071,16 +1088,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; } _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"