tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Remove kvm(3) dependency of ifmcstat(8)



Hi all,
please test the attached patch on systems with IPv6 multicast,
especially, if you can trigger the creation of "kludge" entries.
There is one small functional difference -- the new code doesn't show
IPv6 addresses *without* associated multicast group.

For now, the backing sysctls do not require privileges. That can be seen
if someone makes a good point for it.

Joerg
Index: sys/net/if.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/net/if.c,v
retrieving revision 1.275
diff -u -p -r1.275 if.c
--- sys/net/if.c        18 May 2014 14:46:16 -0000      1.275
+++ sys/net/if.c        31 May 2014 19:22:27 -0000
@@ -2383,3 +2383,44 @@ sysctl_net_ifq_setup(struct sysctllog **
                       CTL_NET, pf, ipn, qid, IFQCTL_DROPS, CTL_EOL);
 }
 #endif /* INET || INET6 */
+
+static int
+if_sdl_sysctl(SYSCTLFN_ARGS)
+{
+       struct ifnet *ifp;
+       const struct sockaddr_dl *sdl;
+
+       if (namelen != 1)
+               return EINVAL;
+
+       ifp = if_byindex(name[0]);
+       if (ifp == NULL)
+               return ENODEV;
+
+       sdl = ifp->if_sadl;
+       if (sdl == NULL) {
+               *oldlenp = 0;
+               return 0;
+       }
+
+       if (oldp == NULL) {
+               *oldlenp = sdl->sdl_alen;
+               return 0;
+       }
+
+       if (*oldlenp >= sdl->sdl_alen)
+               *oldlenp = sdl->sdl_alen;
+       return sysctl_copyout(l, &sdl->sdl_data[sdl->sdl_nlen], oldp, *oldlenp);
+}
+
+SYSCTL_SETUP(sysctl_net_sdl_setup, "sysctl net.sdl subtree setup")
+{
+       const struct sysctlnode *rnode = NULL;
+
+       sysctl_createv(clog, 0, NULL, &rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "sdl",
+                      SYSCTL_DESCR("Get active link-layer address"),
+                      if_sdl_sysctl, 0, NULL, 0,
+                      CTL_NET, CTL_CREATE, CTL_EOL);
+}
Index: sys/net/if_ether.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/net/if_ether.h,v
retrieving revision 1.62
diff -u -p -r1.62 if_ether.h
--- sys/net/if_ether.h  23 Apr 2014 23:17:22 -0000      1.62
+++ sys/net/if_ether.h  31 May 2014 01:06:33 -0000
@@ -228,6 +228,12 @@ struct ether_multi {
        LIST_ENTRY(ether_multi) enm_list;
 };
 
+struct ether_multi_sysctl {
+       u_int   enm_refcount;
+       uint8_t enm_addrlo[ETHER_ADDR_LEN];
+       uint8_t enm_addrhi[ETHER_ADDR_LEN];
+};
+
 /*
  * Structure used by macros below to remember position when stepping through
  * all of the ether_multi records.
Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/net/if_ethersubr.c,v
retrieving revision 1.198
diff -u -p -r1.198 if_ethersubr.c
--- sys/net/if_ethersubr.c      15 May 2014 07:35:38 -0000      1.198
+++ sys/net/if_ethersubr.c      31 May 2014 19:12:24 -0000
@@ -78,6 +78,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_ethersubr
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/sysctl.h>
 #include <sys/kernel.h>
 #include <sys/callout.h>
 #include <sys/malloc.h>
@@ -1477,3 +1478,70 @@ ether_ioctl(struct ifnet *ifp, u_long cm
        }
        return 0;
 }
+
+static int
+ether_multicast_sysctl(SYSCTLFN_ARGS)
+{
+       struct ether_multi *enm;
+       struct ether_multi_sysctl addr;
+       struct ifnet *ifp;
+       struct ethercom *ec;
+       int error;
+       size_t written;
+
+       if (namelen != 1)
+               return EINVAL;
+
+       ifp = if_byindex(name[0]);
+       if (ifp == NULL)
+               return ENODEV;
+       if (ifp->if_type != IFT_ETHER) {
+               *oldlenp = 0;
+               return 0;
+       }
+       ec = (struct ethercom *)ifp;
+
+       if (oldp == NULL) {
+               *oldlenp = ec->ec_multicnt * sizeof(addr);
+               return 0;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       error = 0;
+       written = 0;
+
+       LIST_FOREACH(enm, &ec->ec_multiaddrs, enm_list) {
+               if (written + sizeof(addr) > *oldlenp)
+                       break;
+               addr.enm_refcount = enm->enm_refcount;
+               memcpy(addr.enm_addrlo, enm->enm_addrlo, ETHER_ADDR_LEN);
+               memcpy(addr.enm_addrhi, enm->enm_addrhi, ETHER_ADDR_LEN);
+               error = sysctl_copyout(l, &addr, oldp, sizeof(addr));
+               if (error)
+                       break;
+               written += sizeof(addr);
+               oldp = (char *)oldp + sizeof(addr);
+       }
+
+       *oldlenp = written;
+       return error;
+}
+
+SYSCTL_SETUP(sysctl_net_ether_setup, "sysctl net.ether subtree setup")
+{
+       const struct sysctlnode *rnode = NULL;
+
+       sysctl_createv(clog, 0, NULL, &rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "ether",
+                      SYSCTL_DESCR("Ethernet-specific information"),
+                      NULL, 0, NULL, 0,
+                      CTL_NET, CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "multicast",
+                      SYSCTL_DESCR("multicast addresses"),
+                      ether_multicast_sysctl, 0, NULL, 0,
+                      CTL_CREATE, CTL_EOL);
+}
Index: sys/netinet6/mld6.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/netinet6/mld6.c,v
retrieving revision 1.56
diff -u -p -r1.56 mld6.c
--- sys/netinet6/mld6.c 2 Jun 2014 11:02:20 -0000       1.56
+++ sys/netinet6/mld6.c 2 Jun 2014 12:58:06 -0000
@@ -897,3 +897,146 @@ in6_purgemkludge(struct ifnet *ifp)
        LIST_REMOVE(mk, mk_entry);
        free(mk, M_IPMADDR);
 }
+
+static int
+in6_mkludge_sysctl(SYSCTLFN_ARGS)
+{
+       struct multi6_kludge *mk;
+       struct in6_multi *in6m;
+       int error;
+       uint32_t tmp;
+       size_t written;
+
+       if (namelen != 1)
+               return EINVAL;
+
+       if (oldp == NULL) {
+               *oldlenp = 0;
+               LIST_FOREACH(mk, &in6_mk, mk_entry) {
+                       if (mk->mk_ifp->if_index == name[0])
+                               continue;
+                       LIST_FOREACH(in6m, &mk->mk_head, in6m_entry) {
+                               *oldlenp += sizeof(struct in6_addr) +
+                                   sizeof(uint32_t);
+                       }
+               }
+               return 0;
+       }
+
+       error = 0;
+       written = 0;
+       LIST_FOREACH(mk, &in6_mk, mk_entry) {
+               if (mk->mk_ifp->if_index == name[0])
+                       continue;
+               LIST_FOREACH(in6m, &mk->mk_head, in6m_entry) {
+                       if (written + sizeof(struct in6_addr) +
+                           sizeof(uint32_t) > *oldlenp)
+                               goto done;
+                       error = sysctl_copyout(l, &in6m->in6m_addr,
+                           oldp, sizeof(struct in6_addr));
+                       if (error)
+                               goto done;
+                       oldp = (char *)oldp + sizeof(struct in6_addr);
+                       written += sizeof(struct in6_addr);
+                       tmp = in6m->in6m_refcount;
+                       error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp));
+                       if (error)
+                               goto done;
+                       oldp = (char *)oldp + sizeof(tmp);
+                       written += sizeof(tmp);
+               }
+       }
+
+done:
+       *oldlenp = written;
+       return error;
+}
+
+static int
+in6_multicast_sysctl(SYSCTLFN_ARGS)
+{
+       struct ifnet *ifp;
+       struct ifaddr *ifa;
+       struct in6_ifaddr *ifa6;
+       struct in6_multi *in6m;
+       uint32_t tmp;
+       int error;
+       size_t written;
+
+       if (namelen != 1)
+               return EINVAL;
+
+       ifp = if_byindex(name[0]);
+       if (ifp == NULL)
+               return ENODEV;
+
+       if (oldp == NULL) {
+               *oldlenp = 0;
+               TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+                       if (ifa->ifa_addr == NULL)
+                               continue;
+                       if (ifa->ifa_addr->sa_family != AF_INET6)
+                               continue;
+                       ifa6 = (struct in6_ifaddr *)ifa;
+                       LIST_FOREACH(in6m, &ifa6->ia6_multiaddrs, in6m_entry) {
+                               *oldlenp += 2 * sizeof(struct in6_addr) +
+                                   sizeof(uint32_t);
+                       }
+               }
+               return 0;
+       }
+
+       error = 0;
+       written = 0;
+       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+               if (ifa->ifa_addr == NULL)
+                       continue;
+               if (ifa->ifa_addr->sa_family != AF_INET6)
+                       continue;
+               ifa6 = (struct in6_ifaddr *)ifa;
+               LIST_FOREACH(in6m, &ifa6->ia6_multiaddrs, in6m_entry) {
+                       if (written + 2 * sizeof(struct in6_addr) +
+                           sizeof(uint32_t) > *oldlenp)
+                               goto done;
+                       error = sysctl_copyout(l, &ifa6->ia_addr.sin6_addr,
+                           oldp, sizeof(struct in6_addr));
+                       if (error)
+                               goto done;
+                       oldp = (char *)oldp + sizeof(struct in6_addr);
+                       written += sizeof(struct in6_addr);
+                       error = sysctl_copyout(l, &in6m->in6m_addr,
+                           oldp, sizeof(struct in6_addr));
+                       if (error)
+                               goto done;
+                       oldp = (char *)oldp + sizeof(struct in6_addr);
+                       written += sizeof(struct in6_addr);
+                       tmp = in6m->in6m_refcount;
+                       error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp));
+                       if (error)
+                               goto done;
+                       oldp = (char *)oldp + sizeof(tmp);
+                       written += sizeof(tmp);
+               }
+       }
+done:
+       *oldlenp = written;
+       return error;
+}
+
+SYSCTL_SETUP(sysctl_in6_mklude_setup, "sysctl net.inet6.multicast_kludge 
subtree setup")
+{
+
+       sysctl_createv(clog, 0, NULL, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "multicast",
+                      SYSCTL_DESCR("Multicast information"),
+                      in6_multicast_sysctl, 0, NULL, 0,
+                      CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, NULL, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "multicast_kludge",
+                      SYSCTL_DESCR("multicast kludge information"),
+                      in6_mkludge_sysctl, 0, NULL, 0,
+                      CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL);
+}
Index: usr.sbin/ifmcstat/Makefile
===================================================================
RCS file: /home/joerg/repo/netbsd/src/usr.sbin/ifmcstat/Makefile,v
retrieving revision 1.3
diff -u -p -r1.3 Makefile
--- usr.sbin/ifmcstat/Makefile  2 Aug 2002 03:58:10 -0000       1.3
+++ usr.sbin/ifmcstat/Makefile  2 Jun 2014 12:13:26 -0000
@@ -4,8 +4,8 @@
 PROG=  ifmcstat
 MAN=   ifmcstat.8
 
-LDADD= -lkvm
-DPADD= ${LIBKVM}
+LDADD+=        -lutil
+DPADD+=        ${LIBUTIL}
 
 CPPFLAGS+=     -DINET6
 
Index: usr.sbin/ifmcstat/ifmcstat.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/usr.sbin/ifmcstat/ifmcstat.c,v
retrieving revision 1.16
diff -u -p -r1.16 ifmcstat.c
--- usr.sbin/ifmcstat/ifmcstat.c        30 May 2014 22:20:48 -0000      1.16
+++ usr.sbin/ifmcstat/ifmcstat.c        2 Jun 2014 14:35:18 -0000
@@ -28,7 +28,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
 
+#include <err.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
@@ -36,9 +40,11 @@
 #include <nlist.h>
 #include <string.h>
 #include <limits.h>
+#include <util.h>
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/sysctl.h>
 #include <net/if.h>
 #include <net/if_types.h>
 #include <net/if_dl.h>
@@ -49,34 +55,12 @@
 
 #include <netdb.h>
 
-kvm_t  *kvmd;
-
-struct nlist nl[] = {
-#define        N_IFNET_LIST    0
-       { "_ifnet_list", 0, 0, 0, 0 },
-#define N_IN6_MK 1
-       { "_in6_mk", 0, 0, 0, 0 },
-       { "", 0, 0, 0, 0 },
-};
-
-static const char *inet6_n2a(struct in6_addr *);
-static char *ifname(struct ifnet *);
-static void kread(u_long, void *, int);
-static void acmc(struct ether_multi *);
-static void if6_addrlist(struct ifaddr *);
-static void in6_multilist(struct in6_multi *);
-
-#define        KREAD(addr, buf, type) \
-       kread((u_long)addr, (void *)buf, sizeof(type))
-
-struct multi6_kludge {
-       LIST_ENTRY(multi6_kludge) mk_entry;
-       struct ifnet *mk_ifp;
-       struct in6_multihead mk_head;
-};
+static const char *inet6_n2a(void *);
+static void print_ether_mcast(u_short);
+static void print_inet6_mcast(u_short, const char *);
 
 static const char *
-inet6_n2a(struct in6_addr *p)
+inet6_n2a(void *p)
 {
        static char buf[NI_MAXHOST];
        struct sockaddr_in6 sin6;
@@ -85,7 +69,7 @@ inet6_n2a(struct in6_addr *p)
        memset(&sin6, 0, sizeof(sin6));
        sin6.sin6_family = AF_INET6;
        sin6.sin6_len = sizeof(struct sockaddr_in6);
-       sin6.sin6_addr = *p;
+       memcpy(&sin6.sin6_addr, p, sizeof(sin6.sin6_addr));
        inet6_getscopeid(&sin6, INET6_IS_ADDR_LINKLOCAL|
            INET6_IS_ADDR_MC_LINKLOCAL);
        if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
@@ -98,149 +82,174 @@ inet6_n2a(struct in6_addr *p)
 int
 main(void)
 {
-       char    buf[_POSIX2_LINE_MAX], ifnam[IFNAMSIZ];
-       struct  ifnet   *ifp, *nifp, ifnet;
-       struct ethercom ec;
-       union {
-               struct sockaddr_storage st;
-               struct sockaddr_dl sdl;
-       } su;
-       struct sockaddr_dl *sdlp;
-       sdlp = &su.sdl;
-
-       if ((kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, buf)) == NULL) {
-               perror("kvm_openfiles");
-               exit(1);
-       }
-       if (kvm_nlist(kvmd, nl) < 0) {
-               perror("kvm_nlist");
-               exit(1);
-       }
-       if (nl[N_IFNET_LIST].n_value == 0) {
-               printf("symbol %s not found\n", nl[N_IFNET_LIST].n_name);
-               exit(1);
-       }
-       KREAD(nl[N_IFNET_LIST].n_value, &ifp, struct ifnet *);
-       while (ifp) {
-               KREAD(ifp, &ifnet, struct ifnet);
-               printf("%s:\n", if_indextoname(ifnet.if_index, ifnam));
-
-               if6_addrlist(ifnet.if_addrlist.tqh_first);
-               nifp = ifnet.if_list.tqe_next;
-
-               KREAD(ifnet.if_sadl, sdlp, struct sockaddr_dl);
-               if (sdlp->sdl_type == IFT_ETHER) {
-                       /* If we didn't get all of it, try again */
-                       if (sdlp->sdl_len > sizeof(struct sockaddr_dl))
-                               kread((u_long)ifnet.if_sadl, (void *)sdlp, 
sdlp->sdl_len);
-                       printf("\tenaddr %s",
-                              ether_ntoa((struct ether_addr *)LLADDR(sdlp)));
-                       KREAD(ifp, &ec, struct ethercom);
-                       printf(" multicnt %d", ec.ec_multicnt);
-                       acmc(ec.ec_multiaddrs.lh_first);
-                       printf("\n");
-               }
+       struct if_nameindex  *ifps;
+       size_t i;
 
-               ifp = nifp;
+
+       ifps = if_nameindex();
+       if (ifps == NULL)
+               errx(1, "failed to obtain list of interfaces");
+       for (i = 0; ifps[i].if_name != NULL; ++i) {
+               printf("%s:\n", ifps[i].if_name);
+               print_inet6_mcast(ifps[i].if_index, ifps[i].if_name);
+               print_ether_mcast(ifps[i].if_index);
        }
+       if_freenameindex(ifps);
 
        exit(0);
        /*NOTREACHED*/
 }
 
-static char *
-ifname(struct ifnet *ifp)
+static void *
+fetch_sysctl(size_t *len, int oids[], size_t oidlen, const char *msg)
 {
-       static char buf[BUFSIZ];
-       struct ifnet ifnet;
+       void *data;
 
-       KREAD(ifp, &ifnet, struct ifnet);
-       strncpy(buf, ifnet.if_xname, BUFSIZ);
-       return buf;
-}
+       *len = 0;
+       data = NULL;
 
-static void
-kread(u_long addr, void *buf, int len)
-{
-       if (kvm_read(kvmd, addr, buf, len) != len) {
-               perror("kvm_read");
-               exit(1);
+       for (;;) {
+               if (sysctl(oids, oidlen, data, len, NULL, 0) == 0) {
+                       if (data != NULL || len == 0)
+                               return data;
+                       errno = ENOMEM;
+               }
+               free(data);
+               if (errno == ENOMEM) {
+                       data = emalloc(*len);
+                       continue;
+               }
+               if (errno != ENODEV)
+                       warn("%s", msg);
+               return NULL;
        }
 }
 
 static void
-acmc(struct ether_multi *am)
+print_hwaddr(const uint8_t *hwaddr, size_t len)
 {
-       struct ether_multi em;
-
-       while (am) {
-               KREAD(am, &em, struct ether_multi);
-               
-               printf("\n\t\t");
-               printf("%s -- ", ether_ntoa((struct ether_addr 
*)em.enm_addrlo));
-               printf("%s ", ether_ntoa((struct ether_addr *)&em.enm_addrhi));
-               printf("%d", em.enm_refcount);
-               am = em.enm_list.le_next;
-       }
+       while (len)
+               printf("%02x%s", *hwaddr++, len-- == 0 ? "" : ":");
 }
 
 static void
-if6_addrlist(struct ifaddr *ifap)
+print_ether_mcast(u_short ifindex)
 {
-       struct ifaddr ifa;
-       struct sockaddr sa;
-       struct in6_ifaddr if6a;
-       struct in6_multi *mc = 0;
-       struct ifaddr *ifap0;
-
-       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_INET6)
-                       goto nextifap;
-               KREAD(ifap, &if6a, struct in6_ifaddr);
-               printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr));
-               mc = mc ? mc : if6a.ia6_multiaddrs.lh_first;
-       nextifap:
-               ifap = ifa.ifa_list.tqe_next;
-       }
-       if (mc)
-               in6_multilist(mc);
-       if (nl[N_IN6_MK].n_value != 0) {
-               LIST_HEAD(in6_mktype, multi6_kludge) in6_mk;
-               struct multi6_kludge *mkp, mk;
-               char *nam;
-
-               KREAD(nl[N_IN6_MK].n_value, &in6_mk, struct in6_mktype);
-               KREAD(ifap0, &ifa, struct ifaddr);
-
-               nam = strdup(ifname(ifa.ifa_ifp));
-
-               for (mkp = in6_mk.lh_first; mkp; mkp = mk.mk_entry.le_next) {
-                       KREAD(mkp, &mk, struct multi6_kludge);
-                       if (strcmp(nam, ifname(mk.mk_ifp)) == 0 &&
-                           mk.mk_head.lh_first) {
-                               printf("\t(on kludge entry for %s)\n", nam);
-                               in6_multilist(mk.mk_head.lh_first);
-                       }
-               }
-
-               free(nam);
+       static int ems_oids[4], sdl_oids[3];
+       size_t i, ems_len, sdl_len;
+       void *hwaddr;
+       struct ether_multi_sysctl *ems;
+
+       if (ems_oids[0] == 0) {
+               size_t oidlen = __arraycount(ems_oids);
+               if (sysctlnametomib("net.ether.multicast", ems_oids, &oidlen) 
== -1)
+                       errx(1, "net.ether.multicast not found");
+               if (oidlen != 3)
+                       errx(1, "Wrong OID path for net.ether.multicast");
+       }
+
+       if (sdl_oids[0] == 0) {
+               size_t oidlen = __arraycount(sdl_oids);
+               if (sysctlnametomib("net.sdl", sdl_oids, &oidlen) == -1)
+                       errx(1, "net.sdl not found");
+               if (oidlen != 2)
+                       errx(1, "Wrong OID path for net.sdl");
+       }
+
+       sdl_oids[2] = ifindex;
+       hwaddr = fetch_sysctl(&sdl_len, sdl_oids, 3, "failed to read net.sdl");
+
+       if (sdl_len == 0) {
+               free(hwaddr);
+               return;
+       }
+
+       ems_oids[3] = ifindex;
+       ems = fetch_sysctl(&ems_len, ems_oids, 4,
+           "failed to read net.ether.multicast");
+       ems_len /= sizeof(*ems);
+
+       printf("\tenaddr ");
+       print_hwaddr(hwaddr, sdl_len);
+       printf(" multicnt %zu\n", ems_len);
+
+       for (i = 0; i < ems_len; ++i) {
+               printf("\t\t");
+               print_hwaddr(ems[i].enm_addrlo, sizeof(ems[i].enm_addrlo));
+               printf(" -- ");
+               print_hwaddr(ems[i].enm_addrhi, sizeof(ems[i].enm_addrhi));
+               printf(" %d\n", ems[i].enm_refcount);
        }
+       free(ems);
+       free(hwaddr);
 }
 
 static void
-in6_multilist(struct in6_multi *mc)
+print_inet6_mcast(u_short ifindex, const char *ifname)
 {
-       struct in6_multi multi;
+       static int mcast_oids[4], kludge_oids[4];
+       const char *addr;
+       uint8_t *mcast_addrs, *kludge_addrs, *p, *last_p;
+       uint32_t refcnt;
+       size_t len;
+
+       if (mcast_oids[0] == 0) {
+               size_t oidlen = __arraycount(mcast_oids);
+               if (sysctlnametomib("net.inet6.multicast", mcast_oids,
+                   &oidlen) == -1)
+                       errx(1, "net.inet6.multicast not found");
+               if (oidlen != 3)
+                       errx(1, "Wrong OID path for net.inet6.multicast");
+       }
+
+       if (kludge_oids[0] == 0) {
+               size_t oidlen = __arraycount(kludge_oids);
+               if (sysctlnametomib("net.inet6.multicast_kludge", kludge_oids,
+                   &oidlen) == -1)
+                       errx(1, "net.inet6.multicast_kludge not found");
+               if (oidlen != 3)
+                       errx(1, "Wrong OID path for 
net.inet6.multicast_kludge");
+       }
+
+       mcast_oids[3] = ifindex;
+       kludge_oids[3] = ifindex;
+
+       mcast_addrs = fetch_sysctl(&len, mcast_oids, 4,
+           "failed to read net.inet6.multicast");
+       if (len) {
+               p = mcast_addrs;
+               last_p = NULL;
+               while (len >= 2 * sizeof(struct in6_addr) + sizeof(uint32_t)) {
+                       if (last_p == NULL ||
+                           memcmp(p, last_p, sizeof(struct in6_addr)))
+                               printf("\tinet6 %s\n", inet6_n2a(p));
+                       last_p = p;
+                       p += sizeof(struct in6_addr);
+                       addr = inet6_n2a(p);
+                       p += sizeof(struct in6_addr);
+                       memcpy(&refcnt, p, sizeof(refcnt));
+                       p += sizeof(refcnt);
+                       printf("\t\tgroup %s refcount %" PRIu32 "\n", addr,
+                           refcnt);
+                       len -= 2 * sizeof(struct in6_addr) + sizeof(uint32_t);
+               }
+       }
+       free(mcast_addrs);
 
-       while (mc) {
-               KREAD(mc, &multi, struct in6_multi);
-               printf("\t\tgroup %s", inet6_n2a(&multi.in6m_addr));
-               printf(" refcnt %u\n", multi.in6m_refcount);
-               mc = multi.in6m_entry.le_next;
+       kludge_addrs = fetch_sysctl(&len, kludge_oids, 4,
+           "failed to read net.inet6.multicast_kludge");
+       if (len) {
+               printf("\t(on kludge entry for %s)\n", ifname);
+               p = kludge_addrs;
+               while (len >= sizeof(struct in6_addr) + sizeof(uint32_t)) {
+                       addr = inet6_n2a(p);
+                       p += sizeof(struct in6_addr);
+                       memcpy(&refcnt, p, sizeof(refcnt));
+                       p += sizeof(refcnt);
+                       printf("\t\tgroup %s refcount %" PRIu32 "\n", addr,
+                           refcnt);
+                       len -= sizeof(struct in6_addr) + sizeof(uint32_t);
+               }
        }
+       free(kludge_addrs);
 }


Home | Main Index | Thread Index | Old Index