]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #21037 from yuwata/network-dhcp6-pd-simplify-distribute
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 19 Oct 2021 07:24:38 +0000 (09:24 +0200)
committerGitHub <noreply@github.com>
Tue, 19 Oct 2021 07:24:38 +0000 (09:24 +0200)
network: dhcp6-pd: simplify dhcp6_pd_prefix_distribute()

1  2 
src/network/networkd-dhcp6.c

index fdf4ba5e1e8a57cd6906fb5992c7bc5cf8299b90,ccd6b65f29aa500fc55011abc42e7e51265d707d..6ec178f35404f9a0fff70e8b3199af520c277d48
@@@ -56,62 -56,64 +56,62 @@@ static bool dhcp6_lease_has_pd_prefix(s
          return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred, &lifetime_valid) >= 0;
  }
  
 -static int dhcp6_pd_get_link_by_prefix(Manager *manager, const struct in6_addr *prefix, Link **ret) {
 -        union in_addr_union u;
 -        Link *link;
 +static void link_remove_dhcp6_pd_prefix(Link *link, const struct in6_addr *prefix) {
 +        void *key;
  
 -        assert(manager);
 +        assert(link);
 +        assert(link->manager);
          assert(prefix);
  
 -        u.in6 = *prefix;
 +        if (hashmap_get(link->manager->links_by_dhcp6_pd_prefix, prefix) != link)
 +                return;
  
 -        HASHMAP_FOREACH(link, manager->links_by_index) {
 -                if (!link_dhcp6_pd_is_enabled(link))
 -                        continue;
 +        hashmap_remove2(link->manager->links_by_dhcp6_pd_prefix, prefix, &key);
 +        free(key);
 +}
  
 -                if (link->network->dhcp6_pd_assign) {
 -                        Address *address;
 +static int link_add_dhcp6_pd_prefix(Link *link, const struct in6_addr *prefix) {
 +        _cleanup_free_ struct in6_addr *copy = NULL;
 +        int r;
  
 -                        SET_FOREACH(address, link->addresses) {
 -                                if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
 -                                        continue;
 -                                assert(address->family == AF_INET6);
 +        assert(link);
 +        assert(prefix);
  
 -                                if (in_addr_prefix_covers(AF_INET6, &u, 64, &address->in_addr) > 0) {
 -                                        if (ret)
 -                                                *ret = link;
 -                                        return 0;
 -                                }
 -                        }
 -                } else {
 -                        Route *route;
 -
 -                        SET_FOREACH(route, link->routes) {
 -                                if (route->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
 -                                        continue;
 -                                assert(route->family == AF_INET6);
 -
 -                                if (in6_addr_equal(&route->dst.in6, prefix)) {
 -                                        if (ret)
 -                                                *ret = link;
 -                                        return 0;
 -                                }
 -                        }
 -                }
 -        }
 +        copy = newdup(struct in6_addr, prefix, 1);
 +        if (!copy)
 +                return -ENOMEM;
  
 -        return -ENOENT;
 +        r = hashmap_ensure_put(&link->manager->links_by_dhcp6_pd_prefix, &in6_addr_hash_ops_free, copy, link);
 +        if (r < 0)
 +                return r;
 +        if (r > 0)
 +                TAKE_PTR(copy);
 +
 +        return 0;
  }
  
 -static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret) {
 -        union in_addr_union u;
 +static int link_get_by_dhcp6_pd_prefix(Manager *manager, const struct in6_addr *prefix, Link **ret) {
 +        Link *link;
  
 +        assert(manager);
 +        assert(prefix);
 +
 +        link = hashmap_get(manager->links_by_dhcp6_pd_prefix, prefix);
 +        if (!link)
 +                return -ENODEV;
 +
 +        if (ret)
 +                *ret = link;
 +        return 0;
 +}
 +
 +static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret) {
          assert(link);
          assert(pd_prefix);
  
          if (!link_dhcp6_pd_is_enabled(link))
                  return -ENOENT;
  
 -        u.in6 = *pd_prefix;
 -
          if (link->network->dhcp6_pd_assign) {
                  Address *address;
  
                                  continue;
                          assert(address->family == AF_INET6);
  
 -                        if (in_addr_prefix_covers(AF_INET6, &u, pd_prefix_len, &address->in_addr) <= 0)
 +                        if (in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &address->in_addr.in6) <= 0)
                                  continue;
  
                          if (ret) {
 -                                union in_addr_union prefix = address->in_addr;
 +                                struct in6_addr prefix = address->in_addr.in6;
  
 -                                in_addr_mask(AF_INET6, &prefix, 64);
 -                                *ret = prefix.in6;
 +                                in6_addr_mask(&prefix, 64);
 +                                *ret = prefix;
                          }
                          return 0;
                  }
                                  continue;
                          assert(route->family == AF_INET6);
  
 -                        if (in_addr_prefix_covers(AF_INET6, &u, pd_prefix_len, &route->dst) > 0) {
 +                        if (in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &route->dst.in6) > 0) {
                                  if (ret)
                                          *ret = route->dst.in6;
                                  return 0;
@@@ -173,8 -175,6 +173,8 @@@ int dhcp6_pd_remove(Link *link, bool on
                  if (link->radv)
                          (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
  
 +                link_remove_dhcp6_pd_prefix(link, &route->dst.in6);
 +
                  k = route_remove(route);
                  if (k < 0)
                          r = k;
          }
  
          SET_FOREACH(address, link->addresses) {
 +                struct in6_addr prefix;
 +
                  if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
                          continue;
                  if (only_marked && !address_is_marked(address))
                          continue;
  
 -                if (link->radv) {
 -                        union in_addr_union prefix = address->in_addr;
 +                prefix = address->in_addr.in6;
 +                in6_addr_mask(&prefix, 64);
  
 -                        in_addr_mask(AF_INET6, &prefix, 64);
 -                        (void) sd_radv_remove_prefix(link->radv, &prefix.in6, 64);
 -                }
 +                if (link->radv)
 +                        (void) sd_radv_remove_prefix(link->radv, &prefix, 64);
 +
 +                link_remove_dhcp6_pd_prefix(link, &prefix);
  
                  k = address_remove(address);
                  if (k < 0)
@@@ -224,37 -221,33 +224,37 @@@ static int dhcp6_pd_address_ready_callb
  }
  
  static int dhcp6_pd_check_ready(Link *link) {
 -        bool has_ready = false;
 -        Address *address;
          int r;
  
          assert(link);
 +        assert(link->network);
  
          if (link->dhcp6_pd_messages > 0) {
                  log_link_debug(link, "%s(): DHCPv6PD addresses and routes are not set.", __func__);
                  return 0;
          }
  
 -        SET_FOREACH(address, link->addresses) {
 -                if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
 -                        continue;
 -                if (address_is_ready(address)) {
 -                        has_ready = true;
 -                        break;
 +        if (link->network->dhcp6_pd_assign) {
 +                bool has_ready = false;
 +                Address *address;
 +
 +                SET_FOREACH(address, link->addresses) {
 +                        if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
 +                                continue;
 +                        if (address_is_ready(address)) {
 +                                has_ready = true;
 +                                break;
 +                        }
                  }
 -        }
  
 -        if (!has_ready) {
 -                SET_FOREACH(address, link->addresses)
 -                        if (address->source == NETWORK_CONFIG_SOURCE_DHCP6PD)
 -                                address->callback = dhcp6_pd_address_ready_callback;
 +                if (!has_ready) {
 +                        SET_FOREACH(address, link->addresses)
 +                                if (address->source == NETWORK_CONFIG_SOURCE_DHCP6PD)
 +                                        address->callback = dhcp6_pd_address_ready_callback;
  
 -                log_link_debug(link, "%s(): no DHCPv6PD address is ready.", __func__);
 -                return 0;
 +                        log_link_debug(link, "%s(): no DHCPv6PD address is ready.", __func__);
 +                        return 0;
 +                }
          }
  
          link->dhcp6_pd_configured = true;
@@@ -443,7 -436,7 +443,7 @@@ static int dhcp6_pd_assign_prefix
          if (r < 0)
                  return r;
  
 -        return 0;
 +        return link_add_dhcp6_pd_prefix(link, prefix);
  }
  
  static bool link_has_preferred_subnet_id(Link *link) {
@@@ -490,9 -483,9 +490,9 @@@ static int dhcp6_get_preferred_delegate
  
                  /* Verify that the prefix we did calculate fits in the pd prefix.
                   * This should not fail as we checked the prefix size beforehand */
 -                assert_se(in_addr_prefix_covers(AF_INET6, (const union in_addr_union*) pd_prefix, pd_prefix_len, &prefix) > 0);
 +                assert_se(in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &prefix.in6) > 0);
  
 -                if (dhcp6_pd_get_link_by_prefix(link->manager, &prefix.in6, &assigned_link) >= 0 &&
 +                if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix.in6, &assigned_link) >= 0 &&
                      assigned_link != link) {
                          _cleanup_free_ char *assigned_buf = NULL;
  
          for (uint64_t n = 0; n < n_prefixes; n++) {
                  /* If we do not have an allocation preference just iterate
                   * through the address space and return the first free prefix. */
 -                if (dhcp6_pd_get_link_by_prefix(link->manager, &prefix.in6, &assigned_link) < 0 ||
 +                if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix.in6, &assigned_link) < 0 ||
                      assigned_link == link) {
                          *ret = prefix.in6;
                          return 0;
@@@ -555,28 -548,22 +555,22 @@@ static int dhcp6_pd_prefix_distribute
                  if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
                          continue;
  
-                 r = dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix);
-                 if (r < 0) {
-                         r = dhcp6_get_preferred_delegated_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix);
-                         if (r < 0)
-                                 continue;
-                 }
+                 if (dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0 &&
+                     dhcp6_get_preferred_delegated_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0)
+                         continue;
  
                  (void) in6_addr_prefix_to_string(&assigned_prefix, 64, &buf);
-                 if (link == dhcp6_link) {
-                         r = dhcp6_pd_request_address(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
-                         if (r < 0)
-                                 return log_link_warning_errno(link, r, "Failed to assign addresses in prefix %s: %m", strna(buf));
-                         log_link_debug(link, "Assigned addresses in prefix %s: %m", strna(buf));
-                 } else {
-                         r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
-                         if (r < 0) {
-                                 log_link_error_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf));
-                                 link_enter_failed(link);
-                         } else
-                                 log_link_debug(link, "Assigned prefix %s", strna(buf));
+                 r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
+                 if (r < 0) {
+                         log_link_warning_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf));
+                         if (link == dhcp6_link)
+                                 return r;
+                         link_enter_failed(link);
+                         continue;
                  }
+                 log_link_debug(link, "Assigned prefix %s", strna(buf));
          }
  
          return 0;
@@@ -850,6 -837,7 +844,6 @@@ static int dhcp6_pd_prefix_acquired(Lin
          for (sd_dhcp6_lease_reset_pd_prefix_iter(dhcp6_link->dhcp6_lease);;) {
                  uint32_t lifetime_preferred, lifetime_valid;
                  struct in6_addr pd_prefix;
 -                union in_addr_union prefix;
                  uint8_t pd_prefix_len;
  
                  r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix, &pd_prefix_len,
  
                  assert(pd_prefix_len <= 64);
  
 -                prefix.in6 = pd_prefix;
 -                r = in_addr_mask(AF_INET6, &prefix, pd_prefix_len);
 +                /* Mask prefix for safety. */
 +                r = in6_addr_mask(&pd_prefix, pd_prefix_len);
                  if (r < 0)
                          return log_link_error_errno(dhcp6_link, r, "Failed to mask DHCPv6 PD prefix: %m");
  
                          uint64_t n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
                          _cleanup_free_ char *buf = NULL;
  
 -                        (void) in6_addr_prefix_to_string(&prefix.in6, pd_prefix_len, &buf);
 +                        (void) in6_addr_prefix_to_string(&pd_prefix, pd_prefix_len, &buf);
                          log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s",
                                         n_prefixes, strna(buf));
                  }
  
                  r = dhcp6_pd_prefix_distribute(dhcp6_link,
 -                                               &prefix.in6,
 +                                               &pd_prefix,
                                                 pd_prefix_len,
                                                 lifetime_preferred,
                                                 lifetime_valid,
                          return r;
  
                  r = dhcp6_pd_prefix_distribute(dhcp6_link,
 -                                               &prefix.in6,
 +                                               &pd_prefix,
                                                 pd_prefix_len,
                                                 lifetime_preferred,
                                                 lifetime_valid,