]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-radv: allow to send multiple routes or prefix64 that have intersection with others
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 23 Apr 2024 04:09:52 +0000 (13:09 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 24 Apr 2024 03:22:05 +0000 (12:22 +0900)
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.

src/libsystemd-network/sd-radv.c

index fa15f96336ebd447dde4a0b3664a2c1494b34ecb..6dc4f9be29b2ce1da7cf79d5617f8a8c7461c7f4 100644 (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;