From owner-svn-src-head@FreeBSD.ORG Sun Feb 15 15:19:35 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 21B761065674; Sun, 15 Feb 2009 15:19:35 +0000 (UTC) (envelope-from bms@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0E4348FC19; Sun, 15 Feb 2009 15:19:35 +0000 (UTC) (envelope-from bms@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n1FFJYCk081895; Sun, 15 Feb 2009 15:19:34 GMT (envelope-from bms@svn.freebsd.org) Received: (from bms@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n1FFJYlW081893; Sun, 15 Feb 2009 15:19:34 GMT (envelope-from bms@svn.freebsd.org) Message-Id: <200902151519.n1FFJYlW081893@svn.freebsd.org> From: Bruce M Simpson Date: Sun, 15 Feb 2009 15:19:34 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188645 - head/usr.sbin/ifmcstat X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Feb 2009 15:19:36 -0000 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 ' 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 + * 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. */