#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);
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);
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,
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);
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;
return 0;
}
-static int route_add(Manager *manager, Route *route) {
+static int route_attach(Manager *manager, Route *route) {
int r;
assert(manager);
}
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);
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;
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) {
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);
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;
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,
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;
}
/* 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
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",
}
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);
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;
}
}
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;
}
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;
}
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;
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);
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;
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);
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);
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;
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);
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);
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);
HASHMAP_FOREACH(route, network->routes_by_section)
if (route_section_verify(route) < 0)
- route_free(route);
+ route_detach(route);
}