summaryrefslogtreecommitdiffhomepage
path: root/src/router.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2017-02-16 12:20:08 +0100
committerHans Dedecker <dedeckeh@gmail.com>2017-02-16 18:25:41 +0100
commit942fb33d3017e8769a7354ee008daf0f31a40fe2 (patch)
tree501c416bd8c2c8b8befecfc93addf46e8f1721ac /src/router.c
parentf91333771b9625850e0f5cad8af6e9c6441e387e (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.c119
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] = {