svn commit: r188645 - head/usr.sbin/ifmcstat

Bruce M Simpson bms at FreeBSD.org
Sun Feb 15 07:19:36 PST 2009


Author: bms
Date: Sun Feb 15 15:19:34 2009
New Revision: 188645
URL: http://svn.freebsd.org/changeset/base/188645

Log:
  Improve ifmcstat(8) and fix a few bugs while we're at it:
   * Retire the old 'ifmcstat <kernel>' usage.
   * Print AF_LINK records even if run against KVM.
     This makes the KVM backend consistent with the sysctl backend.
   * Suppress printing of link-layer group records by default.
   * Add a -v switch to allow link-layer groups to be printed.
   * If compiled without INET6 support, actually work.
   * If compiled with INET6 support, print the scope ID of
     all IPv6 addresses in both backends.
   * Update man page.
   * Update copyrights.
  
  With this change, it is now reasonable to retire netstat -g.
  Most of the SSM related gunk in this file will require later refactoring.
  
  MFC after:	2 weeks

Modified:
  head/usr.sbin/ifmcstat/ifmcstat.8
  head/usr.sbin/ifmcstat/ifmcstat.c

Modified: head/usr.sbin/ifmcstat/ifmcstat.8
==============================================================================
--- head/usr.sbin/ifmcstat/ifmcstat.8	Sun Feb 15 13:22:21 2009	(r188644)
+++ head/usr.sbin/ifmcstat/ifmcstat.8	Sun Feb 15 15:19:34 2009	(r188645)
@@ -1,5 +1,6 @@
 .\"	$KAME: ifmcstat.8,v 1.6 2002/10/31 04:23:43 suz Exp $
 .\"
+.\" Copyright (c) 2007-2009 Bruce Simpson.
 .\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
 .\" All rights reserved.
 .\"
@@ -29,7 +30,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 30, 2007
+.Dd February 15, 2009
 .Dt IFMCSTAT 8
 .Os
 .Sh NAME
@@ -39,10 +40,9 @@
 .Nm
 .Op Fl i Ar interface
 .Op Fl f Ar address-family
+.Op Fl v
 .Op Fl M Ar core
 .Op Fl N Ar system
-.Nm
-.Op Ar kernel
 .\"
 .Sh DESCRIPTION
 The
@@ -55,17 +55,23 @@ The following options are supported:
 specifies the interface to be displayed.
 .Pp
 .It Fl f Ar address-family
-specifies the address-family to be displayed; currently only
-.Ar inet
-and
+specifies the address family to be displayed;
+.Ar inet ,
 .Ar inet6
+and
+.Ar link
 are supported.
+.It Fl v
+specifies that link-layer memberships should be printed;
+they are suppressed by default.
+It may not be specified for
+.Fl f Ar link .
 .El
 .Pp
 The following options are only available if
 .Nm
 has been built with support for
-.Xr kvm 3 .
+.Xr kvm 3 :
 .Bl -tag -width Fl
 .It Fl M Ar core
 extracts values associated with the name list from the specified core,
@@ -74,24 +80,11 @@ instead of the default
 .It Fl N Ar system
 extracts the name list from the specified kernel instead of the
 default, which is the kernel image the system has booted from.
-.It Nm Ar system
-This is the same as specifying
-.Nm
-.Fl N Ar system .
-This usage is deprecated; it is supported only for backwards compatibility.
 .El
 .Sh IMPLEMENTATION NOTES
-When built without
-.Xr kvm 3
-support, the information displayed by
-.Nm
-is more limited.
-This support is recommended for debugging purposes.
-It requires superuser privilege if used to inspect a running kernel.
-.Pp
-When run without using
-.Xr kvm 3
-support,
+When run with the
+.Fl v
+option,
 .Nm
 may print multicast MAC addresses twice if they are
 referenced by a layer 3 protocol.
@@ -101,16 +94,24 @@ When run with
 support,
 the names of all interfaces configured in the system will be
 printed in the first column of output, even if no multicast
-addresses are configured on those interfaces.
+group memberships are present on those interfaces.
+The output may also be slightly different, as the kernel
+data structures are being traversed with minimal post-processing
+of the output.
+.Pp
+When built without
+.Xr kvm 3
+support, the information displayed by
+.Nm
+is more limited.
+This support is recommended for debugging purposes.
+It requires super-user privilege if used to inspect a running kernel.
+.Xr kvm 3
+will be used by default if
+.Nm
+is run with super-user privileges.
 .Sh SEE ALSO
 .Xr getifaddrs 3 ,
 .Xr getifmaddrs 3 ,
 .Xr kvm 3 ,
 .Xr netstat 8
-.Sh BUGS
-.Nm
-does not support the
-.Ar link
-argument to the
-.Ar address-family
-option.

Modified: head/usr.sbin/ifmcstat/ifmcstat.c
==============================================================================
--- head/usr.sbin/ifmcstat/ifmcstat.c	Sun Feb 15 13:22:21 2009	(r188644)
+++ head/usr.sbin/ifmcstat/ifmcstat.c	Sun Feb 15 15:19:34 2009	(r188645)
@@ -1,7 +1,7 @@
 /*	$KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $	*/
 
 /*
- * Copyright (c) 2007 Bruce M. Simpson <bms at FreeBSD.org>
+ * Copyright (c) 2007-2009 Bruce Simpson.
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
  * 
@@ -111,6 +111,7 @@ typedef union sockunion sockunion_t;
 
 uint32_t	ifindex = 0;
 int		af = AF_UNSPEC;
+int		vflag = 0;
 
 #define	sa_equal(a1, a2)	\
 	(bcmp((a1), (a2), ((a1))->sa_len) == 0)
@@ -144,10 +145,11 @@ static struct in6_multi *
 #ifdef HAVE_MLDV2
 static void		in6_addr_slistentry(struct in6_addr_slist *, char *);
 #endif
-static const char *	inet6_n2a(struct in6_addr *);
 #endif /* INET6 */
 
 static void		kread(u_long, void *, int);
+static void		ll_addrlist(struct ifaddr *);
+
 static int		ifmcstat_kvm(const char *kernel, const char *core);
 
 #define	KREAD(addr, buf, type) \
@@ -163,8 +165,25 @@ struct	nlist nl[] = {
 #endif /* WITH_KVM */
 
 static int		ifmcstat_getifmaddrs(void);
+#ifdef INET6
+static const char *	inet6_n2a(struct in6_addr *);
+#endif
 int			main(int, char **);
 
+static void
+usage()
+{
+
+	fprintf(stderr,
+	    "usage: ifmcstat [-i interface] [-f address family]"
+	    " [-v]"
+#ifdef WITH_KVM
+	    " [-M core] [-N system]"
+#endif
+	    "\n");
+	exit(EX_USAGE);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -172,13 +191,9 @@ main(int argc, char **argv)
 #ifdef WITH_KVM
 	const char *kernel = NULL;
 	const char *core = NULL;
-
-	/* "ifmcstat [kernel]" format is supported for backward compatiblity */
-	if (argc == 2)
-		kernel = argv[1];
 #endif
 
-	while ((c = getopt(argc, argv, "i:f:M:N:")) != -1) {
+	while ((c = getopt(argc, argv, "i:f:vM:N:")) != -1) {
 		switch (c) {
 		case 'i':
 			if ((ifindex = if_nametoindex(optarg)) == 0) {
@@ -201,11 +216,19 @@ main(int argc, char **argv)
 				break;
 			}
 #endif
+			if (strcmp(optarg, "link") == 0) {
+				af = AF_LINK;
+				break;
+			}
 			fprintf(stderr, "%s: unknown address family\n", optarg);
 			exit(1);
 			/*NOTREACHED*/
 			break;
 
+		case 'v':
+			vflag = 1;
+			break;
+
 #ifdef WITH_KVM
 		case 'M':
 			core = strdup(optarg);
@@ -217,18 +240,15 @@ main(int argc, char **argv)
 #endif
 
 		default:
-			fprintf(stderr,
-			    "usage: ifmcstat [-i interface] [-f address family]"
-#ifdef WITH_KVM
-			    " [-M core] [-N system]"
-#endif
-			    "\n");
-			exit(1);
+			usage();
 			break;
 			/*NOTREACHED*/
 		}
 	}
 
+	if (af == AF_LINK && vflag)
+		usage();
+
 #ifdef WITH_KVM
 	error = ifmcstat_kvm(kernel, core);
 	/*
@@ -280,6 +300,8 @@ ifmcstat_kvm(const char *kernel, const c
 #ifdef INET6
 		if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
 #endif
+		if (vflag)
+			ll_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
 next:
 		ifp = nifp;
 	}
@@ -297,36 +319,67 @@ kread(u_long addr, void *buf, int len)
 	}
 }
 
-#ifdef INET6
-
-static const char *
-inet6_n2a(struct in6_addr *p)
+static void
+ll_addrlist(struct ifaddr *ifap)
 {
-	static char buf[NI_MAXHOST];
-	struct sockaddr_in6 sin6;
-	u_int32_t scopeid;
-	const int niflags = NI_NUMERICHOST;
+	char addrbuf[NI_MAXHOST];
+	struct ifaddr ifa;
+	struct sockaddr sa;
+	struct sockaddr_dl sdl;
+	struct ifaddr *ifap0;
+	int error;
 
-	memset(&sin6, 0, sizeof(sin6));
-	sin6.sin6_family = AF_INET6;
-	sin6.sin6_len = sizeof(struct sockaddr_in6);
-	sin6.sin6_addr = *p;
-	if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
-	    IN6_IS_ADDR_MC_NODELOCAL(p)) {
-		scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
-		if (scopeid) {
-			sin6.sin6_scope_id = scopeid;
-			sin6.sin6_addr.s6_addr[2] = 0;
-			sin6.sin6_addr.s6_addr[3] = 0;
+	if (af && af != AF_LINK)
+		return;
+
+	ifap0 = ifap;
+	while (ifap) {
+		KREAD(ifap, &ifa, struct ifaddr);
+		if (ifa.ifa_addr == NULL)
+			goto nextifap;
+		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
+		if (sa.sa_family != PF_LINK)
+			goto nextifap;
+		KREAD(ifa.ifa_addr, &sdl, struct sockaddr_dl);
+		if (sdl.sdl_alen == 0)
+			goto nextifap;
+		addrbuf[0] = '\0';
+		error = getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len,
+		    addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
+		printf("\tlink %s\n", addrbuf);
+	nextifap:
+		ifap = ifa.ifa_link.tqe_next;
+	}
+	if (ifap0) {
+		struct ifnet ifnet;
+		struct ifmultiaddr ifm, *ifmp = 0;
+
+		KREAD(ifap0, &ifa, struct ifaddr);
+		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
+		if (TAILQ_FIRST(&ifnet.if_multiaddrs))
+			ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
+		while (ifmp) {
+			KREAD(ifmp, &ifm, struct ifmultiaddr);
+			if (ifm.ifma_addr == NULL)
+				goto nextmulti;
+			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
+			if (sa.sa_family != AF_LINK)
+				goto nextmulti;
+			KREAD(ifm.ifma_addr, &sdl, struct sockaddr_dl);
+			addrbuf[0] = '\0';
+			error = getnameinfo((struct sockaddr *)&sdl,
+			    sdl.sdl_len, addrbuf, sizeof(addrbuf),
+			    NULL, 0, NI_NUMERICHOST);
+			printf("\t\tgroup %s refcnt %d\n",
+			    addrbuf, ifm.ifma_refcount);
+		nextmulti:
+			ifmp = TAILQ_NEXT(&ifm, ifma_link);
 		}
 	}
-	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
-			buf, sizeof(buf), NULL, 0, niflags) == 0)
-		return buf;
-	else
-		return "(invalid)";
 }
 
+#ifdef INET6
+
 static void
 if6_addrlist(struct ifaddr *ifap)
 {
@@ -619,11 +672,41 @@ in_addr_slistentry(struct in_addr_slist 
 
 #endif /* WITH_KVM */
 
+#ifdef INET6
+static const char *
+inet6_n2a(struct in6_addr *p)
+{
+	static char buf[NI_MAXHOST];
+	struct sockaddr_in6 sin6;
+	u_int32_t scopeid;
+	const int niflags = NI_NUMERICHOST;
+
+	memset(&sin6, 0, sizeof(sin6));
+	sin6.sin6_family = AF_INET6;
+	sin6.sin6_len = sizeof(struct sockaddr_in6);
+	sin6.sin6_addr = *p;
+	if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
+	    IN6_IS_ADDR_MC_NODELOCAL(p)) {
+		scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+		if (scopeid) {
+			sin6.sin6_scope_id = scopeid;
+			sin6.sin6_addr.s6_addr[2] = 0;
+			sin6.sin6_addr.s6_addr[3] = 0;
+		}
+	}
+	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+			buf, sizeof(buf), NULL, 0, niflags) == 0)
+		return buf;
+	else
+		return "(invalid)";
+}
+#endif /* INET6 */
+
 static int
 ifmcstat_getifmaddrs(void)
 {
 	char			 thisifname[IFNAMSIZ];
-	char			 addrbuf[INET6_ADDRSTRLEN];
+	char			 addrbuf[NI_MAXHOST];
 	struct ifaddrs		*ifap, *ifa;
 	struct ifmaddrs		*ifmap, *ifma;
 	sockunion_t		 lastifasa;
@@ -698,25 +781,28 @@ ifmcstat_getifmaddrs(void)
 			    (ifa->ifa_addr == NULL) ||
 			    (ifa->ifa_addr->sa_family != pgsa->sa.sa_family))
 				continue;
-#ifdef INET6
 			/*
 			 * For AF_INET6 only the link-local address should
-			 * be returned.
-			 * XXX: ifmcstat actually prints all of the inet6
-			 * addresses, but never mind...
+			 * be returned. If built without IPv6 support,
+			 * skip this address entirely.
 			 */
 			pifasa = (sockunion_t *)ifa->ifa_addr;
-			if (pifasa->sa.sa_family == AF_INET6 &&
-			    !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)) {
+			if (pifasa->sa.sa_family == AF_INET6
+#ifdef INET6
+			    && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)
+#endif
+			) {
 				pifasa = NULL;
 				continue;
 			}
-#endif
 			break;
 		}
 		if (pifasa == NULL)
 			continue;	/* primary address not found */
 
+		if (!vflag && pifasa->sa.sa_family == AF_LINK)
+			continue;
+
 		/* Parse and print primary address, if not already printed. */
 		if (lastifasa.ss.ss_family == AF_UNSPEC ||
 		    ((lastifasa.ss.ss_family == AF_LINK &&
@@ -739,8 +825,18 @@ ifmcstat_getifmaddrs(void)
 			}
 
 			switch (pifasa->sa.sa_family) {
-			case AF_INET:
 			case AF_INET6:
+#ifdef INET6
+			{
+				const char *p =
+				    inet6_n2a(&pifasa->sin6.sin6_addr);
+				strlcpy(addrbuf, p, sizeof(addrbuf));
+				break;
+			}
+#else
+			/* FALLTHROUGH */
+#endif
+			case AF_INET:
 			case AF_LINK:
 				error = getnameinfo(&pifasa->sa,
 				    pifasa->sa.sa_len,
@@ -759,10 +855,19 @@ ifmcstat_getifmaddrs(void)
 		}
 
 		/* Print this group address. */
-		error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len, addrbuf,
-		    sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
-		if (error)
-			perror("getnameinfo");
+#ifdef INET6
+		if (pgsa->sa.sa_family == AF_INET6) {
+			const char *p = inet6_n2a(&pgsa->sin6.sin6_addr);
+			strlcpy(addrbuf, p, sizeof(addrbuf));
+		} else
+#endif
+		{
+			error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len,
+			    addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
+			if (error)
+				perror("getnameinfo");
+		}
+
 		fprintf(stdout, "\t\tgroup %s\n", addrbuf);
 
 		/* Link-layer mapping, if present. */


More information about the svn-src-head mailing list