radv: Add prefixes with dynamically updated lifetimes
Add a boolean that indicates whether the prefixes will always exist or if they will time out after the assigned valid lifetime. In the latter case calculate the expiry times for both preferred and valid lifetimes for the prefixes, and decrease the remaining lifetimes each time when a Router Advertisement is sent. Should the prefix be updated, re-calculate the prefix lifetime. When updating, update the existing entry, if any, with the lifetimes of the added entry as the existing entry has its lifetimes set according to its previously calculated expiry times.
This commit is contained in:
parent
652bf04254
commit
d601b56687
|
@ -93,6 +93,9 @@ struct sd_radv_prefix {
|
|||
} _packed_ opt;
|
||||
|
||||
LIST_FIELDS(struct sd_radv_prefix, prefix);
|
||||
|
||||
usec_t valid_until;
|
||||
usec_t preferred_until;
|
||||
};
|
||||
|
||||
#define log_radv_full(level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "RADV: " fmt, ##__VA_ARGS__)
|
||||
|
|
|
@ -169,6 +169,12 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst,
|
|||
.msg_namelen = sizeof(dst_addr),
|
||||
.msg_iov = iov,
|
||||
};
|
||||
usec_t time_now;
|
||||
int r;
|
||||
|
||||
r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (dst && !in_addr_is_null(AF_INET6, (union in_addr_union*) dst))
|
||||
dst_addr.sin6_addr = *dst;
|
||||
|
@ -198,6 +204,18 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst,
|
|||
}
|
||||
|
||||
LIST_FOREACH(prefix, p, ra->prefixes) {
|
||||
if (p->valid_until) {
|
||||
|
||||
if (time_now > p->valid_until)
|
||||
p->opt.valid_lifetime = 0;
|
||||
else
|
||||
p->opt.valid_lifetime = htobe32((p->valid_until - time_now) / USEC_PER_SEC);
|
||||
|
||||
if (time_now > p->preferred_until)
|
||||
p->opt.preferred_lifetime = 0;
|
||||
else
|
||||
p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC);
|
||||
}
|
||||
iov[msg.msg_iovlen].iov_base = &p->opt;
|
||||
iov[msg.msg_iovlen].iov_len = sizeof(p->opt);
|
||||
msg.msg_iovlen++;
|
||||
|
@ -518,9 +536,13 @@ _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
|
|||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
|
||||
_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic) {
|
||||
sd_radv_prefix *cur;
|
||||
int r;
|
||||
_cleanup_free_ char *addr_p = NULL;
|
||||
char time_string_preferred[FORMAT_TIMESPAN_MAX];
|
||||
char time_string_valid[FORMAT_TIMESPAN_MAX];
|
||||
usec_t time_now, valid, preferred, valid_until, preferred_until;
|
||||
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
|
@ -528,7 +550,6 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
|
|||
return -EINVAL;
|
||||
|
||||
LIST_FOREACH(prefix, cur, ra->prefixes) {
|
||||
int r;
|
||||
|
||||
r = in_addr_prefix_intersect(AF_INET6,
|
||||
(union in_addr_union*) &cur->opt.in6_addr,
|
||||
|
@ -538,13 +559,16 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
|
|||
if (r > 0) {
|
||||
_cleanup_free_ char *addr_cur = NULL;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6,
|
||||
(union in_addr_union*) &cur->opt.in6_addr,
|
||||
&addr_cur);
|
||||
(void) in_addr_to_string(AF_INET6,
|
||||
(union in_addr_union*) &p->opt.in6_addr,
|
||||
&addr_p);
|
||||
|
||||
if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
|
||||
goto update;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6,
|
||||
(union in_addr_union*) &cur->opt.in6_addr,
|
||||
&addr_cur);
|
||||
log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
|
||||
addr_cur, cur->opt.prefixlen,
|
||||
addr_p, p->opt.prefixlen);
|
||||
|
@ -560,7 +584,39 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
|
|||
ra->n_prefixes++;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
|
||||
log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
|
||||
|
||||
if (!dynamic) {
|
||||
log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur = p;
|
||||
|
||||
update:
|
||||
r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
valid = be32toh(p->opt.valid_lifetime) * USEC_PER_SEC;
|
||||
valid_until = usec_add(valid, time_now);
|
||||
if (valid_until == USEC_INFINITY)
|
||||
return -EOVERFLOW;
|
||||
|
||||
preferred = be32toh(p->opt.preferred_lifetime) * USEC_PER_SEC;
|
||||
preferred_until = usec_add(preferred, time_now);
|
||||
if (preferred_until == USEC_INFINITY)
|
||||
return -EOVERFLOW;
|
||||
|
||||
cur->valid_until = valid_until;
|
||||
cur->preferred_until = preferred_until;
|
||||
|
||||
log_radv("%s prefix %s/%u preferred %s valid %s",
|
||||
cur? "Updated": "Added",
|
||||
addr_p, p->opt.prefixlen,
|
||||
format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
|
||||
preferred, USEC_PER_SEC),
|
||||
format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX,
|
||||
valid, USEC_PER_SEC));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -342,8 +342,8 @@ static void test_ra(void) {
|
|||
if (prefix[i].preferred)
|
||||
assert_se(sd_radv_prefix_set_preferred_lifetime(p, prefix[i].preferred) >= 0);
|
||||
|
||||
assert_se((sd_radv_add_prefix(ra, p) >= 0) == prefix[i].succesful);
|
||||
assert_se(sd_radv_add_prefix(ra, p) < 0);
|
||||
assert_se((sd_radv_add_prefix(ra, p, false) >= 0) == prefix[i].succesful);
|
||||
assert_se(sd_radv_add_prefix(ra, p, false) < 0);
|
||||
|
||||
p = sd_radv_prefix_unref(p);
|
||||
assert_se(!p);
|
||||
|
|
|
@ -502,7 +502,7 @@ int radv_configure(Link *link) {
|
|||
RADV_PREFIX_DELEGATION_STATIC,
|
||||
RADV_PREFIX_DELEGATION_BOTH)) {
|
||||
LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
|
||||
r = sd_radv_add_prefix(link->radv, p->radv_prefix);
|
||||
r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
|
||||
if (r != -EEXIST && r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
@ -62,7 +63,7 @@ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime);
|
|||
int sd_radv_set_managed_information(sd_radv *ra, int managed);
|
||||
int sd_radv_set_other_information(sd_radv *ra, int other);
|
||||
int sd_radv_set_preference(sd_radv *ra, unsigned preference);
|
||||
int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
|
||||
int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic);
|
||||
int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
|
||||
const struct in6_addr *dns, size_t n_dns);
|
||||
int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list);
|
||||
|
|
Loading…
Reference in New Issue