On Tue, Nov 20, 2018 at 04:23:33PM +0100, Reyk Floeter wrote:
> 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

I removed that part for now, it's only true for interface group vs.
interface.

Interfaces get merged (this is also true for interface groups, it's
just that groups don't get merged with interfaces):

interface vether0 { dns {nameserver ::11 }}
interface vether0 { dns {nameserver ::22 }}

gets parsed as:

interface vether0 {
        dns {
                nameserver ::11
                nameserver ::22
        }
}

> 
> OK?
> 
> Reyk
> 

I renamed conf to conf_name and only pass that merge_ra_interface()
since it's the name in the config, not the config itself that we
store.

This is OK florian@ if it works for you.

diff --git frontend.c frontend.c
index 6b96623fb47..700ca3df88b 100644
--- frontend.c
+++ frontend.c
@@ -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_name[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(char *, 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 *);
@@ -687,37 +690,84 @@ find_ra_iface_conf(struct ra_iface_conf_head *head, char 
*if_name)
        return (NULL);
 }
 
+void
+merge_ra_interface(char *name, char *conf_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_name, conf_name,
+           sizeof(ra_iface->conf_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);
+}
+
 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                    *conf_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);
+               conf_name = ra_iface_conf->name;
+
+               /* check if network interface or group */
+               if (isdigit((unsigned char)conf_name[strlen(conf_name) - 1])) {
+                       merge_ra_interface(conf_name, conf_name);
                } else {
-                       log_debug("keeping interface %s", ra_iface_conf->name);
-                       ra_iface->removed = 0;
+                       log_debug("interface group %s", conf_name);
+
+                       memset(&ifgr, 0, sizeof(ifgr));
+                       strlcpy(ifgr.ifgr_name, conf_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",
+                                   conf_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(ifg->ifgrq_member,
+                                   conf_name);
+                       }
+                       free(ifgr.ifgr_groups);
                }
        }
 
@@ -739,7 +789,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_name);
 
                if (ra_iface_conf->autoprefix)
                        get_interface_prefixes(ra_iface,
@@ -903,7 +953,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_name);
        ra_options_conf = &ra_iface_conf->ra_options;
 
        len = sizeof(*ra);
diff --git rad.conf.5 rad.conf.5
index acf3c0e9997..9c0c1cd717e 100644
--- rad.conf.5
+++ rad.conf.5
@@ -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


-- 
I'm not entirely sure you are real.

Reply via email to