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
This commit is contained in:
Bruce M Simpson 2009-02-15 15:19:34 +00:00
parent d1ec640bcf
commit d508ff40b9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=188645
2 changed files with 188 additions and 82 deletions

View File

@ -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.

View File

@ -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. */