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"

Reply via email to