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 }