odhcpd: add option for setting preferred lifetime
authorNick Hainke <vincent@systemli.org>
Sat, 2 Jan 2021 22:27:03 +0000 (23:27 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Sun, 3 Jan 2021 14:42:49 +0000 (15:42 +0100)
"valid_lft" and "preferred_lft" are different. If the "preferred_lft"
is expired the prefix should be avoided in source prefix selection.
However, the interface is allowed to still receive downstream traffic.

preferred_lfetime:
  Limit for preferred lifetime of a prefix

If you want the old behavior, you have to set preferred_lifetime to
the same value as leasetime.

Signed-off-by: Nick Hainke <vincent@systemli.org>
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
README
src/config.c
src/dhcpv6-ia.c
src/odhcpd.h
src/router.c

diff --git a/README b/README
index a34a93c1ae08747b4a87c31f85273b374d6b60f4..f9cbb117004294a738add82945f4b3365fa484f0 100644 (file)
--- a/README
+++ b/README
@@ -110,7 +110,8 @@ domain                      list    <local search domain>   Search domains to announce
 leasetime              string  12h                     DHCPv4 address leasetime
 start                  integer 100                     DHCPv4 pool start
 limit                  integer 150                     DHCPv4 pool size
 leasetime              string  12h                     DHCPv4 address leasetime
 start                  integer 100                     DHCPv4 pool start
 limit                  integer 150                     DHCPv4 pool size
-
+preferred_lifetime     string  12h                     Value for the preferred lifetime
+                                                       for a prefix
 ra_default             integer 0                       Override default route
                        0: default, 1: ignore no public address, 2: ignore all
 ra_flags               list    other-config            List of RA flags to be
 ra_default             integer 0                       Override default route
                        0: default, 1: ignore no public address, 2: ignore all
 ra_flags               list    other-config            List of RA flags to be
index 015a716dd1cf2de877108f1c670927b66045d2aa..78b58550040061ce2c056e94b28d50e554edaace 100644 (file)
@@ -82,6 +82,7 @@ enum {
        IFACE_ATTR_NDPROXY_ROUTING,
        IFACE_ATTR_NDPROXY_SLAVE,
        IFACE_ATTR_PREFIX_FILTER,
        IFACE_ATTR_NDPROXY_ROUTING,
        IFACE_ATTR_NDPROXY_SLAVE,
        IFACE_ATTR_PREFIX_FILTER,
+       IFACE_ATTR_PREFERRED_LIFETIME,
        IFACE_ATTR_MAX
 };
 
        IFACE_ATTR_MAX
 };
 
@@ -130,6 +131,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [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 },
        [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 },
+       [IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
 };
 
 static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = {
 };
 
 static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = {
@@ -197,6 +199,7 @@ static void set_interface_defaults(struct interface *iface)
        iface->ndp = MODE_DISABLED;
        iface->learn_routes = 1;
        iface->dhcp_leasetime = 43200;
        iface->ndp = MODE_DISABLED;
        iface->learn_routes = 1;
        iface->dhcp_leasetime = 43200;
+       iface->preferred_lifetime = 43200;
        iface->dhcpv4_start.s_addr = htonl(START_DEFAULT);
        iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1);
        iface->dhcpv6_assignall = true;
        iface->dhcpv4_start.s_addr = htonl(START_DEFAULT);
        iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1);
        iface->dhcpv6_assignall = true;
@@ -525,6 +528,14 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
                iface->dhcp_leasetime = time;
        }
 
                iface->dhcp_leasetime = time;
        }
 
+       if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) {
+               double time = parse_leasetime(c);
+               if (time < 0)
+                       goto err;
+
+               iface->preferred_lifetime = time;
+       }
+
        if ((c = tb[IFACE_ATTR_START])) {
                iface->dhcpv4_start.s_addr = htonl(blobmsg_get_u32(c));
                iface->dhcpv4_end.s_addr = htonl(ntohl(iface->dhcpv4_start.s_addr) +
        if ((c = tb[IFACE_ATTR_START])) {
                iface->dhcpv4_start.s_addr = htonl(blobmsg_get_u32(c));
                iface->dhcpv4_end.s_addr = htonl(ntohl(iface->dhcpv4_start.s_addr) +
index d7848de4638bfb9115fa053adba676cfe836464a..a59fc20f9054723d35d347968d1a5231582fc6e9 100644 (file)
@@ -247,6 +247,9 @@ void dhcpv6_ia_enum_addrs(struct interface *iface, struct dhcp_assignment *c,
                        addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
                }
 
                        addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
                }
 
+               if (pref > (uint32_t)c->preferred_until)
+                       pref = c->preferred_until;
+
                if (pref > (uint32_t)c->valid_until)
                        pref = c->valid_until;
 
                if (pref > (uint32_t)c->valid_until)
                        pref = c->valid_until;
 
@@ -827,14 +830,16 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status,
        }
 
        if (a) {
        }
 
        if (a) {
-               uint32_t leasetime;
+               uint32_t leasetime, pref;
 
 
-               if (a->leasetime)
+               if (a->leasetime) {
                        leasetime = a->leasetime;
                        leasetime = a->leasetime;
-               else
+                       pref = a->leasetime;
+               } else {
                        leasetime = iface->dhcp_leasetime;
                        leasetime = iface->dhcp_leasetime;
+                       pref = iface->preferred_lifetime;
+               }
 
 
-               uint32_t pref = leasetime;
                uint32_t valid = leasetime;
 
                struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
                uint32_t valid = leasetime;
 
                struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
@@ -851,8 +856,8 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status,
                        if (prefix_pref != UINT32_MAX)
                                prefix_pref -= now;
 
                        if (prefix_pref != UINT32_MAX)
                                prefix_pref -= now;
 
-                       if (prefix_pref > leasetime)
-                               prefix_pref = leasetime;
+                       if (prefix_pref > pref)
+                               prefix_pref = pref;
 
                        if (prefix_valid != UINT32_MAX)
                                prefix_valid -= now;
 
                        if (prefix_valid != UINT32_MAX)
                                prefix_valid -= now;
@@ -918,6 +923,10 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status,
                        /* UINT32_MAX is considered as infinite leasetime */
                        a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
 
                        /* UINT32_MAX is considered as infinite leasetime */
                        a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
 
+               if (!INFINITE_VALID(a->preferred_until))
+                       /* UINT32_MAX is considered as infinite leasetime */
+                       a->preferred_until = (pref == UINT32_MAX) ? 0 : pref + now;
+
                o_ia.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10);
                o_ia.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10);
 
                o_ia.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10);
                o_ia.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10);
 
@@ -1261,6 +1270,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
                                                a->peer = *addr;
                                                a->assigned = is_na && l ? l->hostid : reqhint;
                                                a->valid_until =  now;
                                                a->peer = *addr;
                                                a->assigned = is_na && l ? l->hostid : reqhint;
                                                a->valid_until =  now;
+                                               a->preferred_until =  now;
                                                a->dhcp_free_cb = dhcpv6_ia_free_assignment;
                                                a->iface = iface;
                                                a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA);
                                                a->dhcp_free_cb = dhcpv6_ia_free_assignment;
                                                a->iface = iface;
                                                a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA);
index 2f7dd25291396d6b09f71d7ce17d1d70a088a68e..45b6784ce0986acd5167d49d10ee58122c77cd22 100644 (file)
@@ -182,6 +182,7 @@ struct dhcp_assignment {
 
        struct sockaddr_in6 peer;
        time_t valid_until;
 
        struct sockaddr_in6 peer;
        time_t valid_until;
+       time_t preferred_until;
 
 #define fr_timer       reconf_timer
        struct uloop_timeout reconf_timer;
 
 #define fr_timer       reconf_timer
        struct uloop_timeout reconf_timer;
@@ -286,6 +287,7 @@ struct interface {
        uint32_t ra_retranstime;
        uint32_t ra_hoplimit;
        int ra_mtu;
        uint32_t ra_retranstime;
        uint32_t ra_hoplimit;
        int ra_mtu;
+       uint32_t preferred_lifetime;
 
        // DHCP
        uint32_t dhcp_leasetime;
 
        // DHCP
        uint32_t dhcp_leasetime;
index 06f3a668c4438e0711c8a3acb03851c662a74f09..d6ab4bb517ff67ca68491504a94f97a192b7720e 100644 (file)
@@ -552,8 +552,8 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
                        preferred = TIME_LEFT(addr->preferred, now);
 
                        if (iface->ra_useleasetime &&
                        preferred = TIME_LEFT(addr->preferred, now);
 
                        if (iface->ra_useleasetime &&
-                           preferred > iface->dhcp_leasetime)
-                               preferred = iface->dhcp_leasetime;
+                           preferred > iface->preferred_lifetime)
+                               preferred = iface->preferred_lifetime;
                }
 
                valid = TIME_LEFT(addr->valid, now);
                }
 
                valid = TIME_LEFT(addr->valid, now);