On Sat, Nov 17, 2018 at 02:11:58PM +0100, Klemens Nanni wrote:
> On Fri, Nov 16, 2018 at 08:56:52PM +0100, Reyk Floeter wrote:
> > > 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.
> Nice idea/work, I like 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.
> > > 
> > 
> > Updated diff after committing the ENXIO fix.
> > 
> > Two explanations:
> > 
> > - merge_ra_interfaces() calls merge_ra_interface() for each configured
> > interface (explicit config) and for each member that is found in an
> > interface group.  It is basically just some code shuffling.
> > 
> > - ra_iface->name is split into ra_iface->name and ra_iface->conf as
> > "name" indicates and actual (found) interface name ("tap0") and "conf"
> > is used to lookup the config where it was derived from ("tap" or
> > "tap0", depending on the configuration).
> This begs the question about priority in rad.conf(5). It's always been
> possible to define duplicate `interface' blocks although it didn't make
> any sense.
> 
> Now it does since you could define a default config for the entire group
> and add further interface specific blocks.
> 
> As it currently is, the first matching block wins, so vether0 would
> always get RDNS ::11 whether a more specific block exists or not:
> 
>       interface vether  { dns { nameserver ::11 } }
>       interface vether0 { dns { nameserver ::22 } }
> 
> Maybe we should clarify behaviour in rad.conf(5) regardless of your
> changes?
> 

Updated diff:
- less indentation in merge_ra_interface()
- manpage with additional clarification about first match

OK?

Reyk

Index: usr.sbin/rad/frontend.c
===================================================================
RCS file: /cvs/src/usr.sbin/rad/frontend.c,v
retrieving revision 1.17
diff -u -p -u -p -r1.17 frontend.c
--- usr.sbin/rad/frontend.c     16 Nov 2018 19:45:40 -0000      1.17
+++ usr.sbin/rad/frontend.c     20 Nov 2018 15:21:16 -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 *);
@@ -688,36 +691,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;
+
+       if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
+               log_debug("keeping interface %s", name);
+               ra_iface->removed = 0;
+               return;
+       }
+
+       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);
+}
+
+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 +787,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 +951,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     20 Nov 2018 15:21:16 -0000
@@ -109,13 +109,15 @@ 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
 .Pp
 Options set in the global section can be overwritten inside an interface
 block.
+If multiple blocks match the same interface, only the first matching
+block will be used.
 In addition an interface block can contain a list of prefixes:
 .Bd -unfilled -offset indent
 .Oo Ic no Oc Ic auto prefix Op { prefix options }

Reply via email to