summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/sd-radv.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-01-15 12:02:37 +0100
committerGitHub <noreply@github.com>2018-01-15 12:02:37 +0100
commit38edb7674bc22551f7c7ac010b296406ce25e7f1 (patch)
treef3ac7a58d28595754c348d97314e24a8a493b002 /src/libsystemd-network/sd-radv.c
parentf94abc667a6330cccd9a0544fa6203cb5b5d335f (diff)
parent982be97c0047d952c148e4c8a3803ad3ceafff39 (diff)
downloadsystemd-38edb7674bc22551f7c7ac010b296406ce25e7f1.tar.gz
systemd-38edb7674bc22551f7c7ac010b296406ce25e7f1.tar.bz2
systemd-38edb7674bc22551f7c7ac010b296406ce25e7f1.zip
Merge pull request #7582 from pfl/dhcp6_prefix_delegation
DHCPv6 prefix delegation
Diffstat (limited to 'src/libsystemd-network/sd-radv.c')
-rw-r--r--src/libsystemd-network/sd-radv.c97
1 files changed, 88 insertions, 9 deletions
diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c
index f6c984f011..f30d6164ea 100644
--- a/src/libsystemd-network/sd-radv.c
+++ b/src/libsystemd-network/sd-radv.c
@@ -168,6 +168,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;
@@ -197,6 +203,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++;
@@ -445,9 +463,6 @@ _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
assert_return(ra, -EINVAL);
assert_return(mtu >= 1280, -EINVAL);
- if (ra->state != SD_RADV_STATE_IDLE)
- return -EBUSY;
-
ra->mtu = mtu;
return 0;
@@ -517,9 +532,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);
@@ -527,7 +546,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,12 +556,15 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
_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);
@@ -559,11 +580,69 @@ _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;
}
+_public_ sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra,
+ struct in6_addr *prefix,
+ uint8_t prefixlen) {
+ sd_radv_prefix *cur, *next;
+
+ assert_return(ra, NULL);
+ assert_return(prefix, NULL);
+
+ LIST_FOREACH_SAFE(prefix, cur, next, ra->prefixes) {
+ if (prefixlen != cur->opt.prefixlen)
+ continue;
+
+ if (!in_addr_equal(AF_INET6,
+ (union in_addr_union *)prefix,
+ (union in_addr_union *)&cur->opt.in6_addr))
+ continue;
+
+ LIST_REMOVE(prefix, ra->prefixes, cur);
+ ra->n_prefixes--;
+
+ break;
+ }
+
+ return cur;
+}
+
_public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
const struct in6_addr *dns, size_t n_dns) {
_cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;