Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Dec 2013 18:30:01 GMT
From:      dfilter@FreeBSD.ORG (dfilter service)
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/167204: commit references a PR
Message-ID:  <201312181830.rBIIU1fr015675@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/167204; it has been noted by GNATS.

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/167204: commit references a PR
Date: Wed, 18 Dec 2013 18:25:34 +0000 (UTC)

 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);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 



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