]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: do not drop duplicated entries in loop
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 14 May 2025 21:36:55 +0000 (06:36 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 28 May 2025 18:16:16 +0000 (19:16 +0100)
Fixes #37456.

(cherry picked from commit 6a4fe38f7fed6b1a94caad49c5aa3dd102658df4)
(cherry picked from commit 936cba12c9ab098948b996723cde42b613343f8c)

src/network/networkd-address.c
src/network/networkd-neighbor.c
src/network/networkd-nexthop.c

index bc748fc5d7282670d35d81465a17e58179f9f690..00fdb51128ec74a3ae450e2a8e641f1f2d46fbe2 100644 (file)
@@ -2606,16 +2606,22 @@ int address_section_verify(Address *address) {
         return 0;
 }
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+        trivial_hash_ops_address_detach,
+        void,
+        trivial_hash_func,
+        trivial_compare_func,
+        Address,
+        address_detach);
+
 int network_drop_invalid_addresses(Network *network) {
-        _cleanup_set_free_ Set *addresses = NULL;
+        _cleanup_set_free_ Set *addresses = NULL, *duplicated_addresses = NULL;
         Address *address;
         int r;
 
         assert(network);
 
         ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) {
-                Address *dup;
-
                 if (address_section_verify(address) < 0) {
                         /* Drop invalid [Address] sections or Address= settings in [Network].
                          * Note that address_detach() will drop the address from addresses_by_section. */
@@ -2624,7 +2630,7 @@ int network_drop_invalid_addresses(Network *network) {
                 }
 
                 /* Always use the setting specified later. So, remove the previously assigned setting. */
-                dup = set_remove(addresses, address);
+                Address *dup = set_remove(addresses, address);
                 if (dup) {
                         log_warning("%s: Duplicated address %s is specified at line %u and %u, "
                                     "dropping the address setting specified at line %u.",
@@ -2633,8 +2639,12 @@ int network_drop_invalid_addresses(Network *network) {
                                     address->section->line,
                                     dup->section->line, dup->section->line);
 
-                        /* address_detach() will drop the address from addresses_by_section. */
-                        address_detach(dup);
+                        /* Do not call address_detach() for 'dup' now, as we can remove only the current
+                         * entry in the loop. We will drop the address from addresses_by_section later. */
+                        r = set_ensure_put(&duplicated_addresses, &trivial_hash_ops_address_detach, dup);
+                        if (r < 0)
+                                return log_oom();
+                        assert(r > 0);
                 }
 
                 /* Use address_hash_ops, instead of address_hash_ops_detach. Otherwise, the Address objects
index 6b81950f96c6323fadf0663461daf394b166f851..350b0ff2bebbf974bafd41b5634042ce54c14f93 100644 (file)
@@ -683,8 +683,16 @@ static int neighbor_section_verify(Neighbor *neighbor) {
         return 0;
 }
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+        trivial_hash_ops_neighbor_detach,
+        void,
+        trivial_hash_func,
+        trivial_compare_func,
+        Neighbor,
+        neighbor_detach);
+
 int network_drop_invalid_neighbors(Network *network) {
-        _cleanup_set_free_ Set *neighbors = NULL;
+        _cleanup_set_free_ Set *neighbors = NULL, *duplicated_neighbors = NULL;
         Neighbor *neighbor;
         int r;
 
@@ -709,8 +717,13 @@ int network_drop_invalid_neighbors(Network *network) {
                                     IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
                                     neighbor->section->line,
                                     dup->section->line, dup->section->line);
-                        /* neighbor_detach() will drop the neighbor from neighbors_by_section. */
-                        neighbor_detach(dup);
+
+                        /* Do not call nexthop_detach() for 'dup' now, as we can remove only the current
+                         * entry in the loop. We will drop the nexthop from nexthops_by_section later. */
+                        r = set_ensure_put(&duplicated_neighbors, &trivial_hash_ops_neighbor_detach, dup);
+                        if (r < 0)
+                                return log_oom();
+                        assert(r > 0);
                 }
 
                 /* Use neighbor_hash_ops, instead of neighbor_hash_ops_detach. Otherwise, the Neighbor objects
index 1b44ef320c9dfaff2d08a0df3d51b67bcce37091..51b7b83f49d310eb1cda1d7ae30ccb6db9d78783 100644 (file)
@@ -1200,6 +1200,7 @@ static int nexthop_section_verify(NextHop *nh) {
 
 int network_drop_invalid_nexthops(Network *network) {
         _cleanup_hashmap_free_ Hashmap *nexthops = NULL;
+        _cleanup_set_free_ Set *duplicated_nexthops = NULL;
         NextHop *nh;
         int r;
 
@@ -1222,8 +1223,13 @@ int network_drop_invalid_nexthops(Network *network) {
                                     dup->section->filename,
                                     nh->id, nh->section->line,
                                     dup->section->line, dup->section->line);
-                        /* nexthop_detach() will drop the nexthop from nexthops_by_section. */
-                        nexthop_detach(dup);
+
+                        /* Do not call nexthop_detach() for 'dup' now, as we can remove only the current
+                         * entry in the loop. We will drop the nexthop from nexthops_by_section later. */
+                        r = set_ensure_put(&duplicated_nexthops, &nexthop_hash_ops, dup);
+                        if (r < 0)
+                                return log_oom();
+                        assert(r > 0);
                 }
 
                 r = hashmap_ensure_put(&nexthops, NULL, UINT32_TO_PTR(nh->id), nh);