1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

network/route: find/distinguish routes in the same way that the kernel uses

The kernel uses different logics to find or distinguish IPv4 and IPv6 routes.
Let's follow the same way that the kernel uses.
See comments in the code for more details.
This commit is contained in:
Yu Watanabe 2024-01-13 13:16:10 +09:00 committed by Luca Boccassi
parent 50d5f64632
commit 47420573a7
3 changed files with 160 additions and 54 deletions

View File

@ -35,7 +35,7 @@ void route_nexthops_done(Route *route) {
ordered_set_free(route->nexthops);
}
static void route_nexthop_hash_func(const RouteNextHop *nh, struct siphash *state) {
static void route_nexthop_hash_func_full(const RouteNextHop *nh, struct siphash *state, bool hash_all_parameters) {
assert(nh);
assert(state);
@ -46,13 +46,15 @@ static void route_nexthop_hash_func(const RouteNextHop *nh, struct siphash *stat
return;
in_addr_hash_func(&nh->gw, nh->family, state);
if (!hash_all_parameters)
return;
siphash24_compress_typesafe(nh->weight, state);
siphash24_compress_typesafe(nh->ifindex, state);
if (nh->ifindex == 0)
siphash24_compress_string(nh->ifname, state); /* For Network or Request object. */
}
static int route_nexthop_compare_func(const RouteNextHop *a, const RouteNextHop *b) {
static int route_nexthop_compare_func_full(const RouteNextHop *a, const RouteNextHop *b, bool hash_all_parameters) {
int r;
assert(a);
@ -69,6 +71,9 @@ static int route_nexthop_compare_func(const RouteNextHop *a, const RouteNextHop
if (r != 0)
return r;
if (!hash_all_parameters)
return 0;
r = CMP(a->weight, b->weight);
if (r != 0)
return r;
@ -86,6 +91,14 @@ static int route_nexthop_compare_func(const RouteNextHop *a, const RouteNextHop
return 0;
}
static void route_nexthop_hash_func(const RouteNextHop *nh, struct siphash *state) {
route_nexthop_hash_func_full(nh, state, /* hash_all_parameters = */ true);
}
static int route_nexthop_compare_func(const RouteNextHop *a, const RouteNextHop *b) {
return route_nexthop_compare_func_full(a, b, /* hash_all_parameters = */ true);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
route_nexthop_hash_ops,
RouteNextHop,
@ -93,6 +106,70 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
route_nexthop_compare_func,
route_nexthop_free);
static size_t route_n_nexthops(const Route *route) {
assert(route);
if (route->nexthop_id != 0 || route_type_is_reject(route))
return 0;
if (ordered_set_isempty(route->nexthops))
return 1;
return ordered_set_size(route->nexthops);
}
void route_nexthops_hash_func(const Route *route, struct siphash *state) {
assert(route);
size_t nhs = route_n_nexthops(route);
siphash24_compress_typesafe(nhs, state);
switch (nhs) {
case 0:
siphash24_compress_typesafe(route->nexthop_id, state);
return;
case 1:
route_nexthop_hash_func_full(&route->nexthop, state, /* hash_all_parameters = */ false);
return;
default: {
RouteNextHop *nh;
ORDERED_SET_FOREACH(nh, route->nexthops)
route_nexthop_hash_func(nh, state);
}}
}
int route_nexthops_compare_func(const Route *a, const Route *b) {
int r;
assert(a);
assert(b);
size_t a_nhs = route_n_nexthops(a);
size_t b_nhs = route_n_nexthops(b);
r = CMP(a_nhs, b_nhs);
if (r != 0)
return r;
switch (a_nhs) {
case 0:
return CMP(a->nexthop_id, b->nexthop_id);
case 1:
return route_nexthop_compare_func_full(&a->nexthop, &b->nexthop, /* hash_all_parameters = */ false);
default: {
RouteNextHop *nh;
ORDERED_SET_FOREACH(nh, a->nexthops) {
r = CMP(nh, (RouteNextHop*) ordered_set_get(a->nexthops, nh));
if (r != 0)
return r;
}
return 0;
}}
}
int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh, Link **ret) {
assert(manager);
assert(nh);

View File

@ -9,6 +9,7 @@
#include "conf-parser.h"
#include "in-addr-util.h"
#include "macro.h"
#include "siphash24.h"
typedef struct Link Link;
typedef struct Manager Manager;
@ -28,6 +29,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(RouteNextHop*, route_nexthop_free);
void route_nexthops_done(Route *route);
void route_nexthops_hash_func(const Route *route, struct siphash *state);
int route_nexthops_compare_func(const Route *a, const Route *b);
int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh, Link **ret);
int route_nexthops_is_ready_to_configure(const Route *route, Link *link);

View File

@ -117,31 +117,51 @@ static void route_hash_func(const Route *route, struct siphash *state) {
switch (route->family) {
case AF_INET:
case AF_INET6:
siphash24_compress_typesafe(route->dst_prefixlen, state);
in_addr_hash_func(&route->dst, route->family, state);
siphash24_compress_typesafe(route->src_prefixlen, state);
in_addr_hash_func(&route->src, route->family, state);
siphash24_compress_typesafe(route->nexthop.family, state);
if (IN_SET(route->nexthop.family, AF_INET, AF_INET6)) {
in_addr_hash_func(&route->nexthop.gw, route->nexthop.family, state);
siphash24_compress_typesafe(route->nexthop.weight, state);
}
in_addr_hash_func(&route->prefsrc, route->family, state);
siphash24_compress_typesafe(route->tos, state);
siphash24_compress_typesafe(route->priority, state);
/* First, the table, destination prefix, priority, and tos (dscp), are used to find routes.
* See fib_table_insert(), fib_find_node(), and fib_find_alias() in net/ipv4/fib_trie.c of the kernel. */
siphash24_compress_typesafe(route->table, state);
in_addr_hash_func(&route->dst, route->family, state);
siphash24_compress_typesafe(route->dst_prefixlen, state);
siphash24_compress_typesafe(route->priority, state);
siphash24_compress_typesafe(route->tos, state);
/* Then, protocol, scope, type, flags, prefsrc, metrics (RTAX_* attributes), and nexthops (gateways)
* are used to find routes. See fib_find_info() in net/ipv4/fib_semantics.c of the kernel. */
siphash24_compress_typesafe(route->protocol, state);
siphash24_compress_typesafe(route->scope, state);
siphash24_compress_typesafe(route->type, state);
route_metric_hash_func(&route->metric, state);
siphash24_compress_typesafe(route->nexthop_id, state);
unsigned flags = route->flags & ~RTNH_COMPARE_MASK;
siphash24_compress_typesafe(flags, state);
in_addr_hash_func(&route->prefsrc, route->family, state);
/* nexthops (id, number of nexthops, nexthop) */
route_nexthops_hash_func(route, state);
/* metrics */
route_metric_hash_func(&route->metric, state);
break;
case AF_INET6:
/* First, table and destination prefix are used for classifying routes.
* See fib6_add() and fib6_add_1() in net/ipv6/ip6_fib.c of the kernel. */
siphash24_compress_typesafe(route->table, state);
in_addr_hash_func(&route->dst, route->family, state);
siphash24_compress_typesafe(route->dst_prefixlen, state);
/* Then, source prefix is used. See fib6_add(). */
in_addr_hash_func(&route->src, route->family, state);
siphash24_compress_typesafe(route->src_prefixlen, state);
/* See fib6_add_rt2node(). */
siphash24_compress_typesafe(route->priority, state);
/* See rt6_duplicate_nexthop() in include/net/ip6_route.h of the kernel.
* Here, we hash nexthop in a similar way as the one for IPv4. */
route_nexthops_hash_func(route, state);
/* Unlike IPv4 routes, metrics are not taken into account. */
break;
default:
/* treat any other address family as AF_UNSPEC */
break;
@ -157,8 +177,7 @@ static int route_compare_func(const Route *a, const Route *b) {
switch (a->family) {
case AF_INET:
case AF_INET6:
r = CMP(a->dst_prefixlen, b->dst_prefixlen);
r = CMP(a->table, b->table);
if (r != 0)
return r;
@ -166,33 +185,7 @@ static int route_compare_func(const Route *a, const Route *b) {
if (r != 0)
return r;
r = CMP(a->src_prefixlen, b->src_prefixlen);
if (r != 0)
return r;
r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
r = CMP(a->nexthop.family, b->nexthop.family);
if (r != 0)
return r;
if (IN_SET(a->nexthop.family, AF_INET, AF_INET6)) {
r = memcmp(&a->nexthop.gw, &b->nexthop.gw, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
r = CMP(a->nexthop.weight, b->nexthop.weight);
if (r != 0)
return r;
}
r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
r = CMP(a->tos, b->tos);
r = CMP(a->dst_prefixlen, b->dst_prefixlen);
if (r != 0)
return r;
@ -200,7 +193,7 @@ static int route_compare_func(const Route *a, const Route *b) {
if (r != 0)
return r;
r = CMP(a->table, b->table);
r = CMP(a->tos, b->tos);
if (r != 0)
return r;
@ -216,15 +209,47 @@ static int route_compare_func(const Route *a, const Route *b) {
if (r != 0)
return r;
r = route_metric_compare_func(&a->metric, &b->metric);
r = CMP(a->flags & ~RTNH_COMPARE_MASK, b->flags & ~RTNH_COMPARE_MASK);
if (r != 0)
return r;
r = CMP(a->nexthop_id, b->nexthop_id);
r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
return 0;
r = route_nexthops_compare_func(a, b);
if (r != 0)
return r;
return route_metric_compare_func(&a->metric, &b->metric);
case AF_INET6:
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;
r = CMP(a->dst_prefixlen, b->dst_prefixlen);
if (r != 0)
return r;
r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
r = CMP(a->src_prefixlen, b->src_prefixlen);
if (r != 0)
return r;
r = CMP(a->priority, b->priority);
if (r != 0)
return r;
return route_nexthops_compare_func(a, b);
default:
/* treat any other address family as AF_UNSPEC */
return 0;