diff options
author | bms <bms@FreeBSD.org> | 2009-04-29 19:19:13 +0000 |
---|---|---|
committer | bms <bms@FreeBSD.org> | 2009-04-29 19:19:13 +0000 |
commit | 32a71137f08bc028578417de36a241d7e6011f58 (patch) | |
tree | 51d9a006ee48417962ce45f044b7e5603910fe13 /usr.sbin/ifmcstat | |
parent | 51a4d1c4a3d279a3638c0b40f351aa93f965c7df (diff) | |
download | FreeBSD-src-32a71137f08bc028578417de36a241d7e6011f58.zip FreeBSD-src-32a71137f08bc028578417de36a241d7e6011f58.tar.gz |
Bite the bullet, and make the IPv6 SSM and MLDv2 mega-commit:
import from p4 bms_netdev. Summary of changes:
* Connect netinet6/in6_mcast.c to build.
The legacy KAME KPIs are mostly preserved.
* Eliminate now dead code from ip6_output.c.
Don't do mbuf bingo, we are not going to do RFC 2292 style
CMSG tricks for multicast options as they are not required
by any current IPv6 normative reference.
* Refactor transports (UDP, raw_ip6) to do own mcast filtering.
SCTP, TCP unaffected by this change.
* Add ip6_msource, in6_msource structs to in6_var.h.
* Hookup mld_ifinfo state to in6_ifextra, allocate from
domifattach path.
* Eliminate IN6_LOOKUP_MULTI(), it is no longer referenced.
Kernel consumers which need this should use in6m_lookup().
* Refactor IPv6 socket group memberships to use a vector (like IPv4).
* Update ifmcstat(8) for IPv6 SSM.
* Add witness lock order for IN6_MULTI_LOCK.
* Move IN6_MULTI_LOCK out of lower ip6_output()/ip6_input() paths.
* Introduce IP6STAT_ADD/SUB/INC/DEC as per rwatson's IPv4 cleanup.
* Update carp(4) for new IPv6 SSM KPIs.
* Virtualize ip6_mrouter socket.
Changes mostly localized to IPv6 MROUTING.
* Don't do a local group lookup in MROUTING.
* Kill unused KAME prototypes in6_purgemkludge(), in6_restoremkludge().
* Preserve KAME DAD timer jitter behaviour in MLDv1 compatibility mode.
* Bump __FreeBSD_version to 800084.
* Update UPDATING.
NOTE WELL:
* This code hasn't been tested against real MLDv2 queriers
(yet), although the on-wire protocol has been verified in Wireshark.
* There are a few unresolved issues in the socket layer APIs to
do with scope ID propagation.
* There is a LOR present in ip6_output()'s use of
in6_setscope() which needs to be resolved. See comments in mld6.c.
This is believed to be benign and can't be avoided for the moment
without re-introducing an indirect netisr.
This work was mostly derived from the IGMPv3 implementation, and
has been sponsored by a third party.
Diffstat (limited to 'usr.sbin/ifmcstat')
-rw-r--r-- | usr.sbin/ifmcstat/ifmcstat.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c index 34068ea..0aea6fd 100644 --- a/usr.sbin/ifmcstat/ifmcstat.c +++ b/usr.sbin/ifmcstat/ifmcstat.c @@ -167,6 +167,7 @@ static void in_ifinfo(struct igmp_ifinfo *); static const char * inm_mode(u_int mode); #endif #ifdef INET6 +static void in6_ifinfo(struct mld_ifinfo *); static const char * inet6_n2a(struct in6_addr *); #endif int main(int, char **); @@ -441,8 +442,35 @@ ll_addrlist(struct ifaddr *ifap) #ifdef INET6 static void +in6_ifinfo(struct mld_ifinfo *mli) +{ + + printf("\t"); + switch (mli->mli_version) { + case MLD_VERSION_1: + case MLD_VERSION_2: + printf("mldv%d", mli->mli_version); + break; + default: + printf("mldv?(%d)", mli->mli_version); + break; + } + printb(" flags", mli->mli_flags, "\020\1SILENT"); + if (mli->mli_version == MLD_VERSION_2) { + printf(" rv %u qi %u qri %u uri %u", + mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri); + } + if (vflag >= 2) { + printf(" v1timer %u v2timer %u", mli->mli_v1_timer, + mli->mli_v2_timer); + } + printf("\n"); +} + +static void if6_addrlist(struct ifaddr *ifap) { + struct ifnet ifnet; struct ifaddr ifa; struct sockaddr sa; struct in6_ifaddr if6a; @@ -460,6 +488,21 @@ if6_addrlist(struct ifaddr *ifap) goto nextifap; KREAD(ifap, &if6a, struct in6_ifaddr); printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr)); + /* + * Print per-link MLD information, if available. + */ + if (ifa.ifa_ifp != NULL) { + struct in6_ifextra ie; + struct mld_ifinfo mli; + + KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); + KREAD(ifnet.if_afdata[AF_INET6], &ie, + struct in6_ifextra); + if (ie.mld_ifinfo != NULL) { + KREAD(ie.mld_ifinfo, &mli, struct mld_ifinfo); + in6_ifinfo(&mli); + } + } nextifap: ifap = ifa.ifa_link.tqe_next; } @@ -842,6 +885,110 @@ out_free: #endif /* INET */ +#ifdef INET6 +/* + * Retrieve MLD per-group source filter mode and lists via sysctl. + * + * Note: The 128-bit IPv6 group addres needs to be segmented into + * 32-bit pieces for marshaling to sysctl. So the MIB name ends + * up looking like this: + * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3] + * Assumes that pgroup originated from the kernel, so its components + * are already in network-byte order. + */ +static void +in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup) +{ +#define MAX_SYSCTL_TRY 5 + char addrbuf[INET6_ADDRSTRLEN]; + int mib[10]; + int ntry = 0; + int *pi; + size_t mibsize; + size_t len; + size_t needed; + size_t cnt; + int i; + char *buf; + struct in6_addr *pina; + uint32_t *p; + uint32_t fmode; + const char *modestr; + + mibsize = sizeof(mib) / sizeof(mib[0]); + if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib, + &mibsize) == -1) { + perror("sysctlnametomib"); + return; + } + + needed = 0; + mib[5] = ifindex; + pi = (int *)pgroup; + for (i = 0; i < 4; i++) + mib[6 + i] = *pi++; + + mibsize = sizeof(mib) / sizeof(mib[0]); + do { + if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { + perror("sysctl net.inet6.ip6.mcast.filters"); + return; + } + if ((buf = malloc(needed)) == NULL) { + perror("malloc"); + return; + } + if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + perror("sysctl"); + goto out_free; + } + free(buf); + buf = NULL; + } + } while (buf == NULL); + + len = needed; + if (len < sizeof(uint32_t)) { + perror("sysctl"); + goto out_free; + } + + p = (uint32_t *)buf; + fmode = *p++; + len -= sizeof(uint32_t); + + modestr = inm_mode(fmode); + if (modestr) + printf(" mode %s", modestr); + else + printf(" mode (%u)", fmode); + + if (vflag == 0) + goto out_free; + + cnt = len / sizeof(struct in6_addr); + pina = (struct in6_addr *)p; + + for (i = 0; i < cnt; i++) { + if (i == 0) + printf(" srcs "); + inet_ntop(AF_INET6, (const char *)pina++, addrbuf, + INET6_ADDRSTRLEN); + fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf); + len -= sizeof(struct in6_addr); + } + if (len > 0) { + fprintf(stderr, "warning: %u trailing bytes from %s\n", + (unsigned int)len, "net.inet6.ip6.mcast.filters"); + } + +out_free: + free(buf); +#undef MAX_SYSCTL_TRY +} +#endif /* INET6 */ + static int ifmcstat_getifmaddrs(void) { @@ -1015,6 +1162,33 @@ ifmcstat_getifmaddrs(void) } in_ifinfo(&igi); } +#endif /* INET */ +#ifdef INET6 + /* + * Print per-link MLD information, if available. + */ + if (pifasa->sa.sa_family == AF_INET6) { + struct mld_ifinfo mli; + size_t mibsize, len; + int mib[5]; + + mibsize = sizeof(mib) / sizeof(mib[0]); + if (sysctlnametomib("net.inet6.mld.ifinfo", + mib, &mibsize) == -1) { + perror("sysctlnametomib"); + goto next_ifnet; + } + mib[mibsize] = thisifindex; + len = sizeof(struct mld_ifinfo); + if (sysctl(mib, mibsize + 1, &mli, &len, NULL, + 0) == -1) { + perror("sysctl net.inet6.mld.ifinfo"); + goto next_ifnet; + } + in6_ifinfo(&mli); + } +#endif /* INET6 */ +#if defined(INET) || defined(INET6) next_ifnet: #endif lastifasa = *pifasa; @@ -1041,6 +1215,12 @@ next_ifnet: pgsa->sin.sin_addr); } #endif +#ifdef INET6 + if (pgsa->sa.sa_family == AF_INET6) { + in6m_print_sources_sysctl(thisifindex, + &pgsa->sin6.sin6_addr); + } +#endif fprintf(stdout, "\n"); /* Link-layer mapping, if present. */ |