mirror of
https://github.com/systemd/systemd.git
synced 2025-03-21 02:50:18 +03:00
Merge pull request #13508 from yuwata/network-route-fix-13506
network: takes more route information into hash func
This commit is contained in:
commit
404ca5560b
@ -577,7 +577,9 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t
|
||||
|
||||
assert(m->n_containers < RTNL_CONTAINER_DEPTH);
|
||||
assert(m->containers[m->n_containers].attributes);
|
||||
assert(type < m->containers[m->n_containers].n_attributes);
|
||||
|
||||
if (type >= m->containers[m->n_containers].n_attributes)
|
||||
return -ENODATA;
|
||||
|
||||
attribute = &m->containers[m->n_containers].attributes[type];
|
||||
|
||||
|
@ -181,7 +181,7 @@ static int link_set_dhcp_routes(Link *link) {
|
||||
* the addresses now, let's not configure the routes either. */
|
||||
return 0;
|
||||
|
||||
r = set_ensure_allocated(&link->dhcp_routes, &route_full_hash_ops);
|
||||
r = set_ensure_allocated(&link->dhcp_routes, &route_hash_ops);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
|
@ -134,22 +134,21 @@ int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
|
||||
&lifetime_preferred,
|
||||
&lifetime_valid) >= 0) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
Route *route;
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
|
||||
if (pd_prefix_len >= 64)
|
||||
continue;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||
|
||||
r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, NULL, 0, 0, 0, &route);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Failed to add unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
|
||||
strnull(buf),
|
||||
pd_prefix_len);
|
||||
continue;
|
||||
}
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route_update(route, NULL, 0, NULL, NULL, 0, 0, RTN_UNREACHABLE);
|
||||
route->family = AF_INET6;
|
||||
route->dst = pd_prefix;
|
||||
route->dst_prefixlen = pd_prefix_len;
|
||||
route->type = RTN_UNREACHABLE;
|
||||
|
||||
r = route_remove(route, link, dhcp6_route_remove_handler);
|
||||
if (r < 0) {
|
||||
@ -290,20 +289,17 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
||||
strnull(buf), pd_prefix_len);
|
||||
|
||||
if (pd_prefix_len < 64) {
|
||||
uint32_t table;
|
||||
Route *route;
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
|
||||
table = link_get_dhcp_route_table(link);
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, NULL, 0, 0, table, &route);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Failed to add unreachable route for DHCPv6 delegated subnet %s/%u: %m",
|
||||
strnull(buf),
|
||||
pd_prefix_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
route_update(route, NULL, 0, NULL, NULL, 0, 0, RTN_UNREACHABLE);
|
||||
route->family = AF_INET6;
|
||||
route->dst = pd_prefix;
|
||||
route->dst_prefixlen = pd_prefix_len;
|
||||
route->table = link_get_dhcp_route_table(link);
|
||||
route->type = RTN_UNREACHABLE;
|
||||
|
||||
r = route_configure(route, link, dhcp6_route_handler);
|
||||
if (r < 0) {
|
||||
@ -721,20 +717,23 @@ static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *
|
||||
}
|
||||
|
||||
static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
_cleanup_free_ struct in6_addr *a = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
Link *assigned_link;
|
||||
Route *route;
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
r = route_add(link, AF_INET6, (union in_addr_union *) addr, 64,
|
||||
NULL, 0, 0, 0, &route);
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->family = AF_INET6;
|
||||
route->dst.in6 = *addr;
|
||||
route->dst_prefixlen = 64;
|
||||
|
||||
r = route_configure(route, link, dhcp6_route_add_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -786,8 +785,8 @@ static int dhcp6_prefix_remove_handler(sd_netlink *nl, sd_netlink_message *m, Li
|
||||
int dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
||||
_cleanup_free_ struct in6_addr *a = NULL;
|
||||
_cleanup_(link_unrefp) Link *l = NULL;
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
Route *route;
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
@ -798,10 +797,15 @@ int dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
||||
return -EINVAL;
|
||||
|
||||
(void) sd_radv_remove_prefix(l->radv, addr, 64);
|
||||
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, NULL, 0, 0, 0, &route);
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->family = AF_INET6;
|
||||
route->dst.in6 = *addr;
|
||||
route->dst_prefixlen = 64;
|
||||
|
||||
r = route_remove(route, l, dhcp6_prefix_remove_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -2444,7 +2444,7 @@ static int link_drop_foreign_config(Link *link) {
|
||||
continue;
|
||||
|
||||
if (link_is_static_route_configured(link, route)) {
|
||||
r = route_add(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, NULL);
|
||||
r = route_add(link, route, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
@ -2906,7 +2906,6 @@ static int link_load(Link *link) {
|
||||
*dhcp4_address = NULL,
|
||||
*ipv4ll_address = NULL;
|
||||
union in_addr_union address;
|
||||
union in_addr_union route_dst;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
@ -2993,14 +2992,11 @@ network_file_fail:
|
||||
p = routes;
|
||||
|
||||
for (;;) {
|
||||
Route *route;
|
||||
_cleanup_free_ char *route_str = NULL;
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
||||
usec_t lifetime;
|
||||
_cleanup_(route_freep) Route *tmp = NULL;
|
||||
_cleanup_free_ char *route_str = NULL;
|
||||
char *prefixlen_str;
|
||||
int family;
|
||||
unsigned char prefixlen, tos, table;
|
||||
uint32_t priority;
|
||||
Route *route;
|
||||
|
||||
r = extract_first_word(&p, &route_str, NULL, 0);
|
||||
if (r < 0) {
|
||||
@ -3018,7 +3014,11 @@ network_file_fail:
|
||||
|
||||
*prefixlen_str++ = '\0';
|
||||
|
||||
r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
|
||||
r = route_new(&tmp);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT, &tmp->dst_prefixlen, &tmp->tos, &tmp->priority, &tmp->table, &tmp->lifetime);
|
||||
if (r != 5) {
|
||||
log_link_debug(link,
|
||||
"Failed to parse destination prefix length, tos, priority, table or expiration %s",
|
||||
@ -3026,24 +3026,23 @@ network_file_fail:
|
||||
continue;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(route_str, &family, &route_dst);
|
||||
r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = route_add(link, family, &route_dst, prefixlen, NULL, tos, priority, table, &route);
|
||||
r = route_add(link, tmp, &route);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to add route: %m");
|
||||
|
||||
if (lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
|
||||
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
|
||||
if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
|
||||
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), route->lifetime,
|
||||
0, route_expire_handler, route);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
|
||||
}
|
||||
|
||||
route->lifetime = lifetime;
|
||||
sd_event_source_unref(route->expire);
|
||||
route->expire = TAKE_PTR(expire);
|
||||
}
|
||||
|
@ -265,15 +265,13 @@ static int manager_connect_udev(Manager *m) {
|
||||
}
|
||||
|
||||
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
||||
_cleanup_(route_freep) Route *tmp = NULL;
|
||||
Route *route = NULL;
|
||||
Manager *m = userdata;
|
||||
Link *link = NULL;
|
||||
uint32_t ifindex;
|
||||
uint16_t type;
|
||||
uint32_t ifindex, priority = 0;
|
||||
unsigned char protocol, scope, tos, table, rt_type;
|
||||
int family;
|
||||
unsigned char dst_prefixlen, src_prefixlen;
|
||||
union in_addr_union dst = IN_ADDR_NULL, gw = IN_ADDR_NULL, src = IN_ADDR_NULL, prefsrc = IN_ADDR_NULL;
|
||||
Route *route = NULL;
|
||||
unsigned char table;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
@ -318,39 +316,43 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_family(message, &family);
|
||||
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
|
||||
r = route_new(&tmp);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = sd_rtnl_message_route_get_family(message, &tmp->family);
|
||||
if (r < 0 || !IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
||||
log_link_warning(link, "rtnl: received route message with invalid family, ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_protocol(message, &protocol);
|
||||
r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: received route message with invalid route protocol: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (family) {
|
||||
switch (tmp->family) {
|
||||
case AF_INET:
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
|
||||
return 0;
|
||||
@ -359,25 +361,25 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
|
||||
return 0;
|
||||
@ -390,31 +392,31 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
|
||||
r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
|
||||
r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_scope(message, &scope);
|
||||
r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_tos(message, &tos);
|
||||
r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_type(message, &rt_type);
|
||||
r = sd_rtnl_message_route_get_type(message, &tmp->type);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
|
||||
return 0;
|
||||
@ -425,14 +427,40 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
tmp->table = table;
|
||||
|
||||
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
|
||||
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) route_get(link, family, &dst, dst_prefixlen, &gw, tos, priority, table, &route);
|
||||
r = sd_netlink_message_enter_container(message, RTA_METRICS);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m");
|
||||
return 0;
|
||||
}
|
||||
if (r >= 0) {
|
||||
r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_exit_container(message);
|
||||
if (r < 0) {
|
||||
log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
(void) route_get(link, tmp, &route);
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
|
||||
@ -440,41 +468,39 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
||||
char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX],
|
||||
buf_protocol[ROUTE_PROTOCOL_STR_MAX];
|
||||
|
||||
if (!in_addr_is_null(family, &dst)) {
|
||||
(void) in_addr_to_string(family, &dst, &buf_dst);
|
||||
(void) asprintf(&buf_dst_prefixlen, "/%u", dst_prefixlen);
|
||||
if (!in_addr_is_null(tmp->family, &tmp->dst)) {
|
||||
(void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst);
|
||||
(void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen);
|
||||
}
|
||||
if (!in_addr_is_null(family, &src))
|
||||
(void) in_addr_to_string(family, &src, &buf_src);
|
||||
if (!in_addr_is_null(family, &gw))
|
||||
(void) in_addr_to_string(family, &gw, &buf_gw);
|
||||
if (!in_addr_is_null(family, &prefsrc))
|
||||
(void) in_addr_to_string(family, &prefsrc, &buf_prefsrc);
|
||||
if (!in_addr_is_null(tmp->family, &tmp->src))
|
||||
(void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
|
||||
if (!in_addr_is_null(tmp->family, &tmp->gw))
|
||||
(void) in_addr_to_string(tmp->family, &tmp->gw, &buf_gw);
|
||||
if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
|
||||
(void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
|
||||
|
||||
log_link_debug(link,
|
||||
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
||||
type == RTM_DELROUTE ? "Forgetting" : route ? "Updating remembered" : "Remembering",
|
||||
type == RTM_DELROUTE ? "Forgetting" : route ? "Received remembered" : "Remembering",
|
||||
strna(buf_dst), strempty(buf_dst_prefixlen),
|
||||
strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
|
||||
format_route_scope(scope, buf_scope, sizeof buf_scope),
|
||||
format_route_table(table, buf_table, sizeof buf_table),
|
||||
format_route_protocol(protocol, buf_protocol, sizeof buf_protocol),
|
||||
strna(route_type_to_string(rt_type)));
|
||||
format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
|
||||
format_route_table(tmp->table, buf_table, sizeof buf_table),
|
||||
format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol),
|
||||
strna(route_type_to_string(tmp->type)));
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWROUTE:
|
||||
if (!route) {
|
||||
/* A route appeared that we did not request */
|
||||
r = route_add_foreign(link, family, &dst, dst_prefixlen, &gw, tos, priority, table, &route);
|
||||
r = route_add_foreign(link, tmp, &route);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol, rt_type);
|
||||
|
||||
break;
|
||||
|
||||
case RTM_DELROUTE:
|
||||
|
@ -154,68 +154,6 @@ static void route_hash_func(const Route *route, struct siphash *state) {
|
||||
|
||||
siphash24_compress(&route->family, sizeof(route->family), state);
|
||||
|
||||
switch (route->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
/* Equality of routes are given by the 4-touple
|
||||
(dst_prefix,dst_prefixlen,tos,priority,table) */
|
||||
siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
|
||||
siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
|
||||
siphash24_compress(&route->tos, sizeof(route->tos), state);
|
||||
siphash24_compress(&route->priority, sizeof(route->priority), state);
|
||||
siphash24_compress(&route->table, sizeof(route->table), state);
|
||||
|
||||
break;
|
||||
default:
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int route_compare_func(const Route *a, const Route *b) {
|
||||
int r;
|
||||
|
||||
r = CMP(a->family, b->family);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
switch (a->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
r = CMP(a->dst_prefixlen, b->dst_prefixlen);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->tos, b->tos);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->priority, b->priority);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->table, b->table);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
|
||||
default:
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS(route_hash_ops, Route, route_hash_func, route_compare_func);
|
||||
|
||||
static void route_full_hash_func(const Route *route, struct siphash *state) {
|
||||
assert(route);
|
||||
|
||||
siphash24_compress(&route->family, sizeof(route->family), state);
|
||||
|
||||
switch (route->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
@ -232,6 +170,8 @@ static void route_full_hash_func(const Route *route, struct siphash *state) {
|
||||
siphash24_compress(&route->protocol, sizeof(route->protocol), state);
|
||||
siphash24_compress(&route->scope, sizeof(route->scope), state);
|
||||
siphash24_compress(&route->type, sizeof(route->type), state);
|
||||
siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
|
||||
siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
|
||||
|
||||
break;
|
||||
default:
|
||||
@ -240,7 +180,7 @@ static void route_full_hash_func(const Route *route, struct siphash *state) {
|
||||
}
|
||||
}
|
||||
|
||||
static int route_full_compare_func(const Route *a, const Route *b) {
|
||||
static int route_compare_func(const Route *a, const Route *b) {
|
||||
int r;
|
||||
|
||||
r = CMP(a->family, b->family);
|
||||
@ -282,6 +222,14 @@ static int route_full_compare_func(const Route *a, const Route *b) {
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->initcwnd, b->initcwnd);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->initrwnd, b->initrwnd);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
@ -302,10 +250,10 @@ static int route_full_compare_func(const Route *a, const Route *b) {
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
route_full_hash_ops,
|
||||
route_hash_ops,
|
||||
Route,
|
||||
route_full_hash_func,
|
||||
route_full_compare_func,
|
||||
route_hash_func,
|
||||
route_compare_func,
|
||||
route_free);
|
||||
|
||||
bool route_equal(Route *r1, Route *r2) {
|
||||
@ -318,39 +266,21 @@ bool route_equal(Route *r1, Route *r2) {
|
||||
return route_compare_func(r1, r2) == 0;
|
||||
}
|
||||
|
||||
int route_get(Link *link,
|
||||
int family,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
const union in_addr_union *gw,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
uint32_t table,
|
||||
Route **ret) {
|
||||
int route_get(Link *link, Route *in, Route **ret) {
|
||||
|
||||
Route route, *existing;
|
||||
Route *existing;
|
||||
|
||||
assert(link);
|
||||
assert(dst);
|
||||
assert(in);
|
||||
|
||||
route = (Route) {
|
||||
.family = family,
|
||||
.dst = *dst,
|
||||
.dst_prefixlen = dst_prefixlen,
|
||||
.gw = gw ? *gw : IN_ADDR_NULL,
|
||||
.tos = tos,
|
||||
.priority = priority,
|
||||
.table = table,
|
||||
};
|
||||
|
||||
existing = set_get(link->routes, &route);
|
||||
existing = set_get(link->routes, in);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
}
|
||||
|
||||
existing = set_get(link->routes_foreign, &route);
|
||||
existing = set_get(link->routes_foreign, in);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
@ -360,37 +290,35 @@ int route_get(Link *link,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int route_add_internal(
|
||||
Link *link,
|
||||
Set **routes,
|
||||
int family,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
const union in_addr_union *gw,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
uint32_t table,
|
||||
Route **ret) {
|
||||
static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret) {
|
||||
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(routes);
|
||||
assert(dst);
|
||||
assert(in);
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->family = family;
|
||||
route->dst = *dst;
|
||||
route->dst_prefixlen = dst_prefixlen;
|
||||
route->dst = *dst;
|
||||
route->gw = gw ? *gw : IN_ADDR_NULL;
|
||||
route->tos = tos;
|
||||
route->priority = priority;
|
||||
route->table = table;
|
||||
route->family = in->family;
|
||||
route->src = in->src;
|
||||
route->src_prefixlen = in->src_prefixlen;
|
||||
route->dst = in->dst;
|
||||
route->dst_prefixlen = in->dst_prefixlen;
|
||||
route->gw = in->gw;
|
||||
route->prefsrc = in->prefsrc;
|
||||
route->scope = in->scope;
|
||||
route->protocol = in->protocol;
|
||||
route->type = in->type;
|
||||
route->tos = in->tos;
|
||||
route->priority = in->priority;
|
||||
route->table = in->table;
|
||||
route->initcwnd = in->initcwnd;
|
||||
route->initrwnd = in->initrwnd;
|
||||
route->lifetime = in->lifetime;
|
||||
|
||||
r = set_ensure_allocated(routes, &route_hash_ops);
|
||||
if (r < 0)
|
||||
@ -412,37 +340,19 @@ static int route_add_internal(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_add_foreign(
|
||||
Link *link,
|
||||
int family,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
const union in_addr_union *gw,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
uint32_t table,
|
||||
Route **ret) {
|
||||
|
||||
return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, gw, tos, priority, table, ret);
|
||||
int route_add_foreign(Link *link, Route *in, Route **ret) {
|
||||
return route_add_internal(link, &link->routes_foreign, in, ret);
|
||||
}
|
||||
|
||||
int route_add(Link *link,
|
||||
int family,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
const union in_addr_union *gw,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
uint32_t table,
|
||||
Route **ret) {
|
||||
int route_add(Link *link, Route *in, Route **ret) {
|
||||
|
||||
Route *route;
|
||||
int r;
|
||||
|
||||
r = route_get(link, family, dst, dst_prefixlen, gw, tos, priority, table, &route);
|
||||
r = route_get(link, in, &route);
|
||||
if (r == -ENOENT) {
|
||||
/* Route does not exist, create a new one */
|
||||
r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, gw, tos, priority, table, &route);
|
||||
r = route_add_internal(link, &link->routes, in, &route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
@ -468,27 +378,6 @@ int route_add(Link *link,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void route_update(Route *route,
|
||||
const union in_addr_union *src,
|
||||
unsigned char src_prefixlen,
|
||||
const union in_addr_union *gw,
|
||||
const union in_addr_union *prefsrc,
|
||||
unsigned char scope,
|
||||
unsigned char protocol,
|
||||
unsigned char type) {
|
||||
|
||||
assert(route);
|
||||
assert(src || src_prefixlen == 0);
|
||||
|
||||
route->src = src ? *src : IN_ADDR_NULL;
|
||||
route->src_prefixlen = src_prefixlen;
|
||||
route->gw = gw ? *gw : IN_ADDR_NULL;
|
||||
route->prefsrc = prefsrc ? *prefsrc : IN_ADDR_NULL;
|
||||
route->scope = scope;
|
||||
route->protocol = protocol;
|
||||
route->type = type;
|
||||
}
|
||||
|
||||
static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
@ -626,7 +515,6 @@ int route_configure(
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
||||
usec_t lifetime;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -636,7 +524,7 @@ int route_configure(
|
||||
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
||||
assert(callback);
|
||||
|
||||
if (route_get(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, NULL) <= 0 &&
|
||||
if (route_get(link, route, NULL) <= 0 &&
|
||||
set_size(link->routes) >= routes_max())
|
||||
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
||||
"Too many routes are configured, refusing: %m");
|
||||
@ -810,15 +698,11 @@ int route_configure(
|
||||
|
||||
link_ref(link);
|
||||
|
||||
lifetime = route->lifetime;
|
||||
|
||||
r = route_add(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, &route);
|
||||
r = route_add(link, route, &route);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not add route: %m");
|
||||
|
||||
/* TODO: drop expiration handling once it can be pushed into the kernel */
|
||||
route->lifetime = lifetime;
|
||||
|
||||
if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
|
||||
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
|
||||
route->lifetime, 0, route_expire_handler, route);
|
||||
|
@ -49,17 +49,16 @@ struct Route {
|
||||
LIST_FIELDS(Route, routes);
|
||||
};
|
||||
|
||||
extern const struct hash_ops route_full_hash_ops;
|
||||
extern const struct hash_ops route_hash_ops;
|
||||
|
||||
int route_new(Route **ret);
|
||||
void route_free(Route *route);
|
||||
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback);
|
||||
int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
|
||||
|
||||
int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, const union in_addr_union *gw, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
|
||||
int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, const union in_addr_union *gw, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
|
||||
int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, const union in_addr_union *gw, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
|
||||
void route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol, unsigned char type);
|
||||
int route_get(Link *link, Route *in, Route **ret);
|
||||
int route_add(Link *link, Route *in, Route **ret);
|
||||
int route_add_foreign(Link *link, Route *in, Route **ret);
|
||||
bool route_equal(Route *r1, Route *r2);
|
||||
|
||||
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
|
Loading…
x
Reference in New Issue
Block a user