]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/route: introduce ref/unref functions for Route object
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 7 Jan 2024 06:16:03 +0000 (15:16 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 25 Jan 2024 07:43:44 +0000 (16:43 +0900)
Then, Route object can live if it is detached from the owner (Manager,
Network, or Wireguard object).

This is the one for routes of ebd96906477aac2bbc6b9de0d6e9bd0f39db5581.

src/network/netdev/wireguard.c
src/network/networkd-dhcp-prefix-delegation.c
src/network/networkd-dhcp4.c
src/network/networkd-ndisc.c
src/network/networkd-network.c
src/network/networkd-route-metric.c
src/network/networkd-route-nexthop.c
src/network/networkd-route.c
src/network/networkd-route.h

index 0195dce1bf04c6654623661621e869dcb4b541ca..95c9c8c330093d5e20f666b49d9184c9f937b5b8 100644 (file)
@@ -1190,7 +1190,7 @@ static int wireguard_verify(NetDev *netdev, const char *filename) {
                         continue;
 
                 LIST_FOREACH(ipmasks, ipmask, peer->ipmasks) {
-                        _cleanup_(route_freep) Route *route = NULL;
+                        _cleanup_(route_unrefp) Route *route = NULL;
 
                         r = route_new(&route);
                         if (r < 0)
index d8f9a2c053c38bf8e37e46d0e41dacf418bc5eac..61295d9ce6458b7c57a847d7b4482cd096232918 100644 (file)
@@ -282,7 +282,7 @@ static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
 }
 
 static int dhcp_pd_request_route(Link *link, const struct in6_addr *prefix, usec_t lifetime_usec) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         Route *existing;
         int r;
 
@@ -670,7 +670,7 @@ static int dhcp_request_unreachable_route(
                 route_netlink_handler_t callback,
                 bool *configured) {
 
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         Route *existing;
         int r;
 
@@ -781,7 +781,7 @@ static int dhcp_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_t
 }
 
 static int dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link *link, const struct in_addr *br_address, usec_t lifetime_usec) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         Route *existing;
         int r;
 
index 1a1836cf6669e290bc7455e3ede6f6352fa92986..f9baf0d535675c7420bcf04d852dd6e3b46f9526 100644 (file)
@@ -410,7 +410,7 @@ static bool link_prefixroute(Link *link) {
 }
 
 static int dhcp4_request_prefix_route(Link *link) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         int r;
 
         assert(link);
@@ -438,7 +438,7 @@ static int dhcp4_request_prefix_route(Link *link) {
 }
 
 static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         struct in_addr address;
         int r;
 
@@ -556,7 +556,7 @@ static int dhcp4_request_classless_static_or_static_routes(Link *link) {
                 return r;
 
         FOREACH_ARRAY(e, routes, n_routes) {
-                _cleanup_(route_freep) Route *route = NULL;
+                _cleanup_(route_unrefp) Route *route = NULL;
                 struct in_addr gw;
 
                 r = route_new(&route);
@@ -584,7 +584,7 @@ static int dhcp4_request_classless_static_or_static_routes(Link *link) {
 }
 
 static int dhcp4_request_default_gateway(Link *link) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         struct in_addr address, router;
         int r;
 
@@ -639,7 +639,7 @@ static int dhcp4_request_semi_static_routes(Link *link) {
         assert(link->network);
 
         HASHMAP_FOREACH(rt, link->network->routes_by_section) {
-                _cleanup_(route_freep) Route *route = NULL;
+                _cleanup_(route_unrefp) Route *route = NULL;
                 struct in_addr gw;
 
                 if (!rt->gateway_from_dhcp_or_ra)
@@ -690,7 +690,7 @@ static int dhcp4_request_routes_to_servers(
         assert(servers || n_servers == 0);
 
         FOREACH_ARRAY(dst, servers, n_servers) {
-                _cleanup_(route_freep) Route *route = NULL;
+                _cleanup_(route_unrefp) Route *route = NULL;
                 struct in_addr gw;
 
                 if (in4_addr_is_null(dst))
index 488c8c02948a9ed443c7b8fe9b383e6491917d0b..7a67c552993a5aaf8a998f11e0f824fbee9378a6 100644 (file)
@@ -316,7 +316,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
                 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
 
         if (link->network->ipv6_accept_ra_use_gateway) {
-                _cleanup_(route_freep) Route *route = NULL;
+                _cleanup_(route_unrefp) Route *route = NULL;
 
                 r = route_new(&route);
                 if (r < 0)
@@ -335,7 +335,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
 
         Route *route_gw;
         HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
-                _cleanup_(route_freep) Route *route = NULL;
+                _cleanup_(route_unrefp) Route *route = NULL;
 
                 if (!route_gw->gateway_from_dhcp_or_ra)
                         continue;
@@ -498,7 +498,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
 }
 
 static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         unsigned prefixlen, preference;
         usec_t lifetime_usec;
         struct in6_addr prefix;
@@ -600,7 +600,7 @@ static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
 }
 
 static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         unsigned preference, prefixlen;
         struct in6_addr gateway, dst;
         usec_t lifetime_usec;
index 16c679b34388e640106c9b2c05f1884f709c6826..300fba5dd9968be7987864fd4478befe11b0376e 100644 (file)
@@ -188,7 +188,7 @@ int network_verify(Network *network) {
                                     network->filename);
 
                 network->addresses_by_section = ordered_hashmap_free(network->addresses_by_section);
-                network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
+                network->routes_by_section = hashmap_free(network->routes_by_section);
         }
 
         if (network->link_local < 0) {
@@ -782,7 +782,7 @@ static Network *network_free(Network *network) {
         /* static configs */
         set_free_free(network->ipv6_proxy_ndp_addresses);
         ordered_hashmap_free(network->addresses_by_section);
-        hashmap_free_with_destructor(network->routes_by_section, route_free);
+        hashmap_free(network->routes_by_section);
         ordered_hashmap_free(network->nexthops_by_section);
         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);
index b27b3c12948e81220e17e0ff980b453b6a243077..9c417a4fc4f26ed76b96ff8e9bb72eaefce01752 100644 (file)
@@ -374,7 +374,7 @@ static int config_parse_route_metric_boolean_impl(
                         void *userdata) {                               \
                                                                         \
                 Network *network = ASSERT_PTR(userdata);                \
-                _cleanup_(route_free_or_set_invalidp) Route *route = NULL; \
+                _cleanup_(route_unref_or_set_invalidp) Route *route = NULL; \
                 uint16_t attr_type = ltype;                             \
                 int r;                                                  \
                                                                         \
@@ -436,7 +436,7 @@ int config_parse_route_metric_tcp_congestion(
                 void *userdata) {
 
         Network *network = ASSERT_PTR(userdata);
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         assert(filename);
index 5f1da286046456c1215c70a5af671a897c6fed13..8ccd4e66e87e14ccfb442e9c7085ab95b823c890 100644 (file)
@@ -899,7 +899,7 @@ int config_parse_gateway(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         assert(filename);
@@ -986,7 +986,7 @@ int config_parse_route_gateway_onlink(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         assert(filename);
@@ -1026,7 +1026,7 @@ int config_parse_route_nexthop(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         uint32_t id;
         int r;
 
@@ -1079,7 +1079,7 @@ int config_parse_multipath_route(
                 void *userdata) {
 
         _cleanup_(route_nexthop_freep) RouteNextHop *nh = NULL;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         _cleanup_free_ char *word = NULL;
         Network *network = userdata;
         const char *p;
index efb121cb82f44a320a44695280ecc143d9f7c28d..89a96cbda11ceb01d77ed97c8106c6e642752147 100644 (file)
 #include "vrf.h"
 #include "wireguard.h"
 
-Route* route_free(Route *route) {
-        if (!route)
-                return NULL;
+static Route* route_detach_impl(Route *route) {
+        assert(route);
+        assert(!!route->network + !!route->manager + !!route->wireguard <= 1);
 
         if (route->network) {
                 assert(route->section);
                 hashmap_remove(route->network->routes_by_section, route->section);
+                route->network = NULL;
+                return route;
         }
 
-        if (route->manager)
+        if (route->manager) {
                 set_remove(route->manager->routes, route);
+                route->manager = NULL;
+                return route;
+        }
 
-        if (route->wireguard)
+        if (route->wireguard) {
                 set_remove(route->wireguard->routes, route);
+                route->wireguard = NULL;
+                return route;
+        }
+
+        return NULL;
+}
+
+static void route_detach(Route *route) {
+        route_unref(route_detach_impl(route));
+}
+
+static Route* route_free(Route *route) {
+        if (!route)
+                return NULL;
+
+        route_detach_impl(route);
 
         config_section_free(route->section);
         route_nexthops_done(route);
@@ -44,6 +65,8 @@ Route* route_free(Route *route) {
         return mfree(route);
 }
 
+DEFINE_TRIVIAL_REF_UNREF_FUNC(Route, route, route_free);
+
 static void route_hash_func(const Route *route, struct siphash *state) {
         assert(route);
 
@@ -195,16 +218,25 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 Route,
                 route_hash_func,
                 route_compare_func,
-                route_free);
+                route_detach);
+
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+                route_section_hash_ops,
+                ConfigSection,
+                config_section_hash_func,
+                config_section_compare_func,
+                Route,
+                route_detach);
 
 int route_new(Route **ret) {
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
 
         route = new(Route, 1);
         if (!route)
                 return -ENOMEM;
 
         *route = (Route) {
+                .n_ref = 1,
                 .family = AF_UNSPEC,
                 .scope = RT_SCOPE_UNIVERSE,
                 .protocol = RTPROT_UNSPEC,
@@ -221,7 +253,7 @@ int route_new(Route **ret) {
 
 int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
         _cleanup_(config_section_freep) ConfigSection *n = NULL;
-        _cleanup_(route_freep) Route *route = NULL;
+        _cleanup_(route_unrefp) Route *route = NULL;
         int r;
 
         assert(network);
@@ -251,7 +283,7 @@ int route_new_static(Network *network, const char *filename, unsigned section_li
         route->section = TAKE_PTR(n);
         route->source = NETWORK_CONFIG_SOURCE_STATIC;
 
-        r = hashmap_ensure_put(&network->routes_by_section, &config_section_hash_ops, route->section, route);
+        r = hashmap_ensure_put(&network->routes_by_section, &route_section_hash_ops, route->section, route);
         if (r < 0)
                 return r;
 
@@ -259,7 +291,7 @@ int route_new_static(Network *network, const char *filename, unsigned section_li
         return 0;
 }
 
-static int route_add(Manager *manager, Route *route) {
+static int route_attach(Manager *manager, Route *route) {
         int r;
 
         assert(manager);
@@ -334,7 +366,7 @@ static int route_get_request(Manager *manager, const Route *route, Request **ret
 }
 
 int route_dup(const Route *src, const RouteNextHop *nh, Route **ret) {
-        _cleanup_(route_freep) Route *dest = NULL;
+        _cleanup_(route_unrefp) Route *dest = NULL;
         int r;
 
         assert(src);
@@ -344,7 +376,8 @@ int route_dup(const Route *src, const RouteNextHop *nh, Route **ret) {
         if (!dest)
                 return -ENOMEM;
 
-        /* Unset all pointers */
+        /* Unset number of reference and all pointers */
+        dest->n_ref = 1;
         dest->manager = NULL;
         dest->network = NULL;
         dest->wireguard = NULL;
@@ -570,7 +603,8 @@ static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdat
         Route *route = ASSERT_PTR(userdata);
         int r;
 
-        assert(route->manager);
+        if (!route->manager)
+                return 0; /* already detached. */
 
         r = route_remove(route, route->manager);
         if (r < 0) {
@@ -683,7 +717,7 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
 
 static int route_requeue_request(Request *req, Link *link, const Route *route) {
         _unused_ _cleanup_(request_unrefp) Request *req_unref = NULL;
-        _cleanup_(route_freep) Route *tmp = NULL;
+        _cleanup_(route_unrefp) Route *tmp = NULL;
         int r;
 
         assert(req);
@@ -806,7 +840,7 @@ static int link_request_route_one(
                 unsigned *message_counter,
                 route_netlink_handler_t netlink_handler) {
 
-        _cleanup_(route_freep) Route *tmp = NULL;
+        _cleanup_(route_unrefp) Route *tmp = NULL;
         Route *existing = NULL;
         int r;
 
@@ -829,7 +863,7 @@ static int link_request_route_one(
         log_route_debug(tmp, "Requesting", link->manager);
         r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
                                     tmp,
-                                    route_free,
+                                    route_unref,
                                     route_hash_func,
                                     route_compare_func,
                                     route_process_request,
@@ -957,10 +991,9 @@ int link_request_static_routes(Link *link, bool only_ipv4) {
 static int process_route_one(
                 Manager *manager,
                 uint16_t type,
-                Route *in,
+                Route *tmp,
                 const struct rta_cacheinfo *cacheinfo) {
 
-        _cleanup_(route_freep) Route *tmp = in;
         Request *req = NULL;
         Route *route = NULL;
         Link *link = NULL;
@@ -987,13 +1020,13 @@ static int process_route_one(
                         }
 
                         /* If we do not know the route, then save it. */
-                        r = route_add(manager, tmp);
+                        r = route_attach(manager, tmp);
                         if (r < 0) {
                                 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
                                 return 0;
                         }
 
-                        route = TAKE_PTR(tmp);
+                        route = route_ref(tmp);
                         is_new = true;
 
                 } else
@@ -1020,7 +1053,7 @@ static int process_route_one(
                 if (route) {
                         route_enter_removed(route);
                         log_route_debug(route, "Forgetting removed", manager);
-                        route_free(route);
+                        route_detach(route);
                 } else
                         log_route_debug(tmp,
                                         manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
@@ -1047,7 +1080,7 @@ static int process_route_one(
 }
 
 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
-        _cleanup_(route_freep) Route *tmp = NULL;
+        _cleanup_(route_unrefp) Route *tmp = NULL;
         int r;
 
         assert(rtnl);
@@ -1190,17 +1223,17 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
         has_cacheinfo = r >= 0;
 
         if (tmp->family == AF_INET || ordered_set_isempty(tmp->nexthops))
-                return process_route_one(m, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
+                return process_route_one(m, type, tmp, has_cacheinfo ? &cacheinfo : NULL);
 
         RouteNextHop *nh;
         ORDERED_SET_FOREACH(nh, tmp->nexthops) {
-                _cleanup_(route_freep) Route *dup = NULL;
+                _cleanup_(route_unrefp) Route *dup = NULL;
 
                 r = route_dup(tmp, nh, &dup);
                 if (r < 0)
                         return log_oom();
 
-                r = process_route_one(m, type, TAKE_PTR(dup), has_cacheinfo ? &cacheinfo : NULL);
+                r = process_route_one(m, type, dup, has_cacheinfo ? &cacheinfo : NULL);
                 if (r < 0)
                         return r;
         }
@@ -1248,7 +1281,7 @@ static bool route_by_kernel(const Route *route) {
 }
 
 static int link_unmark_route(Link *link, const Route *route, const RouteNextHop *nh) {
-        _cleanup_(route_freep) Route *tmp = NULL;
+        _cleanup_(route_unrefp) Route *tmp = NULL;
         Route *existing;
         int r;
 
@@ -1400,7 +1433,7 @@ int link_foreignize_routes(Link *link) {
 }
 
 int network_add_ipv4ll_route(Network *network) {
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         unsigned section_line;
         int r;
 
@@ -1435,7 +1468,7 @@ int network_add_ipv4ll_route(Network *network) {
 }
 
 int network_add_default_route_on_device(Network *network) {
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         unsigned section_line;
         int r;
 
@@ -1475,7 +1508,7 @@ int config_parse_preferred_src(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         assert(filename);
@@ -1520,7 +1553,7 @@ int config_parse_destination(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         union in_addr_union *buffer;
         unsigned char *prefixlen;
         int r;
@@ -1578,7 +1611,7 @@ int config_parse_route_priority(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         assert(filename);
@@ -1621,7 +1654,7 @@ int config_parse_route_scope(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         assert(filename);
@@ -1663,7 +1696,7 @@ int config_parse_route_table(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         Network *network = userdata;
         int r;
 
@@ -1707,7 +1740,7 @@ int config_parse_ipv6_route_preference(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         r = route_new_static(network, filename, section_line, &route);
@@ -1748,7 +1781,7 @@ int config_parse_route_protocol(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int r;
 
         r = route_new_static(network, filename, section_line, &route);
@@ -1786,7 +1819,7 @@ int config_parse_route_type(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
+        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
         int t, r;
 
         r = route_new_static(network, filename, section_line, &route);
@@ -1871,5 +1904,5 @@ void network_drop_invalid_routes(Network *network) {
 
         HASHMAP_FOREACH(route, network->routes_by_section)
                 if (route_section_verify(route) < 0)
-                        route_free(route);
+                        route_detach(route);
 }
index 51a06dd0f14c0e7e9ee7c78fa5e21f3a5e7ed5ab..004295e5998ebd297ff03b7775f86b0b629659ed 100644 (file)
@@ -35,6 +35,8 @@ struct Route {
         NetworkConfigState state;
         union in_addr_union provider; /* DHCP server or router address */
 
+        unsigned n_ref;
+
         /* rtmsg header */
         int family;
         unsigned char dst_prefixlen;
@@ -80,8 +82,9 @@ struct Route {
 
 extern const struct hash_ops route_hash_ops;
 
-Route* route_free(Route *route);
-DEFINE_SECTION_CLEANUP_FUNCTIONS(Route, route_free);
+Route* route_ref(Route *route);
+Route* route_unref(Route *route);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Route, route_unref);
 
 int route_new(Route **ret);
 int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret);