]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/neighbor: introduce ref/unref function for Neighbor object
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 2 Jan 2024 19:41:20 +0000 (04:41 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 3 Jan 2024 19:58:36 +0000 (04:58 +0900)
src/network/networkd-neighbor.c
src/network/networkd-neighbor.h
src/network/networkd-network.c

index e172c564b006d852fe80fefc40918de187cb745f..ac4682ab18f3d32bcbb18b8abb1bb4ac32d0e5a5 100644 (file)
 #include "networkd-queue.h"
 #include "set.h"
 
-Neighbor *neighbor_free(Neighbor *neighbor) {
-        if (!neighbor)
-                return NULL;
+static Neighbor* neighbor_detach_impl(Neighbor *neighbor) {
+        assert(neighbor);
+        assert(!neighbor->link || !neighbor->network);
 
         if (neighbor->network) {
                 assert(neighbor->section);
                 ordered_hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
+                neighbor->network = NULL;
+                return neighbor;
         }
 
-        config_section_free(neighbor->section);
-
-        if (neighbor->link)
+        if (neighbor->link) {
                 set_remove(neighbor->link->neighbors, neighbor);
+                neighbor->link = NULL;
+                return neighbor;
+        }
+
+        return NULL;
+}
 
+static void neighbor_detach(Neighbor *neighbor) {
+        neighbor_unref(neighbor_detach_impl(neighbor));
+}
+
+static Neighbor* neighbor_free(Neighbor *neighbor) {
+        if (!neighbor)
+                return NULL;
+
+        neighbor_detach_impl(neighbor);
+
+        config_section_free(neighbor->section);
         return mfree(neighbor);
 }
 
-DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor, neighbor_free);
+DEFINE_TRIVIAL_REF_UNREF_FUNC(Neighbor, neighbor, neighbor_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor, neighbor_unref);
+
+static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state);
+static int neighbor_compare_func(const Neighbor *a, const Neighbor *b);
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+        neighbor_hash_ops_detach,
+        Neighbor,
+        neighbor_hash_func,
+        neighbor_compare_func,
+        neighbor_detach);
+
+DEFINE_PRIVATE_HASH_OPS(
+        neighbor_hash_ops,
+        Neighbor,
+        neighbor_hash_func,
+        neighbor_compare_func);
+
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+        neighbor_section_hash_ops,
+        ConfigSection,
+        config_section_hash_func,
+        config_section_compare_func,
+        Neighbor,
+        neighbor_detach);
+
+static int neighbor_new(Neighbor **ret) {
+        Neighbor *neighbor;
+
+        assert(ret);
+
+        neighbor = new(Neighbor, 1);
+        if (!neighbor)
+                return -ENOMEM;
+
+        *neighbor = (Neighbor) {
+                .n_ref = 1,
+        };
+
+        *ret = TAKE_PTR(neighbor);
+        return 0;
+}
 
 static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
         _cleanup_(config_section_freep) ConfigSection *n = NULL;
-        _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
+        _cleanup_(neighbor_unrefp) Neighbor *neighbor = NULL;
         int r;
 
         assert(network);
@@ -49,18 +108,15 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
                 return 0;
         }
 
-        neighbor = new(Neighbor, 1);
-        if (!neighbor)
-                return -ENOMEM;
+        r = neighbor_new(&neighbor);
+        if (r < 0)
+                return r;
 
-        *neighbor = (Neighbor) {
-                .network = network,
-                .family = AF_UNSPEC,
-                .section = TAKE_PTR(n),
-                .source = NETWORK_CONFIG_SOURCE_STATIC,
-        };
+        neighbor->network = network;
+        neighbor->section = TAKE_PTR(n);
+        neighbor->source = NETWORK_CONFIG_SOURCE_STATIC;
 
-        r = ordered_hashmap_ensure_put(&network->neighbors_by_section, &config_section_hash_ops, neighbor->section, neighbor);
+        r = ordered_hashmap_ensure_put(&network->neighbors_by_section, &neighbor_section_hash_ops, neighbor->section, neighbor);
         if (r < 0)
                 return r;
 
@@ -69,7 +125,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
 }
 
 static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
-        _cleanup_(neighbor_freep) Neighbor *dest = NULL;
+        _cleanup_(neighbor_unrefp) Neighbor *dest = NULL;
 
         assert(neighbor);
         assert(ret);
@@ -78,7 +134,8 @@ static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
         if (!dest)
                 return -ENOMEM;
 
-        /* Unset all pointers */
+        /* Clear the reference counter and all pointers */
+        dest->n_ref = 1;
         dest->link = NULL;
         dest->network = NULL;
         dest->section = NULL;
@@ -115,19 +172,6 @@ static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
         return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
 }
 
-DEFINE_PRIVATE_HASH_OPS(
-        neighbor_hash_ops,
-        Neighbor,
-        neighbor_hash_func,
-        neighbor_compare_func);
-
-DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
-        neighbor_hash_ops_free,
-        Neighbor,
-        neighbor_hash_func,
-        neighbor_compare_func,
-        neighbor_free);
-
 static int neighbor_get_request(Link *link, const Neighbor *neighbor, Request **ret) {
         Request *req;
 
@@ -167,19 +211,21 @@ static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
         return 0;
 }
 
-static int neighbor_add(Link *link, Neighbor *neighbor) {
+static int neighbor_attach(Link *link, Neighbor *neighbor) {
         int r;
 
         assert(link);
         assert(neighbor);
+        assert(!neighbor->link);
 
-        r = set_ensure_put(&link->neighbors, &neighbor_hash_ops_free, neighbor);
+        r = set_ensure_put(&link->neighbors, &neighbor_hash_ops_detach, neighbor);
         if (r < 0)
                 return r;
         if (r == 0)
                 return -EEXIST;
 
         neighbor->link = link;
+        neighbor_ref(neighbor);
         return 0;
 }
 
@@ -279,7 +325,7 @@ static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_messag
 }
 
 static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
-        _cleanup_(neighbor_freep) Neighbor *tmp = NULL;
+        _cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
         Neighbor *existing = NULL;
         int r;
 
@@ -308,7 +354,7 @@ static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
         log_neighbor_debug(tmp, "Requesting", link);
         r = link_queue_request_safe(link, REQUEST_TYPE_NEIGHBOR,
                                     tmp,
-                                    neighbor_free,
+                                    neighbor_unref,
                                     neighbor_hash_func,
                                     neighbor_compare_func,
                                     neighbor_process_request,
@@ -477,7 +523,7 @@ void link_foreignize_neighbors(Link *link) {
 }
 
 int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
-        _cleanup_(neighbor_freep) Neighbor *tmp = NULL;
+        _cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
         Neighbor *neighbor = NULL;
         Request *req = NULL;
         uint16_t type, state;
@@ -529,8 +575,8 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
                  * kernel sends messages about neighbors after a link is removed. So, just ignore it. */
                 return 0;
 
-        tmp = new0(Neighbor, 1);
-        if (!tmp)
+        r = neighbor_new(&tmp);
+        if (r < 0)
                 return log_oom();
 
         /* First, retrieve the fundamental information about the neighbor. */
@@ -560,7 +606,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
                 if (neighbor) {
                         neighbor_enter_removed(neighbor);
                         log_neighbor_debug(neighbor, "Forgetting removed", link);
-                        neighbor_free(neighbor);
+                        neighbor_detach(neighbor);
                 } else
                         log_neighbor_debug(tmp, "Kernel removed unknown", link);
 
@@ -572,12 +618,12 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
 
         /* If we did not know the neighbor, then save it. */
         if (!neighbor) {
-                r = neighbor_add(link, tmp);
+                r = neighbor_attach(link, tmp);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Failed to save received neighbor, ignoring: %m");
                         return 0;
                 }
-                neighbor = TAKE_PTR(tmp);
+                neighbor = tmp;
                 is_new = true;
         }
 
@@ -638,9 +684,9 @@ int network_drop_invalid_neighbors(Network *network) {
                 Neighbor *dup;
 
                 if (neighbor_section_verify(neighbor) < 0) {
-                        /* Drop invalid [Neighbor] sections. Note that neighbor_free() will drop the
+                        /* Drop invalid [Neighbor] sections. Note that neighbor_detach() will drop the
                          * neighbor from neighbors_by_section. */
-                        neighbor_free(neighbor);
+                        neighbor_detach(neighbor);
                         continue;
                 }
 
@@ -653,12 +699,12 @@ 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_free() will drop the neighbor from neighbors_by_section. */
-                        neighbor_free(dup);
+                        /* neighbor_detach() will drop the neighbor from neighbors_by_section. */
+                        neighbor_detach(dup);
                 }
 
-                /* Use neighbor_hash_ops, instead of neighbor_hash_ops_free. Otherwise, the Neighbor objects
-                 * will be freed. */
+                /* Use neighbor_hash_ops, instead of neighbor_hash_ops_detach. Otherwise, the Neighbor objects
+                 * will be detached. */
                 r = set_ensure_put(&neighbors, &neighbor_hash_ops, neighbor);
                 if (r < 0)
                         return log_oom();
@@ -681,7 +727,7 @@ int config_parse_neighbor_address(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
+        _cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
         Network *network = ASSERT_PTR(userdata);
         int r;
 
@@ -724,7 +770,7 @@ int config_parse_neighbor_lladdr(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
+        _cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
         Network *network = ASSERT_PTR(userdata);
         int r;
 
index 683a310b3f34e09d6cdb32a54d6f2a6c5ff0e9c9..4a5503ca13f6f1cff4bbed78e996c14db12adaf9 100644 (file)
@@ -21,12 +21,15 @@ typedef struct Neighbor {
         NetworkConfigSource source;
         NetworkConfigState state;
 
+        unsigned n_ref;
+
         int family;
         union in_addr_union in_addr;
         struct hw_addr_data ll_addr;
 } Neighbor;
 
-Neighbor *neighbor_free(Neighbor *neighbor);
+Neighbor* neighbor_ref(Neighbor *neighbor);
+Neighbor* neighbor_unref(Neighbor *neighbor);
 
 int network_drop_invalid_neighbors(Network *network);
 
index 591b4093cc38f37797592083a291716da302eb36..51f5cacc140628d79368b4f1ea09a1e0fe36f83b 100644 (file)
@@ -787,7 +787,7 @@ static Network *network_free(Network *network) {
         ordered_hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
         hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
         hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
-        ordered_hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
+        ordered_hashmap_free(network->neighbors_by_section);
         hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
         hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
         hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);