Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Apr 2013 20:29:23 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r249345 - head/usr.bin/netstat
Message-ID:  <201304102029.r3AKTNF8064667@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Wed Apr 10 20:29:23 2013
New Revision: 249345
URL: http://svnweb.freebsd.org/changeset/base/249345

Log:
  Use kvm_counter_u64_fetch() to fix obtaining ipstat and tcpstat from
  kernel core files.
  
  Sponsored by:	Nginx, Inc.

Modified:
  head/usr.bin/netstat/inet.c
  head/usr.bin/netstat/main.c
  head/usr.bin/netstat/netstat.h

Modified: head/usr.bin/netstat/inet.c
==============================================================================
--- head/usr.bin/netstat/inet.c	Wed Apr 10 20:26:53 2013	(r249344)
+++ head/usr.bin/netstat/inet.c	Wed Apr 10 20:29:23 2013	(r249345)
@@ -603,8 +603,13 @@ tcp_stats(u_long off, const char *name, 
 			warn("sysctl: net.inet.tcp.stats");
 			return;
 		}
-	} else
-		kread(off, &tcpstat, len);
+	} else {
+		u_long tcpstat_p[sizeof(struct tcpstat)/sizeof(uint64_t)];
+ 
+		kread(off, &tcpstat_p, sizeof(tcpstat_p));
+		kread_counters(tcpstat_p, (uint64_t *)&tcpstat,
+		    sizeof(struct tcpstat)/sizeof(uint64_t));
+	}
 
 	printf ("%s:\n", name);
 
@@ -858,8 +863,13 @@ ip_stats(u_long off, const char *name, i
 			warn("sysctl: net.inet.ip.stats");
 			return;
 		}
-	} else
-		kread(off, &ipstat, len);
+	} else {
+		u_long ipstat_p[sizeof(struct ipstat)/sizeof(uint64_t)];
+
+		kread(off, &ipstat_p, sizeof(ipstat_p));
+		kread_counters(ipstat_p, (uint64_t *)&ipstat,
+		    sizeof(struct ipstat)/sizeof(uint64_t));
+	}
 
 	printf("%s:\n", name);
 

Modified: head/usr.bin/netstat/main.c
==============================================================================
--- head/usr.bin/netstat/main.c	Wed Apr 10 20:26:53 2013	(r249344)
+++ head/usr.bin/netstat/main.c	Wed Apr 10 20:29:23 2013	(r249345)
@@ -147,11 +147,11 @@ static struct nlist nl[] = {
 #define	N_IPCOMPSTAT	37
 	{ .n_name = "_ipcompstat" },
 #define	N_TCPSTAT	38
-	{ .n_name = "_tcpstat" },
+	{ .n_name = "_tcpstatp" },
 #define	N_UDPSTAT	39
 	{ .n_name = "_udpstat" },
 #define	N_IPSTAT	40
-	{ .n_name = "_ipstat" },
+	{ .n_name = "_ipstatp" },
 #define	N_ICMPSTAT	41
 	{ .n_name = "_icmpstat" },
 #define	N_IGMPSTAT	42
@@ -696,37 +696,50 @@ printproto(struct protox *tp, const char
 		(*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);
+	setgid(getgid());
+
+	if (kvmd == NULL) {
+		warnx("kvm not available: %s", errbuf);
+		return (-1);
+	}
+
+	if (kvm_nlist(kvmd, nl) < 0) {
+		if (nlistf)
+			errx(1, "%s: kvm_nlist: %s", nlistf,
+			     kvm_geterr(kvmd));
+		else
+			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);
+}
+
 /*
  * Read kernel memory, return 0 on success.
  */
 int
 kread(u_long addr, void *buf, size_t size)
 {
-	char errbuf[_POSIX2_LINE_MAX];
 
-	if (kvmd == NULL) {
-		kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
-		setgid(getgid());
-		if (kvmd != NULL) {
-			if (kvm_nlist(kvmd, nl) < 0) {
-				if (nlistf)
-					errx(1, "%s: kvm_nlist: %s", nlistf,
-					     kvm_geterr(kvmd));
-				else
-					errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
-			}
+	if (kvmd_init() < 0)
+		return (-1);
 
-			if (nl[0].n_type == 0) {
-				if (nlistf)
-					errx(1, "%s: no namelist", nlistf);
-				else
-					errx(1, "no namelist");
-			}
-		} else {
-			warnx("kvm not available: %s", errbuf);
-			return(-1);
-		}
-	}
 	if (!buf)
 		return (0);
 	if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
@@ -736,6 +749,22 @@ kread(u_long addr, void *buf, size_t siz
 	return (0);
 }
 
+/*
+ * Read an array of N counters in kernel memory into array of N uint64_t's.
+ */
+int
+kread_counters(u_long *addr, uint64_t *rval, size_t count)
+{
+
+	if (kvmd_init() < 0)
+		return (-1);
+
+	for (u_int i = 0; i < count; i++, addr++, rval++)
+		*rval = kvm_counter_u64_fetch(kvmd, *addr);
+
+	return (0);
+}
+
 const char *
 plural(uintmax_t n)
 {

Modified: head/usr.bin/netstat/netstat.h
==============================================================================
--- head/usr.bin/netstat/netstat.h	Wed Apr 10 20:26:53 2013	(r249344)
+++ head/usr.bin/netstat/netstat.h	Wed Apr 10 20:29:23 2013	(r249345)
@@ -60,6 +60,7 @@ extern int	af;	/* address family */
 extern int	live;	/* true if we are examining a live system */
 
 int	kread(u_long addr, void *buf, size_t size);
+int	kread_counters(u_long *addr, uint64_t *rval, size_t count);
 const char *plural(uintmax_t);
 const char *plurales(uintmax_t);
 const char *pluralies(uintmax_t);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304102029.r3AKTNF8064667>