diff options
author | Hans Dedecker <dedeckeh@gmail.com> | 2017-02-16 12:20:08 +0100 |
---|---|---|
committer | Hans Dedecker <dedeckeh@gmail.com> | 2017-02-16 18:25:41 +0100 |
commit | 942fb33d3017e8769a7354ee008daf0f31a40fe2 (patch) | |
tree | 501c416bd8c2c8b8befecfc93addf46e8f1721ac /src/router.c | |
parent | f91333771b9625850e0f5cad8af6e9c6441e387e (diff) |
router: support ra_mininterval and ra_lifetime uci parameters (FS#397)
Add support for uci parameters ra_mininterval and ra_lifetime as described
in RFC4861 paragraph 6.2.1.
Variable ra_mininterval allows to configure the minimum interval time
between unsolicited router advertisement messages; default value is
200 seconds. The minimum allowed value is 4 seconds while the maximum
value is limited to 0.75 of the maximum interval time.
The calculation of the maximum interval time between unsolicited
router advertisement messages has been reworked. The default value is 600
seconds as specified in RFC4861; if the maximum interval time exceeds
0.33 * the minimal valid lifetime of all IPv6 prefixes it will be limited
to 0.33 * the minimal valid lifetime of all IPv6 prefixes
Variable ra_lifetime allows to configure the Router Lifetime field
in the router advertisement messages; the value is either 0 or a value
between the maximum interval time and 9000 seconds. If the router lifetime
is smaller than the RA maximum interval it will be set equal to the RA
maximum interval time.
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'src/router.c')
-rw-r--r-- | src/router.c | 119 |
1 files changed, 73 insertions, 46 deletions
diff --git a/src/router.c b/src/router.c index 36267be..4ab06b6 100644 --- a/src/router.c +++ b/src/router.c @@ -211,6 +211,48 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) return found_default; } +static int calc_adv_interval(struct interface *iface, uint32_t minvalid, + uint32_t *maxival) +{ + uint32_t minival = iface->ra_mininterval; + int msecs; + + *maxival = iface->ra_maxinterval; + + if (*maxival > minvalid/3) + *maxival = minvalid/3; + + if (*maxival > MaxRtrAdvInterval) + *maxival = MaxRtrAdvInterval; + else if (*maxival < 4) + *maxival = 4; + + if (minival < MinRtrAdvInterval) + minival = MinRtrAdvInterval; + else if (minival > (*maxival * 3)/4) + minival = (*maxival >= 9 ? *maxival/3 : *maxival); + + odhcpd_urandom(&msecs, sizeof(msecs)); + msecs = (labs(msecs) % ((*maxival - minival)*1000)) + minival*1000; + + return msecs; +} + +static uint16_t calc_ra_lifetime(struct interface *iface, uint32_t maxival) +{ + uint16_t lifetime = 3*maxival; + + if (iface->ra_lifetime >= 0) { + lifetime = iface->ra_lifetime; + if (lifetime < maxival) + lifetime = maxival; + else if (lifetime > 9000) + lifetime = 9000; + } + + return lifetime; +} + // Router Advert server mode static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from) { @@ -250,7 +292,9 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add // If not currently shutting down struct odhcpd_ipaddr addrs[RELAYD_MAX_ADDRS]; ssize_t ipcnt = 0; - int64_t minvalid = INT64_MAX; + uint32_t minvalid = UINT32_MAX; + bool default_route = false; + bool valid_prefix = false; // If not shutdown if (iface->timer_rs.cb) { @@ -258,13 +302,13 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add memcpy(addrs, iface->ia_addr, ipcnt * sizeof(*addrs)); // Check default route - if (iface->default_router > 1) - adv.h.nd_ra_router_lifetime = htons(iface->default_router); - else if (parse_routes(addrs, ipcnt)) - adv.h.nd_ra_router_lifetime = htons(1); + if (iface->default_router) { + default_route = true; - syslog(LOG_INFO, "Initial RA router lifetime %d, %d address(es) available on %s", - ntohs(adv.h.nd_ra_router_lifetime), (int)ipcnt, iface->ifname); + if (iface->default_router > 1) + valid_prefix = true; + } else if (parse_routes(addrs, ipcnt)) + default_route = true; } // Construct Prefix Information options @@ -303,19 +347,11 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add } if (addr->preferred > (uint32_t)now && - minvalid > 1000LL * TIME_LEFT(addr->valid, now)) - minvalid = 1000LL * TIME_LEFT(addr->valid, now); - - uint32_t this_lifetime = TIME_LEFT(addr->valid, now); - if (this_lifetime > UINT16_MAX) - this_lifetime = UINT16_MAX; - if ((!IN6_IS_ADDR_ULA(&addr->addr) || iface->default_router) - && adv.h.nd_ra_router_lifetime - && ntohs(adv.h.nd_ra_router_lifetime) < this_lifetime) { - adv.h.nd_ra_router_lifetime = htons(this_lifetime); - - syslog(LOG_INFO, "Updating RA router lifetime to %d on %s", this_lifetime, iface->ifname); - } + minvalid > TIME_LEFT(addr->valid, now)) + minvalid = TIME_LEFT(addr->valid, now); + + if (!IN6_IS_ADDR_ULA(&addr->addr) || iface->default_router) + valid_prefix = true; odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr, (iface->ra_advrouter) ? 128 : addr->prefix); @@ -336,11 +372,22 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add p->nd_opt_pi_valid_time = 0; } - if (!iface->default_router && adv.h.nd_ra_router_lifetime == htons(1)) { - syslog(LOG_WARNING, "A default route is present but there is no public prefix " - "on %s thus we don't announce a default route!", iface->ifname); + // Calculate periodic transmit + uint32_t maxival; + int msecs = calc_adv_interval(iface, minvalid, &maxival); + + if (default_route) { + if (!valid_prefix) { + syslog(LOG_WARNING, "A default route is present but there is no public prefix " + "on %s thus we don't announce a default route!", iface->ifname); + adv.h.nd_ra_router_lifetime = 0; + } else + adv.h.nd_ra_router_lifetime = htons(calc_ra_lifetime(iface, maxival)); + + } else adv.h.nd_ra_router_lifetime = 0; - } + + syslog(LOG_INFO, "Using a RA lifetime of %d seconds on %s", ntohs(adv.h.nd_ra_router_lifetime), iface->ifname); // DNS Recursive DNS if (iface->dns_cnt > 0) { @@ -433,33 +480,13 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add ++routes_cnt; } - // Calculate periodic transmit - int msecs = 0; - uint32_t maxival = iface->ra_maxinterval * 1000; - uint32_t minival; - - if (maxival < 4000 || maxival > MaxRtrAdvInterval * 1000) - maxival = MaxRtrAdvInterval * 1000; - - if (maxival > minvalid / 3) { - maxival = minvalid / 3; - - if (maxival < 4000) - maxival = 4000; - } - - minival = (maxival * 3) / 4; - - search->lifetime = htonl(maxival / 100); + search->lifetime = htonl(maxival*10); dns.lifetime = search->lifetime; - odhcpd_urandom(&msecs, sizeof(msecs)); - msecs = (labs(msecs) % (maxival - minival)) + minival; - struct icmpv6_opt adv_interval = { .type = ND_OPT_RTR_ADV_INTERVAL, .len = 1, - .data = {0, 0, maxival >> 24, maxival >> 16, maxival >> 8, maxival} + .data = {0, 0, (maxival*1000) >> 24, (maxival*1000) >> 16, (maxival*1000) >> 8, maxival*1000} }; struct iovec iov[RA_IOV_LEN] = { |