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

Alexander V. Chernikov melifaro at FreeBSD.org
Wed Dec 18 18:25:27 UTC 2013


Author: melifaro
Date: Wed Dec 18 18:25:27 2013
New Revision: 259562
URL: http://svnweb.freebsd.org/changeset/base/259562

Log:
  Switch netstat -rn to use standard API for retrieving list of routes
  instead of peeking inside in-kernel radix via kget.
  This permits us to change kernel structures without breaking userland.
  Additionally, this change provide more reliable and faster output.
  
  `Refs` and `Use` fields available in IPv4 by default (and via -W
  for other families) were removed. `Refs` is radix-specific thing
  which is not informative for users. `Use` field value is handy sometimes,
  but a) current API does not support it and b) I'm not sure we will
  support per-rte pcpu counters in near future.
  
  Old method of retrieving data is still supported (either by defining
  NewTree=0 or running netstat with -A). However, Refs/Use fields are
  hidden.
  
  Sponsored by:	Yandex LLC
  MFC after:	4 weeks
  PR:		kern/167204

Modified:
  head/usr.bin/netstat/route.c

Modified: head/usr.bin/netstat/route.c
==============================================================================
--- head/usr.bin/netstat/route.c	Wed Dec 18 17:03:43 2013	(r259561)
+++ head/usr.bin/netstat/route.c	Wed Dec 18 18:25:27 2013	(r259562)
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 
 #include <arpa/inet.h>
+#include <ifaddrs.h>
 #include <libutil.h>
 #include <netdb.h>
 #include <stdint.h>
@@ -113,13 +114,20 @@ 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;
 
@@ -129,7 +137,7 @@ static void size_cols_tree(struct radix_
 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 ntreestuff(int fibnum, int af);
 static void np_rtentry(struct rt_msghdr *);
 static void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int);
 static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask,
@@ -175,7 +183,7 @@ routepr(u_long rtree, int fibnum)
 	printf("\n");
 
 	if (Aflag == 0 && NewTree)
-		ntreestuff();
+		ntreestuff(fibnum, af);
 	else {
 		if (rtree == 0) {
 			printf("rt_tables: symbol not in namelist\n");
@@ -288,7 +296,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 +307,7 @@ size_cols(int ef __unused, struct radix_
 	wid_if = WID_IF_DEFAULT(ef);
 	wid_expire = 6;
 
-	if (Wflag)
+	if (Wflag && rn != NULL)
 		size_cols_tree(rn);
 }
 
@@ -397,27 +405,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",
@@ -522,20 +517,61 @@ p_rtnode(void)
 }
 
 static void
-ntreestuff(void)
+ntreestuff(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) {
+	mib[6] = fibnum;
+	if (sysctl(mib, 7, NULL, &needed, NULL, 0) < 0) {
 		err(1, "sysctl: net.route.0.0.dump estimate");
 	}
 
@@ -548,6 +584,16 @@ ntreestuff(void)
 	lim  = buf + needed;
 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
 		rtm = (struct rt_msghdr *)next;
+		/*
+		 * 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);
+		}
 		np_rtentry(rtm);
 	}
 }
@@ -556,38 +602,52 @@ static void
 np_rtentry(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;
+	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);
 
-#ifdef notdef
-	/* for the moment, netmasks are skipped over */
-	if (!banner_printed) {
-		printf("Netmasks:\n");
-		banner_printed = 1;
-	}
-	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;
+	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 (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);
+
+	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));
 	}
-	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
+
+	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);
+	}
+
 	putchar('\n');
 }
 
@@ -775,8 +835,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);


More information about the svn-src-all mailing list