From: Yu Watanabe Date: Sun, 7 Jan 2024 06:16:03 +0000 (+0900) Subject: network/route: introduce ref/unref functions for Route object X-Git-Tag: v256-rc1~1041^2~5 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=commitdiff_plain;h=74c301b9ee9479ffb5033f5ee1ec4c18ef79efa0 network/route: introduce ref/unref functions for Route object 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. --- diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 0195dce1bf0..95c9c8c3300 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -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) diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index d8f9a2c053c..61295d9ce64 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -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; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 1a1836cf666..f9baf0d5356 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -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)) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 488c8c02948..7a67c552993 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -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; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 16c679b3438..300fba5dd99 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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); diff --git a/src/network/networkd-route-metric.c b/src/network/networkd-route-metric.c index b27b3c12948..9c417a4fc4f 100644 --- a/src/network/networkd-route-metric.c +++ b/src/network/networkd-route-metric.c @@ -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); diff --git a/src/network/networkd-route-nexthop.c b/src/network/networkd-route-nexthop.c index 5f1da286046..8ccd4e66e87 100644 --- a/src/network/networkd-route-nexthop.c +++ b/src/network/networkd-route-nexthop.c @@ -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; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index efb121cb82f..89a96cbda11 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -21,20 +21,41 @@ #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); } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 51a06dd0f14..004295e5998 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -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);