Hi,

the following diff allows rad(8) to watch interface groups.  This
allows to automatically add/remove interfaces in a given group.

For example, I put "interface tap" into rad.conf and it automatically
serves my VM interfaces.  You could also configure a custom group in
vm.conf and rad.conf.  I'm working on IPv6 for vmd that needs it.

For reasons that I don't remember, I always missed this feature in
rtadvd(8)[RIP].  It was amazingly simple to add it to rad(8) as it
already reinitializes itself on interface changes.

This diff includes the previous ENXIO fix to prevent it from crashing
when a cloner interface such as tap is destroyed.

Reyk

Index: usr.sbin/rad/frontend.c
===================================================================
RCS file: /cvs/src/usr.sbin/rad/frontend.c,v
retrieving revision 1.16
diff -u -p -u -p -r1.16 frontend.c
--- usr.sbin/rad/frontend.c     15 Aug 2018 16:48:20 -0000      1.16
+++ usr.sbin/rad/frontend.c     16 Nov 2018 15:31:24 -0000
@@ -70,6 +70,7 @@
 #include <netinet6/ip6_var.h>
 #include <netinet/icmp6.h>
 
+#include <ctype.h>
 #include <errno.h>
 #include <event.h>
 #include <ifaddrs.h>
@@ -101,6 +102,7 @@ struct ra_iface {
        TAILQ_ENTRY(ra_iface)           entry;
        struct ra_prefix_conf_head      prefixes;
        char                            name[IF_NAMESIZE];
+       char                            conf[IF_NAMESIZE];
        uint32_t                        if_index;
        int                             removed;
        int                             prefix_count;
@@ -116,6 +118,7 @@ void                         frontend_startup(void);
 void                    icmp6_receive(int, short, void *);
 void                    join_all_routers_mcast_group(struct ra_iface *);
 void                    leave_all_routers_mcast_group(struct ra_iface *);
+void                    merge_ra_interface(struct ra_iface_conf *, char *);
 void                    merge_ra_interfaces(void);
 struct ra_iface                *find_ra_iface_by_id(uint32_t);
 struct ra_iface                *find_ra_iface_by_name(char *);
@@ -648,12 +651,13 @@ leave_all_routers_mcast_group(struct ra_
        log_debug("leaving multicast group on %s", ra_iface->name);
        all_routers.ipv6mr_interface = ra_iface->if_index;
        if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
-           &all_routers, sizeof(all_routers)) == -1)
+           &all_routers, sizeof(all_routers)) == -1 && errno != ENXIO)
                fatal("IPV6_LEAVE_GROUP(%s)", ra_iface->name);
 }
 
 struct ra_iface*
-find_ra_iface_by_id(uint32_t if_index) {
+find_ra_iface_by_id(uint32_t if_index)
+{
        struct ra_iface *ra_iface;
 
        TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) {
@@ -688,36 +692,81 @@ find_ra_iface_conf(struct ra_iface_conf_
 }
 
 void
+merge_ra_interface(struct ra_iface_conf *ra_iface_conf, char *name)
+{
+       struct ra_iface         *ra_iface;
+       uint32_t                 if_index;
+
+       ra_iface = find_ra_iface_by_name(name);
+       if (ra_iface == NULL) {
+               log_debug("new interface %s", name);
+               if ((if_index = if_nametoindex(name)) == 0)
+                       return;
+               log_debug("adding interface %s", name);
+               if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
+                       fatal("%s", __func__);
+
+               strlcpy(ra_iface->name, name, sizeof(ra_iface->name));
+               strlcpy(ra_iface->conf, ra_iface_conf->name,
+                   sizeof(ra_iface->conf));
+
+               ra_iface->if_index = if_index;
+               SIMPLEQ_INIT(&ra_iface->prefixes);
+               TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry);
+               join_all_routers_mcast_group(ra_iface);
+       } else {
+               log_debug("keeping interface %s", name);
+               ra_iface->removed = 0;
+       }
+}
+
+void
 merge_ra_interfaces(void)
 {
        struct ra_iface_conf    *ra_iface_conf;
        struct ra_prefix_conf   *ra_prefix_conf;
        struct ra_iface         *ra_iface;
-       uint32_t                 if_index;
+       struct ifgroupreq        ifgr;
+       struct ifg_req          *ifg;
+       char                    *name;
+       unsigned int             len;
 
        TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)
                ra_iface->removed = 1;
 
        SIMPLEQ_FOREACH(ra_iface_conf, &frontend_conf->ra_iface_list, entry) {
-               ra_iface = find_ra_iface_by_name(ra_iface_conf->name);
-               if (ra_iface == NULL) {
-                       log_debug("new interface %s", ra_iface_conf->name);
-                       if ((if_index = if_nametoindex(ra_iface_conf->name))
-                           == 0)
-                               continue;
-                       log_debug("adding interface %s", ra_iface_conf->name);
-                       if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
-                               fatal("%s", __func__);
-
-                       (void) strlcpy(ra_iface->name, ra_iface_conf->name,
-                           sizeof(ra_iface->name));
-                       ra_iface->if_index = if_index;
-                       SIMPLEQ_INIT(&ra_iface->prefixes);
-                       TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry);
-                       join_all_routers_mcast_group(ra_iface);
+               name = ra_iface_conf->name;
+
+               /* check if network interface or group */
+               if (isdigit((unsigned char)name[strlen(name) - 1])) {
+                       merge_ra_interface(ra_iface_conf, name);
                } else {
-                       log_debug("keeping interface %s", ra_iface_conf->name);
-                       ra_iface->removed = 0;
+                       log_debug("interface group %s", name);
+
+                       memset(&ifgr, 0, sizeof(ifgr));
+                       strlcpy(ifgr.ifgr_name, name, sizeof(ifgr.ifgr_name));
+                       if (ioctl(ioctlsock, SIOCGIFGMEMB,
+                           (caddr_t)&ifgr) == -1)
+                               continue;
+
+                       len = ifgr.ifgr_len;
+                       if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
+                               fatal("%s: calloc", __func__);
+                       if (ioctl(ioctlsock, SIOCGIFGMEMB,
+                           (caddr_t)&ifgr) == -1) {
+                               log_debug("group %s without members", name);
+                               free(ifgr.ifgr_groups);
+                               continue;
+                       }
+
+                       for (ifg = ifgr.ifgr_groups;
+                           (ifg != NULL) && (len >= sizeof(struct ifg_req));
+                           ifg++) {
+                               len -= sizeof(struct ifg_req);
+                               merge_ra_interface(ra_iface_conf,
+                                   ifg->ifgrq_member);
+                       }
+                       free(ifgr.ifgr_groups);
                }
        }
 
@@ -739,7 +788,7 @@ merge_ra_interfaces(void)
                }
 
                ra_iface_conf = find_ra_iface_conf(
-                   &frontend_conf->ra_iface_list, ra_iface->name);
+                   &frontend_conf->ra_iface_list, ra_iface->conf);
 
                if (ra_iface_conf->autoprefix)
                        get_interface_prefixes(ra_iface,
@@ -903,7 +952,7 @@ build_packet(struct ra_iface *ra_iface)
        char                            *label_start, *label_end;
 
        ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
-           ra_iface->name);
+           ra_iface->conf);
        ra_options_conf = &ra_iface_conf->ra_options;
 
        len = sizeof(*ra);
Index: usr.sbin/rad/rad.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/rad/rad.conf.5,v
retrieving revision 1.12
diff -u -p -u -p -r1.12 rad.conf.5
--- usr.sbin/rad/rad.conf.5     16 Sep 2018 18:58:36 -0000      1.12
+++ usr.sbin/rad/rad.conf.5     16 Nov 2018 15:31:24 -0000
@@ -109,7 +109,7 @@ The default is 1800 seconds.
 .\" XXX
 .El
 .Sh INTERFACES
-A list of interfaces to send advertisments on:
+A list of interfaces or interface groups to send advertisments on:
 .Bd -unfilled -offset indent
 .Ic interface Ar name Op { prefix list }
 .Ed

Reply via email to