svn commit: r259638 - head/usr.bin/netstat

Alexander V. Chernikov melifaro at FreeBSD.org
Fri Dec 20 00:17:28 UTC 2013


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;
 	}


More information about the svn-src-head mailing list