Support muliple RAs on single interface
authorPierre Pfister <ppfister@cisco.com>
Fri, 8 Dec 2017 14:15:02 +0000 (15:15 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Fri, 8 Dec 2017 17:22:06 +0000 (18:22 +0100)
IETF is moving toward implementing IPv6 multihoming by sending
multiple RAs on a single interface:
- draft-ietf-intarea-provisioning-domains-00
- draft-ietf-rtgwg-enterprise-pa-multihoming-02

odhcpd supports configuration of multiple software interfaces
on the same physical interface, which already advertises
multiple RAs, but had two issues:
- Each RA includes all the prefixes available on the interface.
- Replies to sollicits with a single RA.

This patch introduces the prefix_filter configuration parameter
which allows filtering prefixes that are sent in a given RA,
and fixes the sollicit code in order to reply with all the RAs
that are configured on a given interface.

Signed-off-by: Pierre Pfister <ppfister@cisco.com>
README
src/config.c
src/odhcpd.c
src/odhcpd.h
src/router.c

diff --git a/README b/README
index 95f59bfe8c4c20b6e890177f7f727283ec207b98..0c562e6faed472dadf8170a9e4e83f214cb054a8 100644 (file)
--- a/README
+++ b/README
@@ -134,6 +134,9 @@ ra_mtu                      integer 0                       MTU to be advertised in
                                                        RA messages
 ndproxy_routing                bool    1                       Learn routes from NDP
 ndproxy_slave          bool    0                       NDProxy external slave
+prefix_filter          string  ::/0                    Only advertise on-link prefixes within
+                       [IPv6 prefix]                   the provided IPv6 prefix; others are
+                                                       filtered out.
 
 
 Sections of type host (static leases)
index bb885d078824ca7e024508b0d3284f0b0e52ea24..409b3b81b9c988409b08b1e852d9b6e137f3e800 100644 (file)
@@ -62,6 +62,7 @@ enum {
        IFACE_ATTR_PD_CER,
        IFACE_ATTR_NDPROXY_ROUTING,
        IFACE_ATTR_NDPROXY_SLAVE,
+       IFACE_ATTR_PREFIX_FILTER,
        IFACE_ATTR_MAX
 };
 
@@ -104,6 +105,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [IFACE_ATTR_RA_MTU] = { .name = "ra_mtu", .type = BLOBMSG_TYPE_INT32 },
        [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
+       [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
 };
 
 static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = {
@@ -720,6 +722,23 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
        if ((c = tb[IFACE_ATTR_NDPROXY_SLAVE]))
                iface->external = blobmsg_get_bool(c);
 
+       if ((c = tb[IFACE_ATTR_PREFIX_FILTER])) {
+               const char *str = blobmsg_get_string(c);
+               char *astr = malloc(strlen(str) + 1);
+               char *delim;
+               int l;
+               if (!astr || !strcpy(astr, str) ||
+                               (delim = strchr(astr, '/')) == NULL || (*(delim++) = 0) ||
+                               sscanf(delim, "%i", &l) == 0 || l > 128 ||
+                               inet_pton(AF_INET6, astr, &iface->pio_filter_addr) == 0) {
+                       iface->pio_filter_length = 0;
+               } else {
+                       iface->pio_filter_length = l;
+               }
+               if (astr)
+                       free(astr);
+       }
+
        return 0;
 
 err:
index 97a6de92f34620fa79f2d8516d354e957a4b3f08..58c4338b908296a2e279559e45593c4937486463 100644 (file)
@@ -371,12 +371,6 @@ static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int even
                if (addr.ll.sll_family == AF_PACKET)
                        destiface = addr.ll.sll_ifindex;
 
-               struct interface *iface =
-                               odhcpd_get_interface_by_index(destiface);
-
-               if (!iface && addr.nl.nl_family != AF_NETLINK)
-                       continue;
-
                char ipbuf[INET6_ADDRSTRLEN] = "kernel";
                if (addr.ll.sll_family == AF_PACKET &&
                                len >= (ssize_t)sizeof(struct ip6_hdr))
@@ -386,10 +380,26 @@ static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int even
                else if (addr.in.sin_family == AF_INET)
                        inet_ntop(AF_INET, &addr.in.sin_addr, ipbuf, sizeof(ipbuf));
 
-               syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
-                               ipbuf, (iface) ? iface->ifname : "netlink");
+               // From netlink
+               if (addr.nl.nl_family == AF_NETLINK) {
+                       syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
+                                       ipbuf, "netlink");
+                       e->handle_dgram(&addr, data_buf, len, NULL, dest);
+                       return;
+               } else if (destiface != 0) {
+                       struct interface *iface;
+                       list_for_each_entry(iface, &interfaces, head) {
+                               if (iface->ifindex != destiface)
+                                       continue;
+
+                               syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
+                                               ipbuf, iface->ifname);
+
+                               e->handle_dgram(&addr, data_buf, len, iface, dest);
+                       }
+               }
+
 
-               e->handle_dgram(&addr, data_buf, len, iface, dest);
        }
 }
 
index fbfeb671c977e299fb0a0513eca0e3088d51f3f1..48ee51eb4b7a97798cc02b4a309aad50965d6361 100644 (file)
@@ -208,6 +208,8 @@ struct interface {
        bool ra_advrouter;
        bool ra_useleasetime;
        bool no_dynamic_dhcp;
+       uint8_t pio_filter_length;
+       struct in6_addr pio_filter_addr;
 
        // RA
        int learn_routes;
index c35cd12e7d30c6fd0dc2f71888362e7ffa759533..7bc94ed7825da5d7c91d2ea15ffa4023a3f26eb0 100644 (file)
@@ -380,6 +380,11 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                        continue;
                }
 
+               if (odhcpd_bmemcmp(&addr->addr, &iface->pio_filter_addr,
+                               iface->pio_filter_length) != 0 ||
+                               addr->prefix < iface->pio_filter_length)
+                       continue; // PIO filtered out of this RA
+
                struct nd_opt_prefix_info *p = NULL;
                for (size_t i = 0; i < pfxs_cnt; ++i) {
                        if (addr->prefix == pfxs[i].nd_opt_pi_prefix_len &&