aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/ifmcstat
diff options
context:
space:
mode:
authorBruce M Simpson <bms@FreeBSD.org>2009-02-15 15:19:34 +0000
committerBruce M Simpson <bms@FreeBSD.org>2009-02-15 15:19:34 +0000
commitd508ff40b9b790616790b0311302d5730e458529 (patch)
tree776963ca1caa91a58a49da983cd5e2afed8f06c8 /usr.sbin/ifmcstat
parentd1ec640bcf8be0c86c77d86f8fb69a5279ff515c (diff)
downloadsrc-d508ff40b9b790616790b0311302d5730e458529.tar.gz
src-d508ff40b9b790616790b0311302d5730e458529.zip
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
Notes
Notes: svn path=/head/; revision=188645
Diffstat (limited to 'usr.sbin/ifmcstat')
-rw-r--r--usr.sbin/ifmcstat/ifmcstat.863
-rw-r--r--usr.sbin/ifmcstat/ifmcstat.c207
2 files changed, 188 insertions, 82 deletions
diff --git a/usr.sbin/ifmcstat/ifmcstat.8 b/usr.sbin/ifmcstat/ifmcstat.8
index 9648c4f404bd..78eb39cc04c0 100644
--- a/usr.sbin/ifmcstat/ifmcstat.8
+++ b/usr.sbin/ifmcstat/ifmcstat.8
@@ -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.
diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c
index 0a2eb7e9815a..47428f2fc674 100644
--- a/usr.sbin/ifmcstat/ifmcstat.c
+++ b/usr.sbin/ifmcstat/ifmcstat.c
@@ -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@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 char *core)
#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 *ias, char *heading)
#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. */