Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Oct 2013 09:55:08 +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: r256512 - head/usr.bin/netstat
Message-ID:  <201310150955.r9F9t8pq084143@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Tue Oct 15 09:55:07 2013
New Revision: 256512
URL: http://svnweb.freebsd.org/changeset/base/256512

Log:
    Rewrite netstat/if.c to use getifaddrs(3) and getifmaddrs(3) instead of
  libkvm digging in kernel memory. This is possible since r231506 made
  getifaddrs(3) to supply if_data for each ifaddr.
  
    The pros of this change is that now netstat(1) doesn't know about kernel
  struct ifnet and struct ifaddr. And these structs are about to change
  significantly in head soon. New netstat binary will work well with 10.0
  and any future kernel.
  
    The cons is that now it isn't possible to obtain interface statistics
  from a vmcore.
  
    Functions intpr() and sidewaysintpr() were rewritten from scratch.
  
    The output of netstat(1) has underwent the following changes:
  
  1) The MTU is not printed for protocol addresses, since it has no notion.
     Dash is printed instead. If there would be a strong desire to return
     previous output, it is doable.
  2) Output interface queue drops are not printed. Currently this data isn't
     available to userland via any API. We plan to drop 'struct ifqueue' from
     'struct ifnet' very soon, so old kvm(3) access to queue drops is soon
     to be broken, too. The plan is that drivers would handle their queues
     theirselves and a new field in if_data would be updated in case of drops.
  3) In-kernel reference count for multicast addresses isn't printed. I doubt
     that anyone used it. Anyway, netstat(1) is sysadmin tool, not kernel
     debugger.
  
  Sponsored by:	Netflix
  Sponsored by:	Nginx, Inc.

Modified:
  head/usr.bin/netstat/if.c
  head/usr.bin/netstat/main.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	Tue Oct 15 09:29:36 2013	(r256511)
+++ head/usr.bin/netstat/if.c	Tue Oct 15 09:55:07 2013	(r256512)
@@ -58,24 +58,23 @@ __FBSDID("$FreeBSD$");
 
 #include <err.h>
 #include <errno.h>
+#include <ifaddrs.h>
 #include <libutil.h>
 #ifdef INET6
 #include <netdb.h>
 #endif
 #include <signal.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sysexits.h>
 #include <unistd.h>
 
 #include "netstat.h"
 
-#define	YES	1
-#define	NO	0
-
-static void sidewaysintpr(int, u_long);
-static void catchalarm(int);
+static void sidewaysintpr(int);
 
 #ifdef INET6
 static char addr_buf[NI_MAXHOST];		/* for getnameinfo() */
@@ -198,52 +197,40 @@ show_stat(const char *fmt, int width, u_
 }
 
 /*
- * Print a description of the network interfaces.
+ * Find next multiaddr for a given interface name.
  */
-void
-intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *))
+static struct ifmaddrs *
+next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family)
 {
-	struct ifnet ifnet;
-	struct ifnethead ifnethead;
-	union {
-		struct ifaddr ifa;
-		struct in_ifaddr in;
-#ifdef INET6
-		struct in6_ifaddr in6;
-#endif
-		struct ipx_ifaddr ipx;
-	} ifaddr;
-	u_long ifaddraddr;
-	u_long ifaddrfound;
-	u_long opackets;
-	u_long ipackets;
-	u_long obytes;
-	u_long ibytes;
-	u_long omcasts;
-	u_long imcasts;
-	u_long oerrors;
-	u_long ierrors;
-	u_long idrops;
-	u_long collisions;
-	int drops;
-	struct sockaddr *sa = NULL;
-	char name[IFNAMSIZ];
-	short network_layer;
-	short link_layer;
 
-	if (ifnetaddr == 0) {
-		printf("ifnet: symbol not defined\n");
-		return;
-	}
-	if (interval1) {
-		sidewaysintpr(interval1, ifnetaddr);
-		return;
+	for(; ifma != NULL; ifma = ifma->ifma_next) {
+		struct sockaddr_dl *sdl;
+
+		sdl = (struct sockaddr_dl *)ifma->ifma_name;
+		if (ifma->ifma_addr->sa_family == family &&
+		    strcmp(sdl->sdl_data, name) == 0)
+			break;
 	}
-	if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead) != 0)
-		return;
-	ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead);
-	if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) != 0)
-		return;
+
+	return (ifma);
+}
+
+/*
+ * Print a description of the network interfaces.
+ */
+void
+intpr(int interval, void (*pfunc)(char *))
+{
+	struct ifaddrs *ifap, *ifa;
+	struct ifmaddrs *ifmap, *ifma;
+	
+	if (interval)
+		return sidewaysintpr(interval);
+
+	if (getifaddrs(&ifap) != 0)
+		err(EX_OSERR, "getifaddrs");
+	if (aflag && getifmaddrs(&ifmap) != 0)
+		err(EX_OSERR, "getifmaddrs");
 
 	if (!pfunc) {
 		if (Wflag)
@@ -262,364 +249,295 @@ intpr(int interval1, u_long ifnetaddr, v
 			printf(" %s", "Drop");
 		putchar('\n');
 	}
-	ifaddraddr = 0;
-	while (ifnetaddr || ifaddraddr) {
-		struct sockaddr_in *sockin;
-#ifdef INET6
-		struct sockaddr_in6 *sockin6;
-#endif
-		char *cp;
-		int n, m;
 
-		network_layer = 0;
-		link_layer = 0;
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		bool network = false, link = false;
 
-		if (ifaddraddr == 0) {
-			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) != 0)
-				return;
-			strlcpy(name, ifnet.if_xname, sizeof(name));
-			ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link);
-			if (interface != 0 && strcmp(name, interface) != 0)
-				continue;
-			cp = strchr(name, '\0');
+		if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0)
+			continue;
 
-			if (pfunc) {
-				(*pfunc)(name);
-				continue;
-			}
+		if (pfunc) {
+			char *name;
 
-			if ((ifnet.if_flags&IFF_UP) == 0)
-				*cp++ = '*';
-			*cp = '\0';
-			ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead);
-		}
-		ifaddrfound = ifaddraddr;
+			name = ifa->ifa_name;
+			(*pfunc)(name);
 
-		/*
-		 * Get the interface stats.  These may get
-		 * overriden below on a per-interface basis.
-		 */
-		opackets = ifnet.if_opackets;
-		ipackets = ifnet.if_ipackets;
-		obytes = ifnet.if_obytes;
-		ibytes = ifnet.if_ibytes;
-		omcasts = ifnet.if_omcasts;
-		imcasts = ifnet.if_imcasts;
-		oerrors = ifnet.if_oerrors;
-		ierrors = ifnet.if_ierrors;
-		idrops = ifnet.if_iqdrops;
-		collisions = ifnet.if_collisions;
-		drops = ifnet.if_snd.ifq_drops;
-
-		if (ifaddraddr == 0) {
-			if (Wflag)
-				printf("%-7.7s", name);
-			else
-				printf("%-5.5s", name);
-			printf(" %5lu ", ifnet.if_mtu);
-			printf("%-13.13s ", "none");
-			printf("%-17.17s ", "none");
-		} else {
-			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)
-			    != 0) {
-				ifaddraddr = 0;
-				continue;
-			}
-#define	CP(x) ((char *)(x))
-			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
-				CP(&ifaddr);
-			sa = (struct sockaddr *)cp;
-			if (af != AF_UNSPEC && sa->sa_family != af) {
-				ifaddraddr =
-				    (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link);
-				continue;
+			/*
+			 * Skip all ifaddrs belonging to same interface.
+			 */
+			while(ifa->ifa_next != NULL &&
+			    (strcmp(ifa->ifa_next->ifa_name, name) == 0)) {
+				ifa = ifa->ifa_next;
 			}
-			if (Wflag)
-				printf("%-7.7s", name);
-			else
-				printf("%-5.5s", name);
-			printf(" %5lu ", ifnet.if_mtu);
-			switch (sa->sa_family) {
-			case AF_UNSPEC:
-				printf("%-13.13s ", "none");
-				printf("%-15.15s ", "none");
-				break;
-			case AF_INET:
-				sockin = (struct sockaddr_in *)sa;
-#ifdef notdef
-				/* can't use inet_makeaddr because kernel
-				 * keeps nets unshifted.
-				 */
-				in = inet_makeaddr(ifaddr.in.ia_subnet,
-					INADDR_ANY);
-				printf("%-13.13s ", netname(in.s_addr,
-				    ifaddr.in.ia_subnetmask));
-#else
-				printf("%-13.13s ",
-				    netname(htonl(ifaddr.in.ia_subnet),
-				    ifaddr.in.ia_subnetmask));
-#endif
-				printf("%-17.17s ",
-				    routename(sockin->sin_addr.s_addr));
+			continue;
+		}
 
-				network_layer = 1;
-				break;
-#ifdef INET6
-			case AF_INET6:
-				sockin6 = (struct sockaddr_in6 *)sa;
-				in6_fillscopeid(&ifaddr.in6.ia_addr);
-				printf("%-13.13s ",
-				       netname6(&ifaddr.in6.ia_addr,
-						&ifaddr.in6.ia_prefixmask.sin6_addr));
-				in6_fillscopeid(sockin6);
-				getnameinfo(sa, sa->sa_len, addr_buf,
-				    sizeof(addr_buf), 0, 0, NI_NUMERICHOST);
-				printf("%-17.17s ", addr_buf);
+		if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af)
+			continue;
 
-				network_layer = 1;
-				break;
-#endif /*INET6*/
-			case AF_IPX:
-				{
-				struct sockaddr_ipx *sipx =
-					(struct sockaddr_ipx *)sa;
-				u_long net;
-				char netnum[10];
-
-				*(union ipx_net *) &net = sipx->sipx_addr.x_net;
-				sprintf(netnum, "%lx", (u_long)ntohl(net));
-				printf("ipx:%-8s  ", netnum);
-/*				printf("ipx:%-8s ", netname(net, 0L)); */
-				printf("%-17s ",
-				    ipx_phost((struct sockaddr *)sipx));
-				}
+		if (Wflag)
+			printf("%-7.7s", ifa->ifa_name);
+		else
+			printf("%-5.5s", ifa->ifa_name);
 
-				network_layer = 1;
-				break;
+#define IFA_MTU(ifa)	(((struct if_data *)(ifa)->ifa_data)->ifi_mtu)
+		show_stat("lu", 6, IFA_MTU(ifa), IFA_MTU(ifa));
+#undef IFA_MTU
 
-			case AF_APPLETALK:
-				printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
-				printf("%-11.11s  ",atalk_print(sa,0x0b) );
-				break;
-			case AF_LINK:
-				{
-				struct sockaddr_dl *sdl =
-					(struct sockaddr_dl *)sa;
-				char linknum[10];
-				cp = (char *)LLADDR(sdl);
-				n = sdl->sdl_alen;
-				sprintf(linknum, "<Link#%d>", sdl->sdl_index);
-				m = printf("%-13.13s ", linknum);
-				}
-				goto hexprint;
-			default:
-				m = printf("(%d)", sa->sa_family);
-				for (cp = sa->sa_len + (char *)sa;
-					--cp > sa->sa_data && (*cp == 0);) {}
-				n = cp - sa->sa_data + 1;
-				cp = sa->sa_data;
-			hexprint:
-				while ((--n >= 0) && (m < 30))
-					m += printf("%02x%c", *cp++ & 0xff,
-						    n > 0 ? ':' : ' ');
-				m = 32 - m;
-				while (m-- > 0)
-					putchar(' ');
+		switch (ifa->ifa_addr->sa_family) {
+		case AF_UNSPEC:
+			printf("%-13.13s ", "none");
+			printf("%-15.15s ", "none");
+			break;
+		case AF_INET:
+		    {
+			struct sockaddr_in *sin, *mask;
+
+			sin = (struct sockaddr_in *)ifa->ifa_addr;
+			mask = (struct sockaddr_in *)ifa->ifa_netmask;
+			printf("%-13.13s ", netname(sin->sin_addr.s_addr,
+			    mask->sin_addr.s_addr));
+			printf("%-17.17s ",
+			    routename(sin->sin_addr.s_addr));
 
-				link_layer = 1;
-				break;
-			}
+			network = true;
+			break;
+		    }
+#ifdef INET6
+		case AF_INET6:
+		    {
+			struct sockaddr_in6 *sin6, *mask;
+
+			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+			mask = (struct sockaddr_in6 *)ifa->ifa_netmask;
+
+			printf("%-13.13s ", netname6(sin6, &mask->sin6_addr));
+			getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
+			    addr_buf, sizeof(addr_buf), 0, 0, NI_NUMERICHOST);
+			printf("%-17.17s ", addr_buf);
 
-			/*
-			 * Fixup the statistics for interfaces that
-			 * update stats for their network addresses
-			 */
-			if (network_layer) {
-				opackets = ifaddr.in.ia_ifa.if_opackets;
-				ipackets = ifaddr.in.ia_ifa.if_ipackets;
-				obytes = ifaddr.in.ia_ifa.if_obytes;
-				ibytes = ifaddr.in.ia_ifa.if_ibytes;
-			}
+			network = 1;
+			break;
+	            }
+#endif /* INET6 */
+		case AF_IPX:
+		    {
+			struct sockaddr_ipx *sipx;
+			u_long net;
+			char netnum[10];
+
+			sipx = (struct sockaddr_ipx *)ifa->ifa_addr;
+			*(union ipx_net *) &net = sipx->sipx_addr.x_net;
+
+			sprintf(netnum, "%lx", (u_long)ntohl(net));
+			printf("ipx:%-8s  ", netnum);
+			printf("%-17s ", ipx_phost((struct sockaddr *)sipx));
+
+			network = 1;
+			break;
+		    }
+		case AF_APPLETALK:
+			printf("atalk:%-12.12s ",
+			    atalk_print(ifa->ifa_addr, 0x10));
+			printf("%-11.11s  ",
+			    atalk_print(ifa->ifa_addr, 0x0b));
+			break;
+		case AF_LINK:
+		    {
+			struct sockaddr_dl *sdl;
+			char *cp, linknum[10];
+			int n, m;
+
+			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+			cp = (char *)LLADDR(sdl);
+			n = sdl->sdl_alen;
+			sprintf(linknum, "<Link#%d>", sdl->sdl_index);
+			m = printf("%-13.13s ", linknum);
+
+			while ((--n >= 0) && (m < 30))
+				m += printf("%02x%c", *cp++ & 0xff,
+					    n > 0 ? ':' : ' ');
+			m = 32 - m;
+			while (m-- > 0)
+				putchar(' ');
 
-			ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link);
+			link = 1;
+			break;
+		    }
 		}
 
-		show_stat("lu", 8, ipackets, link_layer|network_layer);
-		show_stat("lu", 5, ierrors, link_layer);
-		show_stat("lu", 5, idrops, link_layer);
+#define	IFA_STAT(s)	(((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+		show_stat("lu", 8, IFA_STAT(ipackets), link|network);
+		show_stat("lu", 5, IFA_STAT(ierrors), link);
+		show_stat("lu", 5, IFA_STAT(iqdrops), link);
 		if (bflag)
-			show_stat("lu", 10, ibytes, link_layer|network_layer);
-
-		show_stat("lu", 8, opackets, link_layer|network_layer);
-		show_stat("lu", 5, oerrors, link_layer);
+			show_stat("lu", 10, IFA_STAT(ibytes), link|network);
+		show_stat("lu", 8, IFA_STAT(opackets), link|network);
+		show_stat("lu", 5, IFA_STAT(oerrors), link);
 		if (bflag)
-			show_stat("lu", 10, obytes, link_layer|network_layer);
-
-		show_stat("NRSlu", 5, collisions, link_layer);
-		if (dflag)
-			show_stat("LSd", 4, drops, link_layer);
+			show_stat("lu", 10, IFA_STAT(obytes), link|network);
+		show_stat("NRSlu", 5, IFA_STAT(collisions), link);
+		/* XXXGL: output queue drops */
 		putchar('\n');
 
-		if (aflag && ifaddrfound) {
-			/*
-			 * Print family's multicast addresses
-			 */
-			struct ifmultiaddr *multiaddr;
-			struct ifmultiaddr ifma;
-			union {
-				struct sockaddr sa;
-				struct sockaddr_in in;
-#ifdef INET6
-				struct sockaddr_in6 in6;
-#endif /* INET6 */
-				struct sockaddr_dl dl;
-			} msa;
-			const char *fmt;
-
-			TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) {
-				if (kread((u_long)multiaddr, (char *)&ifma,
-					  sizeof ifma) != 0)
-					break;
-				multiaddr = &ifma;
-				if (kread((u_long)ifma.ifma_addr, (char *)&msa,
-					  sizeof msa) != 0)
-					break;
-				if (msa.sa.sa_family != sa->sa_family)
-					continue;
+		if (!aflag)
+			continue;
 
-				fmt = 0;
-				switch (msa.sa.sa_family) {
-				case AF_INET:
-					fmt = routename(msa.in.sin_addr.s_addr);
-					break;
+		/*
+		 * Print family's multicast addresses.
+		 */
+		for (ifma = next_ifma(ifmap, ifa->ifa_name,
+		     ifa->ifa_addr->sa_family);
+		     ifma != NULL;
+		     ifma = next_ifma(ifma, ifa->ifa_name,
+		     ifa->ifa_addr->sa_family)) {
+			const char *fmt = NULL;
+
+			switch (ifma->ifma_addr->sa_family) {
+			case AF_INET:
+			    {
+				struct sockaddr_in *sin;
+
+				sin = (struct sockaddr_in *)ifma->ifma_addr;
+				fmt = routename(sin->sin_addr.s_addr);
+				break;
+			    }
 #ifdef INET6
-				case AF_INET6:
-					in6_fillscopeid(&msa.in6);
-					getnameinfo(&msa.sa, msa.sa.sa_len,
-					    addr_buf, sizeof(addr_buf), 0, 0,
-					    NI_NUMERICHOST);
-					printf("%*s %-19.19s(refs: %d)\n",
-					       Wflag ? 27 : 25, "",
-					       addr_buf, ifma.ifma_refcount);
-					break;
+			case AF_INET6:
+
+				/* in6_fillscopeid(&msa.in6); */
+				getnameinfo(ifma->ifma_addr,
+				    ifma->ifma_addr->sa_len, addr_buf,
+				    sizeof(addr_buf), 0, 0, NI_NUMERICHOST);
+				printf("%*s %s\n",
+				    Wflag ? 27 : 25, "", addr_buf);
+				break;
 #endif /* INET6 */
-				case AF_LINK:
-					switch (msa.dl.sdl_type) {
-					case IFT_ETHER:
-					case IFT_FDDI:
-						fmt = ether_ntoa(
-							(struct ether_addr *)
-							LLADDR(&msa.dl));
-						break;
-					}
+			case AF_LINK:
+			    {
+				struct sockaddr_dl *sdl;
+
+				sdl = (struct sockaddr_dl *)ifma->ifma_addr;
+				switch (sdl->sdl_type) {
+				case IFT_ETHER:
+				case IFT_FDDI:
+					fmt = ether_ntoa(
+					    (struct ether_addr *)LLADDR(sdl));
 					break;
 				}
-				if (fmt) {
-					printf("%*s %-17.17s",
-					    Wflag ? 27 : 25, "", fmt);
-					if (msa.sa.sa_family == AF_LINK) {
-						printf(" %8lu", imcasts);
-						printf("%*s",
-						    bflag ? 17 : 6, "");
-						printf(" %8lu", omcasts);
-					}
-					putchar('\n');
+				break;
+			    }
+			}
+
+			if (fmt) {
+				printf("%*s %-17.17s",
+				    Wflag ? 27 : 25, "", fmt);
+				if (ifma->ifma_addr->sa_family == AF_LINK) {
+					printf(" %8lu", IFA_STAT(imcasts));
+					printf("%*s", bflag ? 17 : 6, "");
+					printf(" %8lu", IFA_STAT(omcasts));
 				}
+				putchar('\n');
 			}
+
+			ifma = ifma->ifma_next;
 		}
 	}
+
+	freeifaddrs(ifap);
+	if (aflag)
+		freeifmaddrs(ifmap);
 }
 
-struct	iftot {
-	SLIST_ENTRY(iftot) chain;
-	char	ift_name[IFNAMSIZ];	/* interface name */
+struct iftot {
 	u_long	ift_ip;			/* input packets */
 	u_long	ift_ie;			/* input errors */
 	u_long	ift_id;			/* input drops */
 	u_long	ift_op;			/* output packets */
 	u_long	ift_oe;			/* output errors */
 	u_long	ift_co;			/* collisions */
-	u_int	ift_dr;			/* drops */
 	u_long	ift_ib;			/* input bytes */
 	u_long	ift_ob;			/* output bytes */
 };
 
-u_char	signalled;			/* set if alarm goes off "early" */
-
 /*
- * Print a running summary of interface statistics.
- * Repeat display every interval1 seconds, showing statistics
- * collected over that interval.  Assumes that interval1 is non-zero.
- * First line printed at top of screen is always cumulative.
- * XXX - should be rewritten to use ifmib(4).
+ * Obtain stats for interface(s).
  */
 static void
-sidewaysintpr(int interval1, u_long off)
+fill_iftot(struct iftot *st)
 {
-	struct ifnet ifnet;
-	u_long firstifnet;
-	struct ifnethead ifnethead;
-	struct itimerval interval_it;
-	struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting;
-	int line;
-	int oldmask, first;
-	u_long interesting_off;
+	struct ifaddrs *ifap, *ifa;
+	bool found = false;
 
-	if (kread(off, (char *)&ifnethead, sizeof ifnethead) != 0)
-		return;
-	firstifnet = (u_long)TAILQ_FIRST(&ifnethead);
-
-	if ((iftot = malloc(sizeof(struct iftot))) == NULL) {
-		printf("malloc failed\n");
-		exit(1);
-	}
-	memset(iftot, 0, sizeof(struct iftot));
+	if (getifaddrs(&ifap) != 0)
+		err(EX_OSERR, "getifaddrs");
 
-	interesting = NULL;
-	interesting_off = 0;
-	for (off = firstifnet, ip = iftot; off;) {
-		char name[IFNAMSIZ];
+	bzero(st, sizeof(*st));
 
-		if (kread(off, (char *)&ifnet, sizeof ifnet) != 0)
-			break;
-		strlcpy(name, ifnet.if_xname, sizeof(name));
-		if (interface && strcmp(name, interface) == 0) {
-			interesting = ip;
-			interesting_off = off;
-		}
-		snprintf(ip->ift_name, sizeof(ip->ift_name), "(%s)", name);
-		if ((ipn = malloc(sizeof(struct iftot))) == NULL) {
-			printf("malloc failed\n");
-			exit(1);
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr->sa_family != AF_LINK)
+			continue;
+		if (interface) {
+			if (strcmp(ifa->ifa_name, interface) == 0)
+				found = true;
+			else
+				continue;
 		}
-		memset(ipn, 0, sizeof(struct iftot));
-		SLIST_NEXT(ip, chain) = ipn;
-		ip = ipn;
-		off = (u_long)TAILQ_NEXT(&ifnet, if_link);
-	}
-	if (interface && interesting == NULL)
-		errx(1, "%s: unknown interface", interface);
-	if ((total = malloc(sizeof(struct iftot))) == NULL) {
-		printf("malloc failed\n");
-		exit(1);
-	}
-	memset(total, 0, sizeof(struct iftot));
-	if ((sum = malloc(sizeof(struct iftot))) == NULL) {
-		printf("malloc failed\n");
-		exit(1);
+
+		st->ift_ip += IFA_STAT(ipackets);
+		st->ift_ie += IFA_STAT(ierrors);
+		st->ift_id += IFA_STAT(iqdrops);
+		st->ift_ib += IFA_STAT(ibytes);
+		st->ift_op += IFA_STAT(opackets);
+		st->ift_oe += IFA_STAT(oerrors);
+		st->ift_ob += IFA_STAT(obytes);
+ 		st->ift_co += IFA_STAT(collisions);
 	}
-	memset(sum, 0, sizeof(struct iftot));
+
+	if (interface && found == false)
+		err(EX_DATAERR, "interface %s not found", interface);
+
+	freeifaddrs(ifap);
+}
+
+/*
+ * Set a flag to indicate that a signal from the periodic itimer has been
+ * caught.
+ */
+static sig_atomic_t signalled;
+static void
+catchalarm(int signo __unused)
+{
+	signalled = true;
+}
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval.  Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ */
+static void
+sidewaysintpr(int interval)
+{
+	struct iftot ift[2], *new, *old;
+	struct itimerval interval_it;
+	int oldmask, line;
+
+	new = &ift[0];
+	old = &ift[1];
+	fill_iftot(old);
 
 	(void)signal(SIGALRM, catchalarm);
-	signalled = NO;
-	interval_it.it_interval.tv_sec = interval1;
+	signalled = false;
+	interval_it.it_interval.tv_sec = interval;
 	interval_it.it_interval.tv_usec = 0;
 	interval_it.it_value = interval_it.it_interval;
 	setitimer(ITIMER_REAL, &interval_it, NULL);
-	first = 1;
+
 banner:
 	printf("%17s %14s %16s", "input",
-	    interesting ? interesting->ift_name : "(Total)", "output");
+	    interface != NULL ? interface : "(Total)", "output");
 	putchar('\n');
 	printf("%10s %5s %5s %10s %10s %5s %10s %5s",
 	    "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes",
@@ -629,104 +547,43 @@ banner:
 	putchar('\n');
 	fflush(stdout);
 	line = 0;
+
 loop:
-	if (interesting != NULL) {
-		ip = interesting;
-		if (kread(interesting_off, (char *)&ifnet, sizeof ifnet) != 0) {
-			printf("???\n");
-			exit(1);
-		};
-		if (!first) {
-			show_stat("lu", 10, ifnet.if_ipackets - ip->ift_ip, 1);
-			show_stat("lu", 5, ifnet.if_ierrors - ip->ift_ie, 1);
-			show_stat("lu", 5, ifnet.if_iqdrops - ip->ift_id, 1);
-			show_stat("lu", 10, ifnet.if_ibytes - ip->ift_ib, 1);
-			show_stat("lu", 10, ifnet.if_opackets - ip->ift_op, 1);
-			show_stat("lu", 5, ifnet.if_oerrors - ip->ift_oe, 1);
-			show_stat("lu", 10, ifnet.if_obytes - ip->ift_ob, 1);
-			show_stat("NRSlu", 5,
-			    ifnet.if_collisions - ip->ift_co, 1);
-			if (dflag)
-				show_stat("LSu", 5,
-				    ifnet.if_snd.ifq_drops - ip->ift_dr, 1);
-		}
-		ip->ift_ip = ifnet.if_ipackets;
-		ip->ift_ie = ifnet.if_ierrors;
-		ip->ift_id = ifnet.if_iqdrops;
-		ip->ift_ib = ifnet.if_ibytes;
-		ip->ift_op = ifnet.if_opackets;
-		ip->ift_oe = ifnet.if_oerrors;
-		ip->ift_ob = ifnet.if_obytes;
-		ip->ift_co = ifnet.if_collisions;
-		ip->ift_dr = ifnet.if_snd.ifq_drops;
-	} else {
-		sum->ift_ip = 0;
-		sum->ift_ie = 0;
-		sum->ift_id = 0;
-		sum->ift_ib = 0;
-		sum->ift_op = 0;
-		sum->ift_oe = 0;
-		sum->ift_ob = 0;
-		sum->ift_co = 0;
-		sum->ift_dr = 0;
-		for (off = firstifnet, ip = iftot;
-		     off && SLIST_NEXT(ip, chain) != NULL;
-		     ip = SLIST_NEXT(ip, chain)) {
-			if (kread(off, (char *)&ifnet, sizeof ifnet) != 0) {
-				off = 0;
-				continue;
-			}
-			sum->ift_ip += ifnet.if_ipackets;
-			sum->ift_ie += ifnet.if_ierrors;
-			sum->ift_id += ifnet.if_iqdrops;
-			sum->ift_ib += ifnet.if_ibytes;
-			sum->ift_op += ifnet.if_opackets;
-			sum->ift_oe += ifnet.if_oerrors;
-			sum->ift_ob += ifnet.if_obytes;
-			sum->ift_co += ifnet.if_collisions;
-			sum->ift_dr += ifnet.if_snd.ifq_drops;
-			off = (u_long)TAILQ_NEXT(&ifnet, if_link);
-		}
-		if (!first) {
-			show_stat("lu", 10, sum->ift_ip - total->ift_ip, 1);
-			show_stat("lu", 5, sum->ift_ie - total->ift_ie, 1);
-			show_stat("lu", 5, sum->ift_id - total->ift_id, 1);
-			show_stat("lu", 10, sum->ift_ib - total->ift_ib, 1);
-			show_stat("lu", 10, sum->ift_op - total->ift_op, 1);
-			show_stat("lu", 5, sum->ift_oe - total->ift_oe, 1);
-			show_stat("lu", 10, sum->ift_ob - total->ift_ob, 1);
-			show_stat("NRSlu", 5, sum->ift_co - total->ift_co, 1);
-			if (dflag)
-				show_stat("LSu", 5,
-				    sum->ift_dr - total->ift_dr, 1);
-		}
-		*total = *sum;
-	}
-	if (!first)
-		putchar('\n');
-	fflush(stdout);
 	if ((noutputs != 0) && (--noutputs == 0))
 		exit(0);
 	oldmask = sigblock(sigmask(SIGALRM));
 	while (!signalled)
 		sigpause(0);
-	signalled = NO;
+	signalled = false;
 	sigsetmask(oldmask);
 	line++;
-	first = 0;
+
+	fill_iftot(new);
+
+	show_stat("lu", 10, new->ift_ip - old->ift_ip, 1);
+	show_stat("lu", 5, new->ift_ie - old->ift_ie, 1);
+	show_stat("lu", 5, new->ift_id - old->ift_id, 1);
+	show_stat("lu", 10, new->ift_ib - old->ift_ib, 1);
+	show_stat("lu", 10, new->ift_op - old->ift_op, 1);
+	show_stat("lu", 5, new->ift_oe - old->ift_oe, 1);
+	show_stat("lu", 10, new->ift_ob - old->ift_ob, 1);
+	show_stat("NRSlu", 5, new->ift_co - old->ift_co, 1);
+	/* XXXGL: output queue drops */
+	putchar('\n');
+	fflush(stdout);
+
+	if (new == &ift[0]) {
+		new = &ift[1];
+		old = &ift[0];
+	} else {
+		new = &ift[0];
+		old = &ift[1];
+	}
+
 	if (line == 21)
 		goto banner;
 	else
 		goto loop;
-	/*NOTREACHED*/
-}
 
-/*
- * Set a flag to indicate that a signal from the periodic itimer has been
- * caught.
- */
-static void
-catchalarm(int signo __unused)
-{
-	signalled = YES;
+	/* NOTREACHED */
 }

Modified: head/usr.bin/netstat/main.c
==============================================================================
--- head/usr.bin/netstat/main.c	Tue Oct 15 09:29:36 2013	(r256511)
+++ head/usr.bin/netstat/main.c	Tue Oct 15 09:55:07 2013	(r256512)
@@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
 
 static struct nlist nl[] = {
 #define	N_IFNET		0
-	{ .n_name = "_ifnet" },
+	{ .n_name = "_ifnet" },		/* XXXGL: can be deleted */
 #define	N_RTSTAT	1
 	{ .n_name = "_rtstat" },
 #define	N_RTREE		2
@@ -552,7 +552,7 @@ main(int argc, char *argv[])
 #endif
 	kread(0, NULL, 0);
 	if (iflag && !sflag) {
-		intpr(interval, nl[N_IFNET].n_value, NULL);
+		intpr(interval, NULL);
 		exit(0);
 	}
 	if (rflag) {
@@ -636,8 +636,7 @@ printproto(struct protox *tp, const char
 	if (sflag) {
 		if (iflag) {
 			if (tp->pr_istats)
-				intpr(interval, nl[N_IFNET].n_value,
-				      tp->pr_istats);
+				intpr(interval, tp->pr_istats);
 			else if (pflag)
 				printf("%s: no per-interface stats routine\n",
 				    tp->pr_name);

Modified: head/usr.bin/netstat/netstat.h
==============================================================================
--- head/usr.bin/netstat/netstat.h	Tue Oct 15 09:29:36 2013	(r256511)
+++ head/usr.bin/netstat/netstat.h	Tue Oct 15 09:55:07 2013	(r256512)
@@ -119,7 +119,7 @@ void	netisr_stats(void *);
 void	hostpr(u_long, u_long);
 void	impstats(u_long, u_long);
 
-void	intpr(int, u_long, void (*)(char *));
+void	intpr(int, void (*)(char *));
 
 void	pr_rthdr(int);
 void	pr_family(int);
@@ -130,7 +130,7 @@ char	*ns_phost(struct sockaddr *);
 void	upHex(char *);
 
 char	*routename(in_addr_t);
-char	*netname(in_addr_t, u_long);
+char	*netname(in_addr_t, in_addr_t);
 char	*atalk_print(struct sockaddr *, int);
 char	*atalk_print2(struct sockaddr *, struct sockaddr *, int);
 char	*ipx_print(struct sockaddr *);

Modified: head/usr.bin/netstat/route.c
==============================================================================
--- head/usr.bin/netstat/route.c	Tue Oct 15 09:29:36 2013	(r256511)
+++ head/usr.bin/netstat/route.c	Tue Oct 15 09:55:07 2013	(r256512)
@@ -631,10 +631,9 @@ fmt_sockaddr(struct sockaddr *sa, struct
 			cp = routename(sockin->sin_addr.s_addr);
 		else if (mask)
 			cp = netname(sockin->sin_addr.s_addr,
-				     ntohl(((struct sockaddr_in *)mask)
-					   ->sin_addr.s_addr));
+			    ((struct sockaddr_in *)mask)->sin_addr.s_addr);
 		else
-			cp = netname(sockin->sin_addr.s_addr, 0L);
+			cp = netname(sockin->sin_addr.s_addr, INADDR_ANY);
 		break;
 	    }
 
@@ -870,19 +869,21 @@ domask(char *dst, in_addr_t addr __unuse
 
 /*
  * Return the name of the network whose address is given.
- * The address is assumed to be that of a net or subnet, not a host.
  */
 char *
-netname(in_addr_t in, u_long mask)
+netname(in_addr_t in, in_addr_t mask)
 {
 	char *cp = 0;
 	static char line[MAXHOSTNAMELEN];
 	struct netent *np = 0;
 	in_addr_t i;
 
+	/* It is ok to supply host address. */
+	in &= mask;
+
 	i = ntohl(in);
 	if (!numeric_addr && i) {
-		np = getnetbyaddr(i >> NSHIFT(mask), AF_INET);
+		np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET);
 		if (np != NULL) {
 			cp = np->n_name;
 			trimdomain(cp, strlen(cp));
@@ -893,7 +894,7 @@ netname(in_addr_t in, u_long mask)
 	} else {
 		inet_ntop(AF_INET, &in, line, sizeof(line) - 1);
 	}
-	domask(line + strlen(line), i, mask);
+	domask(line + strlen(line), i, ntohl(mask));
 	return (line);
 }
 



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