network: also manage routes without RTA_OIF attribute
This commit is contained in:
parent
fd7701bf31
commit
ad208fac73
|
@ -38,7 +38,7 @@ static int dhcp4_release_old_lease(Link *link) {
|
||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->dhcp_routes_old) {
|
SET_FOREACH(route, link->dhcp_routes_old) {
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
@ -512,7 +512,7 @@ static int dhcp4_remove_all(Link *link) {
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->dhcp_routes) {
|
SET_FOREACH(route, link->dhcp_routes) {
|
||||||
k = route_remove(route, link, dhcp4_remove_route_handler);
|
k = route_remove(route, NULL, link, dhcp4_remove_route_handler);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
else
|
else
|
||||||
|
|
|
@ -164,7 +164,7 @@ static int dhcp6_pd_remove_old(Link *link, bool force) {
|
||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->dhcp6_pd_routes_old) {
|
SET_FOREACH(route, link->dhcp6_pd_routes_old) {
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ int dhcp6_pd_remove(Link *link) {
|
||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->dhcp6_pd_routes) {
|
SET_FOREACH(route, link->dhcp6_pd_routes) {
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
|
@ -704,7 +704,7 @@ static int dhcp6_remove_old(Link *link, bool force) {
|
||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->dhcp6_routes_old) {
|
SET_FOREACH(route, link->dhcp6_routes_old) {
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
@ -740,7 +740,7 @@ static int dhcp6_remove(Link *link) {
|
||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->dhcp6_routes) {
|
SET_FOREACH(route, link->dhcp6_routes) {
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
|
|
@ -886,6 +886,9 @@ void manager_free(Manager *m) {
|
||||||
m->rules_foreign = set_free(m->rules_foreign);
|
m->rules_foreign = set_free(m->rules_foreign);
|
||||||
set_free(m->rules_saved);
|
set_free(m->rules_saved);
|
||||||
|
|
||||||
|
m->routes = set_free(m->routes);
|
||||||
|
m->routes_foreign = set_free(m->routes_foreign);
|
||||||
|
|
||||||
sd_netlink_unref(m->rtnl);
|
sd_netlink_unref(m->rtnl);
|
||||||
sd_netlink_unref(m->genl);
|
sd_netlink_unref(m->genl);
|
||||||
sd_resolve_unref(m->resolve);
|
sd_resolve_unref(m->resolve);
|
||||||
|
|
|
@ -61,6 +61,10 @@ struct Manager {
|
||||||
Set *rules_foreign;
|
Set *rules_foreign;
|
||||||
Set *rules_saved;
|
Set *rules_saved;
|
||||||
|
|
||||||
|
/* Manager stores routes without RTA_OIF attribute. */
|
||||||
|
Set *routes;
|
||||||
|
Set *routes_foreign;
|
||||||
|
|
||||||
/* For link speed meter*/
|
/* For link speed meter*/
|
||||||
bool use_speed_meter;
|
bool use_speed_meter;
|
||||||
sd_event_source *speed_meter_event_source;
|
sd_event_source *speed_meter_event_source;
|
||||||
|
|
|
@ -163,7 +163,7 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
|
||||||
|
|
||||||
SET_FOREACH(nr, link->ndisc_routes)
|
SET_FOREACH(nr, link->ndisc_routes)
|
||||||
if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
|
if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
|
||||||
k = route_remove(nr->route, link, NULL);
|
k = route_remove(nr->route, NULL, link, NULL);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,6 +272,11 @@ Route *route_free(Route *route) {
|
||||||
free(set_remove(route->link->ndisc_routes, n));
|
free(set_remove(route->link->ndisc_routes, n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (route->manager) {
|
||||||
|
set_remove(route->manager->routes, route);
|
||||||
|
set_remove(route->manager->routes_foreign, route);
|
||||||
|
}
|
||||||
|
|
||||||
ordered_set_free_free(route->multipath_routes);
|
ordered_set_free_free(route->multipath_routes);
|
||||||
|
|
||||||
sd_event_source_unref(route->expire);
|
sd_event_source_unref(route->expire);
|
||||||
|
@ -404,36 +409,51 @@ static bool route_equal(Route *r1, Route *r2) {
|
||||||
return route_compare_func(r1, r2) == 0;
|
return route_compare_func(r1, r2) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int route_get(Link *link, Route *in, Route **ret) {
|
static int route_get(Manager *manager, Link *link, Route *in, Route **ret) {
|
||||||
|
|
||||||
Route *existing;
|
Route *existing;
|
||||||
|
|
||||||
assert(link);
|
assert(manager || link);
|
||||||
assert(in);
|
assert(in);
|
||||||
|
|
||||||
existing = set_get(link->routes, in);
|
if (link) {
|
||||||
if (existing) {
|
existing = set_get(link->routes, in);
|
||||||
if (ret)
|
if (existing) {
|
||||||
*ret = existing;
|
if (ret)
|
||||||
return 1;
|
*ret = existing;
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
existing = set_get(link->routes_foreign, in);
|
existing = set_get(link->routes_foreign, in);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (ret)
|
if (ret)
|
||||||
*ret = existing;
|
*ret = existing;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
existing = set_get(manager->routes, in);
|
||||||
|
if (existing) {
|
||||||
|
if (ret)
|
||||||
|
*ret = existing;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing = set_get(manager->routes_foreign, in);
|
||||||
|
if (existing) {
|
||||||
|
if (ret)
|
||||||
|
*ret = existing;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret) {
|
static int route_add_internal(Manager *manager, Link *link, Set **routes, Route *in, Route **ret) {
|
||||||
|
|
||||||
_cleanup_(route_freep) Route *route = NULL;
|
_cleanup_(route_freep) Route *route = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(manager || link);
|
||||||
assert(routes);
|
assert(routes);
|
||||||
assert(in);
|
assert(in);
|
||||||
|
|
||||||
|
@ -465,6 +485,7 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
|
|
||||||
route->link = link;
|
route->link = link;
|
||||||
|
route->manager = manager;
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
*ret = route;
|
*ret = route;
|
||||||
|
@ -474,28 +495,39 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int route_add_foreign(Link *link, Route *in, Route **ret) {
|
static int route_add_foreign(Manager *manager, Link *link, Route *in, Route **ret) {
|
||||||
return route_add_internal(link, &link->routes_foreign, in, ret);
|
assert(manager || link);
|
||||||
|
return route_add_internal(manager, link, link ? &link->routes_foreign : &manager->routes_foreign, in, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int route_add(Link *link, Route *in, Route **ret) {
|
static int route_add(Manager *manager, Link *link, Route *in, Route **ret) {
|
||||||
|
|
||||||
Route *route;
|
Route *route;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = route_get(link, in, &route);
|
assert(manager || link);
|
||||||
|
assert(in);
|
||||||
|
|
||||||
|
r = route_get(manager, link, in, &route);
|
||||||
if (r == -ENOENT) {
|
if (r == -ENOENT) {
|
||||||
/* Route does not exist, create a new one */
|
/* Route does not exist, create a new one */
|
||||||
r = route_add_internal(link, &link->routes, in, &route);
|
r = route_add_internal(manager, link, link ? &link->routes : &manager->routes, in, &route);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else if (r == 0) {
|
} else if (r == 0) {
|
||||||
/* Take over a foreign route */
|
/* Take over a foreign route */
|
||||||
r = set_ensure_put(&link->routes, &route_hash_ops, route);
|
if (link) {
|
||||||
if (r < 0)
|
r = set_ensure_put(&link->routes, &route_hash_ops, route);
|
||||||
return r;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
set_remove(link->routes_foreign, route);
|
set_remove(link->routes_foreign, route);
|
||||||
|
} else {
|
||||||
|
r = set_ensure_put(&manager->routes, &route_hash_ops, route);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
set_remove(manager->routes_foreign, route);
|
||||||
|
}
|
||||||
} else if (r == 1) {
|
} else if (r == 1) {
|
||||||
/* Route exists, do nothing */
|
/* Route exists, do nothing */
|
||||||
;
|
;
|
||||||
|
@ -512,10 +544,9 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(link);
|
|
||||||
assert(link->ifname);
|
|
||||||
|
|
||||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
/* Note that link may be NULL. */
|
||||||
|
if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
r = sd_netlink_message_get_errno(m);
|
||||||
|
@ -525,19 +556,22 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int route_remove(Route *route, Link *link,
|
int route_remove(
|
||||||
link_netlink_message_handler_t callback) {
|
Route *route,
|
||||||
|
Manager *manager,
|
||||||
|
Link *link,
|
||||||
|
link_netlink_message_handler_t callback) {
|
||||||
|
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link || manager);
|
||||||
assert(link->manager);
|
|
||||||
assert(link->manager->rtnl);
|
|
||||||
assert(link->ifindex > 0);
|
|
||||||
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
||||||
|
|
||||||
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
|
if (!manager)
|
||||||
|
manager = link->manager;
|
||||||
|
|
||||||
|
r = sd_rtnl_message_new_route(manager->rtnl, &req,
|
||||||
RTM_DELROUTE, route->family,
|
RTM_DELROUTE, route->family,
|
||||||
route->protocol);
|
route->protocol);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -618,7 +652,8 @@ int route_remove(Route *route, Link *link,
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||||
|
|
||||||
link_ref(link);
|
if (link)
|
||||||
|
link_ref(link);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -668,9 +703,9 @@ int link_drop_foreign_routes(Link *link) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (link_is_static_route_configured(link, route))
|
if (link_is_static_route_configured(link, route))
|
||||||
k = route_add(link, route, NULL);
|
k = route_add(NULL, link, route, NULL);
|
||||||
else
|
else
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
@ -689,7 +724,7 @@ int link_drop_routes(Link *link) {
|
||||||
if (route->protocol == RTPROT_KERNEL)
|
if (route->protocol == RTPROT_KERNEL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
k = route_remove(route, link, NULL);
|
k = route_remove(route, NULL, link, NULL);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
@ -703,7 +738,7 @@ static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdat
|
||||||
|
|
||||||
assert(route);
|
assert(route);
|
||||||
|
|
||||||
r = route_remove(route, route->link, NULL);
|
r = route_remove(route, route->manager, route->link, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_warning_errno(route->link, r, "Could not remove route: %m");
|
log_link_warning_errno(route->link, r, "Could not remove route: %m");
|
||||||
else
|
else
|
||||||
|
@ -810,7 +845,7 @@ int route_configure(
|
||||||
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
||||||
assert(callback);
|
assert(callback);
|
||||||
|
|
||||||
if (route_get(link, route, NULL) <= 0 &&
|
if (route_get(link->manager, link, route, NULL) <= 0 &&
|
||||||
set_size(link->routes) >= routes_max())
|
set_size(link->routes) >= routes_max())
|
||||||
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
||||||
"Too many routes are configured, refusing: %m");
|
"Too many routes are configured, refusing: %m");
|
||||||
|
@ -988,7 +1023,10 @@ int route_configure(
|
||||||
|
|
||||||
link_ref(link);
|
link_ref(link);
|
||||||
|
|
||||||
r = route_add(link, route, &route);
|
if (IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW) || !ordered_set_isempty(route->multipath_routes))
|
||||||
|
r = route_add(link->manager, NULL, route, &route);
|
||||||
|
else
|
||||||
|
r = route_add(NULL, link, route, &route);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not add route: %m");
|
return log_link_error_errno(link, r, "Could not add route: %m");
|
||||||
|
|
||||||
|
@ -1123,24 +1161,23 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
||||||
if (r == -ENODATA) {
|
if (r < 0 && r != -ENODATA) {
|
||||||
log_debug("rtnl: received route message without ifindex, ignoring");
|
|
||||||
return 0;
|
|
||||||
} else if (r < 0) {
|
|
||||||
log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
|
log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
|
||||||
return 0;
|
return 0;
|
||||||
} else if (ifindex <= 0) {
|
} else if (r >= 0) {
|
||||||
log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
|
if (ifindex <= 0) {
|
||||||
return 0;
|
log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
r = link_get(m, ifindex, &link);
|
r = link_get(m, ifindex, &link);
|
||||||
if (r < 0 || !link) {
|
if (r < 0 || !link) {
|
||||||
/* when enumerating we might be out of sync, but we will
|
/* when enumerating we might be out of sync, but we will
|
||||||
* get the route again, so just ignore it */
|
* get the route again, so just ignore it */
|
||||||
if (!m->enumerating)
|
if (!m->enumerating)
|
||||||
log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
|
log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = route_new(&tmp);
|
r = route_new(&tmp);
|
||||||
|
@ -1290,7 +1327,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) route_get(link, tmp, &route);
|
(void) route_get(m, link, tmp, &route);
|
||||||
|
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING) {
|
||||||
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
|
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
|
||||||
|
@ -1311,7 +1348,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||||
|
|
||||||
log_link_debug(link,
|
log_link_debug(link,
|
||||||
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
||||||
(!route && !link->manager->manage_foreign_routes) ? "Ignoring received foreign" :
|
(!route && !m->manage_foreign_routes) ? "Ignoring received foreign" :
|
||||||
type == RTM_DELROUTE ? "Forgetting" :
|
type == RTM_DELROUTE ? "Forgetting" :
|
||||||
route ? "Received remembered" : "Remembering",
|
route ? "Received remembered" : "Remembering",
|
||||||
strna(buf_dst), strempty(buf_dst_prefixlen),
|
strna(buf_dst), strempty(buf_dst_prefixlen),
|
||||||
|
@ -1324,9 +1361,9 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RTM_NEWROUTE:
|
case RTM_NEWROUTE:
|
||||||
if (!route && link->manager->manage_foreign_routes) {
|
if (!route && m->manage_foreign_routes) {
|
||||||
/* A route appeared that we did not request */
|
/* A route appeared that we did not request */
|
||||||
r = route_add_foreign(link, tmp, &route);
|
r = route_add_foreign(m, link, tmp, &route);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
|
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1420,7 +1457,7 @@ int link_deserialize_routes(Link *link, const char *routes) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = route_add(link, tmp, &route);
|
r = route_add(NULL, link, tmp, &route);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_debug_errno(link, r, "Failed to add route: %m");
|
return log_link_debug_errno(link, r, "Failed to add route: %m");
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ typedef struct Route {
|
||||||
NetworkConfigSection *section;
|
NetworkConfigSection *section;
|
||||||
|
|
||||||
Link *link;
|
Link *link;
|
||||||
|
Manager *manager;
|
||||||
|
|
||||||
int family;
|
int family;
|
||||||
int quickack;
|
int quickack;
|
||||||
|
@ -74,7 +75,7 @@ Route *route_free(Route *route);
|
||||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
|
DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
|
||||||
|
|
||||||
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
|
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
|
||||||
int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
|
int route_remove(Route *route, Manager *manager, Link *link, link_netlink_message_handler_t callback);
|
||||||
|
|
||||||
int link_set_routes(Link *link);
|
int link_set_routes(Link *link);
|
||||||
int link_drop_routes(Link *link);
|
int link_drop_routes(Link *link);
|
||||||
|
|
Loading…
Reference in New Issue