sd-radv: allow to send multiple routes or prefix64 that have intersection with others

I cannot find any RFC that states we should not send multiple route
prefix or pref64 options that have intersection with others.
Moreover, each route prefix option has preference field, thus, user may
want to send e.g. a prefix with the normal preference, and another sub
prefix with the high preference. Previously, such configuration was
prohibited. Let's allow that now.
This commit is contained in:
Yu Watanabe
2024-04-24 12:22:05 +09:00
parent 96dd66eddf
commit 9dc2503539
+12 -46
View File
@@ -702,35 +702,17 @@ void sd_radv_remove_prefix(
int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
sd_radv_route_prefix *found = NULL;
int r;
assert_return(ra, -EINVAL);
assert_return(p, -EINVAL);
const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen);
LIST_FOREACH(prefix, cur, ra->route_prefixes) {
r = in_addr_prefix_intersect(AF_INET6,
(const union in_addr_union*) &cur->opt.in6_addr,
cur->opt.prefixlen,
(const union in_addr_union*) &p->opt.in6_addr,
p->opt.prefixlen);
if (r < 0)
return r;
if (r == 0)
continue;
if (cur->opt.prefixlen == p->opt.prefixlen) {
LIST_FOREACH(prefix, cur, ra->route_prefixes)
if (cur->opt.prefixlen == p->opt.prefixlen &&
in6_addr_equal(&cur->opt.in6_addr, &p->opt.in6_addr)) {
found = cur;
break;
}
return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
"IPv6 route prefix %s conflicts with %s, ignoring.",
addr_p,
IN6_ADDR_PREFIX_TO_STRING(&cur->opt.in6_addr, cur->opt.prefixlen));
}
if (found) {
/* p and cur may be equivalent. First increment the reference counter. */
sd_radv_route_prefix_ref(p);
@@ -743,7 +725,7 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
LIST_APPEND(prefix, ra->route_prefixes, p);
log_radv(ra, "Updated/replaced IPv6 route prefix %s (lifetime: %s)",
strna(addr_p),
IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen),
FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
} else {
/* The route prefix is new. Let's simply add it. */
@@ -752,7 +734,8 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
LIST_APPEND(prefix, ra->route_prefixes, p);
ra->n_route_prefixes++;
log_radv(ra, "Added route prefix %s", strna(addr_p));
log_radv(ra, "Added route prefix %s",
IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen));
}
return 0;
@@ -760,35 +743,17 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
sd_radv_pref64_prefix *found = NULL;
int r;
assert_return(ra, -EINVAL);
assert_return(p, -EINVAL);
const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen);
LIST_FOREACH(prefix, cur, ra->pref64_prefixes) {
r = in_addr_prefix_intersect(AF_INET6,
(const union in_addr_union*) &cur->in6_addr,
cur->prefixlen,
(const union in_addr_union*) &p->in6_addr,
p->prefixlen);
if (r < 0)
return r;
if (r == 0)
continue;
if (cur->prefixlen == p->prefixlen) {
LIST_FOREACH(prefix, cur, ra->pref64_prefixes)
if (cur->prefixlen == p->prefixlen &&
in6_addr_equal(&cur->in6_addr, &p->in6_addr)) {
found = cur;
break;
}
return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
"IPv6 PREF64 prefix %s conflicts with %s, ignoring.",
addr_p,
IN6_ADDR_PREFIX_TO_STRING(&cur->in6_addr, cur->prefixlen));
}
if (found) {
/* p and cur may be equivalent. First increment the reference counter. */
sd_radv_pref64_prefix_ref(p);
@@ -801,7 +766,7 @@ int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
LIST_APPEND(prefix, ra->pref64_prefixes, p);
log_radv(ra, "Updated/replaced IPv6 PREF64 prefix %s (lifetime: %s)",
strna(addr_p),
IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen),
FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
} else {
/* The route prefix is new. Let's simply add it. */
@@ -810,7 +775,8 @@ int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
LIST_APPEND(prefix, ra->pref64_prefixes, p);
ra->n_pref64_prefixes++;
log_radv(ra, "Added PREF64 prefix %s", strna(addr_p));
log_radv(ra, "Added PREF64 prefix %s",
IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen));
}
return 0;