From: Yu Watanabe Date: Sun, 7 Jan 2024 01:36:41 +0000 (+0900) Subject: network/route-metric: manage uint32_t RTAX_XYZ attributes in the same way X-Git-Tag: v256-rc1~1204^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ebf4fa1e82b71cb743518fa22dafb6860fd78bcf;p=thirdparty%2Fsystemd.git network/route-metric: manage uint32_t RTAX_XYZ attributes in the same way Except for RTAX_CC_ALGO, all RTAX_XYZ attributes take uint32_t and the kernel's default value is zero. So, let's unify handling of the attributes. This should not change any effective behavior. Just refactoring. --- diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 4fada25a9c2..64c84f42625 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -380,14 +380,18 @@ static int dhcp4_request_route(Route *in, Link *link) { route->priority = link->network->dhcp_route_metric; if (!route->table_set) route->table = link_get_dhcp4_route_table(link); - if (route->metric.mtu == 0) - route->metric.mtu = link->network->dhcp_route_mtu; - if (route->metric.quickack < 0) - route->metric.quickack = link->network->dhcp_quickack; - if (route->metric.initcwnd == 0) - route->metric.initcwnd = link->network->dhcp_initial_congestion_window; - if (route->metric.initrwnd == 0) - route->metric.initrwnd = link->network->dhcp_advertised_receive_window; + r = route_metric_set(&route->metric, RTAX_MTU, link->network->dhcp_route_mtu); + if (r < 0) + return r; + r = route_metric_set(&route->metric, RTAX_INITCWND, link->network->dhcp_initial_congestion_window); + if (r < 0) + return r; + r = route_metric_set(&route->metric, RTAX_INITRWND, link->network->dhcp_advertised_receive_window); + if (r < 0) + return r; + r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->dhcp_quickack); + if (r < 0) + return r; if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */ link->dhcp4_configured = false; diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 7b703bdfef3..e62e57b7652 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -251,7 +251,7 @@ static int route_append_json(Route *route, JsonVariant **array) { JSON_BUILD_PAIR_UNSIGNED("Priority", route->priority), JSON_BUILD_PAIR_UNSIGNED("Table", route->table), JSON_BUILD_PAIR_STRING("TableString", table), - JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route->metric.mtu), + JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route_metric_get(&route->metric, RTAX_MTU)), JSON_BUILD_PAIR_UNSIGNED("Preference", route->pref), JSON_BUILD_PAIR_UNSIGNED("Flags", route->flags), JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)), diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index ee9e2448f35..43c0cd3ad4a 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -208,12 +208,15 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) { ndisc_set_route_priority(link, route); if (!route->protocol_set) route->protocol = RTPROT_RA; - if (route->metric.quickack < 0) - route->metric.quickack = link->network->ipv6_accept_ra_quickack; - if (route->metric.mtu == 0) - route->metric.mtu = mtu; - if (route->metric.hop_limit == 0) - route->metric.hop_limit = hop_limit; + r = route_metric_set(&route->metric, RTAX_MTU, mtu); + if (r < 0) + return r; + r = route_metric_set(&route->metric, RTAX_HOPLIMIT, hop_limit); + if (r < 0) + return r; + r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ipv6_accept_ra_quickack); + if (r < 0) + return r; is_new = route_get(NULL, link, route, NULL) < 0; diff --git a/src/network/networkd-route-metric.c b/src/network/networkd-route-metric.c index 4c74a5d792b..01ebbbc68d4 100644 --- a/src/network/networkd-route-metric.c +++ b/src/network/networkd-route-metric.c @@ -10,6 +10,8 @@ void route_metric_done(RouteMetric *metric) { assert(metric); + free(metric->metrics); + free(metric->metrics_set); free(metric->tcp_congestion_control_algo); } @@ -17,14 +19,25 @@ int route_metric_copy(const RouteMetric *src, RouteMetric *dest) { assert(src); assert(dest); - dest->quickack = src->quickack; - dest->fast_open_no_cookie = src->fast_open_no_cookie; - dest->mtu = src->mtu; - dest->initcwnd = src->initcwnd; - dest->initrwnd = src->initrwnd; - dest->advmss = src->advmss; - dest->hop_limit = src->hop_limit; - dest->tcp_rto_usec = src->tcp_rto_usec; + dest->n_metrics = src->n_metrics; + if (src->n_metrics > 0) { + assert(src->n_metrics != 1); + + dest->metrics = newdup(uint32_t, src->metrics, src->n_metrics); + if (!dest->metrics) + return -ENOMEM; + } else + dest->metrics = NULL; + + dest->n_metrics_set = src->n_metrics_set; + if (src->n_metrics_set > 0) { + assert(src->n_metrics_set != 1); + + dest->metrics_set = newdup(bool, src->metrics_set, src->n_metrics_set); + if (!dest->metrics_set) + return -ENOMEM; + } else + dest->metrics_set = NULL; return free_and_strdup(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo); } @@ -32,9 +45,9 @@ int route_metric_copy(const RouteMetric *src, RouteMetric *dest) { void route_metric_hash_func(const RouteMetric *metric, struct siphash *state) { assert(metric); - siphash24_compress_typesafe(metric->initcwnd, state); - siphash24_compress_typesafe(metric->initrwnd, state); - siphash24_compress_typesafe(metric->advmss, state); + siphash24_compress_typesafe(metric->n_metrics, state); + siphash24_compress_safe(metric->metrics, sizeof(uint32_t) * metric->n_metrics, state); + siphash24_compress_string(metric->tcp_congestion_control_algo, state); } int route_metric_compare_func(const RouteMetric *a, const RouteMetric *b) { @@ -43,15 +56,68 @@ int route_metric_compare_func(const RouteMetric *a, const RouteMetric *b) { assert(a); assert(b); - r = CMP(a->initcwnd, b->initcwnd); + r = memcmp_nn(a->metrics, a->n_metrics * sizeof(uint32_t), b->metrics, b->n_metrics * sizeof(uint32_t)); if (r != 0) return r; - r = CMP(a->initrwnd, b->initrwnd); - if (r != 0) - return r; + return strcmp_ptr(a->tcp_congestion_control_algo, b->tcp_congestion_control_algo); +} + +int route_metric_set_full(RouteMetric *metric, uint16_t attr, uint32_t value, bool force) { + assert(metric); + + if (force) { + if (!GREEDY_REALLOC0(metric->metrics_set, attr + 1)) + return -ENOMEM; + + metric->metrics_set[attr] = true; + metric->n_metrics_set = MAX(metric->n_metrics_set, (size_t) (attr + 1)); + } else { + /* Do not override the values specified in conf parsers. */ + if (metric->n_metrics_set > attr && metric->metrics_set[attr]) + return 0; + } + + if (value != 0) { + if (!GREEDY_REALLOC0(metric->metrics, attr + 1)) + return -ENOMEM; + + metric->metrics[attr] = value; + metric->n_metrics = MAX(metric->n_metrics, (size_t) (attr + 1)); + return 0; + } + + if (metric->n_metrics <= attr) + return 0; + + metric->metrics[attr] = 0; + + for (size_t i = metric->n_metrics; i > 0; i--) + if (metric->metrics[i-1] != 0) { + metric->n_metrics = i; + return 0; + } - return CMP(a->advmss, b->advmss); + metric->n_metrics = 0; + return 0; +} + +static void route_metric_unset(RouteMetric *metric, uint16_t attr) { + assert(metric); + + if (metric->n_metrics_set > attr) + metric->metrics_set[attr] = false; + + assert_se(route_metric_set_full(metric, attr, 0, /* force = */ false) >= 0); +} + +uint32_t route_metric_get(const RouteMetric *metric, uint16_t attr) { + assert(metric); + + if (metric->n_metrics <= attr) + return 0; + + return metric->metrics[attr]; } int route_metric_set_netlink_message(const RouteMetric *metric, sd_netlink_message *m) { @@ -60,42 +126,21 @@ int route_metric_set_netlink_message(const RouteMetric *metric, sd_netlink_messa assert(metric); assert(m); + if (metric->n_metrics <= 0 && isempty(metric->tcp_congestion_control_algo)) + return 0; + r = sd_netlink_message_open_container(m, RTA_METRICS); if (r < 0) return r; - if (metric->mtu > 0) { - r = sd_netlink_message_append_u32(m, RTAX_MTU, metric->mtu); - if (r < 0) - return r; - } - - if (metric->initcwnd > 0) { - r = sd_netlink_message_append_u32(m, RTAX_INITCWND, metric->initcwnd); - if (r < 0) - return r; - } - - if (metric->initrwnd > 0) { - r = sd_netlink_message_append_u32(m, RTAX_INITRWND, metric->initrwnd); - if (r < 0) - return r; - } + for (size_t i = 0; i < metric->n_metrics; i++) { + if (i == RTAX_CC_ALGO) + continue; - if (metric->quickack >= 0) { - r = sd_netlink_message_append_u32(m, RTAX_QUICKACK, metric->quickack); - if (r < 0) - return r; - } + if (metric->metrics[i] == 0) + continue; - if (metric->fast_open_no_cookie >= 0) { - r = sd_netlink_message_append_u32(m, RTAX_FASTOPEN_NO_COOKIE, metric->fast_open_no_cookie); - if (r < 0) - return r; - } - - if (metric->advmss > 0) { - r = sd_netlink_message_append_u32(m, RTAX_ADVMSS, metric->advmss); + r = sd_netlink_message_append_u32(m, i, metric->metrics[i]); if (r < 0) return r; } @@ -106,18 +151,6 @@ int route_metric_set_netlink_message(const RouteMetric *metric, sd_netlink_messa return r; } - if (metric->hop_limit > 0) { - r = sd_netlink_message_append_u32(m, RTAX_HOPLIMIT, metric->hop_limit); - if (r < 0) - return r; - } - - if (metric->tcp_rto_usec > 0) { - r = sd_netlink_message_append_u32(m, RTAX_RTO_MIN, DIV_ROUND_UP(metric->tcp_rto_usec, USEC_PER_MSEC)); - if (r < 0) - return r; - } - r = sd_netlink_message_close_container(m); if (r < 0) return r; @@ -126,32 +159,38 @@ int route_metric_set_netlink_message(const RouteMetric *metric, sd_netlink_messa } int route_metric_read_netlink_message(RouteMetric *metric, sd_netlink_message *m) { + _cleanup_free_ void *data = NULL; + size_t len; int r; assert(metric); assert(m); - r = sd_netlink_message_enter_container(m, RTA_METRICS); + r = sd_netlink_message_read_data(m, RTA_METRICS, &len, &data); if (r == -ENODATA) return 0; if (r < 0) - return log_warning_errno(r, "rtnl: Could not enter RTA_METRICS container, ignoring: %m"); + return log_warning_errno(r, "rtnl: Could not read RTA_METRICS attribute, ignoring: %m"); - r = sd_netlink_message_read_u32(m, RTAX_INITCWND, &metric->initcwnd); - if (r < 0 && r != -ENODATA) - return log_warning_errno(r, "rtnl: received route message with invalid initcwnd, ignoring: %m"); + for (struct rtattr *rta = data; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + size_t rta_type = RTA_TYPE(rta); - r = sd_netlink_message_read_u32(m, RTAX_INITRWND, &metric->initrwnd); - if (r < 0 && r != -ENODATA) - return log_warning_errno(r, "rtnl: received route message with invalid initrwnd, ignoring: %m"); + if (rta_type == RTAX_CC_ALGO) { + char *p = memdup_suffix0(RTA_DATA(rta), RTA_PAYLOAD(rta)); + if (!p) + return log_oom(); - r = sd_netlink_message_read_u32(m, RTAX_ADVMSS, &metric->advmss); - if (r < 0 && r != -ENODATA) - return log_warning_errno(r, "rtnl: received route message with invalid advmss, ignoring: %m"); + free_and_replace(metric->tcp_congestion_control_algo, p); - r = sd_netlink_message_exit_container(m); - if (r < 0) - return log_warning_errno(r, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m"); + } else { + if (RTA_PAYLOAD(rta) != sizeof(uint32_t)) + continue; + + r = route_metric_set(metric, rta_type, *(uint32_t*) RTA_DATA(rta)); + if (r < 0) + return log_oom(); + } + } return 0; } @@ -187,10 +226,14 @@ int config_parse_route_metric_mtu( return 0; } - r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, AF_UNSPEC, rvalue, &route->metric.mtu, userdata); + uint32_t k; + r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, AF_UNSPEC, rvalue, &k, userdata); if (r <= 0) return r; + if (route_metric_set_full(&route->metric, ltype, k, /* force = */ true) < 0) + return log_oom(); + TAKE_PTR(route); return 0; } @@ -228,7 +271,7 @@ int config_parse_route_metric_advmss( } if (isempty(rvalue)) { - route->metric.advmss = 0; + route_metric_unset(&route->metric, ltype); TAKE_PTR(route); return 0; } @@ -246,7 +289,8 @@ int config_parse_route_metric_advmss( return 0; } - route->metric.advmss = u; + if (route_metric_set_full(&route->metric, ltype, u, /* force = */ true) < 0) + return log_oom(); TAKE_PTR(route); return 0; @@ -285,7 +329,7 @@ int config_parse_route_metric_hop_limit( } if (isempty(rvalue)) { - route->metric.hop_limit = 0; + route_metric_unset(&route->metric, ltype); TAKE_PTR(route); return 0; } @@ -302,7 +346,8 @@ int config_parse_route_metric_hop_limit( return 0; } - route->metric.hop_limit = k; + if (route_metric_set_full(&route->metric, ltype, k, /* force = */ true) < 0) + return log_oom(); TAKE_PTR(route); return 0; @@ -343,7 +388,7 @@ int config_parse_tcp_window( } *window = k; - return 0; + return 1; } int config_parse_route_metric_tcp_window( @@ -360,7 +405,6 @@ int config_parse_route_metric_tcp_window( _cleanup_(route_free_or_set_invalidp) Route *route = NULL; Network *network = userdata; - uint32_t *d; int r; assert(filename); @@ -378,17 +422,14 @@ int config_parse_route_metric_tcp_window( return 0; } - if (streq(lvalue, "InitialCongestionWindow")) - d = &route->metric.initcwnd; - else if (streq(lvalue, "InitialAdvertisedReceiveWindow")) - d = &route->metric.initrwnd; - else - assert_not_reached(); - - r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, d, userdata); - if (r < 0) + uint32_t k; + r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata); + if (r <= 0) return r; + if (route_metric_set_full(&route->metric, ltype, k, /* force = */ true) < 0) + return log_oom(); + TAKE_PTR(route); return 0; } @@ -439,7 +480,8 @@ int config_parse_route_metric_tcp_rto( return 0; } - route->metric.tcp_rto_usec = usec; + if (route_metric_set_full(&route->metric, ltype, DIV_ROUND_UP(usec, USEC_PER_MSEC), /* force = */ true) < 0) + return log_oom(); TAKE_PTR(route); return 0; @@ -483,12 +525,8 @@ int config_parse_route_metric_boolean( return 0; } - if (streq(lvalue, "QuickAck")) - route->metric.quickack = r; - else if (streq(lvalue, "FastOpenNoCookie")) - route->metric.fast_open_no_cookie = r; - else - assert_not_reached(); + if (route_metric_set_full(&route->metric, ltype, r, /* force = */ true) < 0) + return log_oom(); TAKE_PTR(route); return 0; diff --git a/src/network/networkd-route-metric.h b/src/network/networkd-route-metric.h index 8f447f6e811..1a3aaf2ae59 100644 --- a/src/network/networkd-route-metric.h +++ b/src/network/networkd-route-metric.h @@ -10,22 +10,16 @@ #include "hash-funcs.h" typedef struct RouteMetric { - int quickack; - int fast_open_no_cookie; - uint32_t mtu; - uint32_t initcwnd; - uint32_t initrwnd; - uint32_t advmss; - uint32_t hop_limit; - char *tcp_congestion_control_algo; - usec_t tcp_rto_usec; + size_t n_metrics; /* maximum metric attr type with non-zero value */ + uint32_t *metrics; /* RTAX_*, except for RTAX_CC_ALGO */ + + size_t n_metrics_set; + bool *metrics_set; /* used by conf parsers */ + + char *tcp_congestion_control_algo; /* RTAX_CC_ALGO */ } RouteMetric; -#define ROUTE_METRIC_NULL \ - ((const RouteMetric) { \ - .quickack = -1, \ - .fast_open_no_cookie = -1, \ - }) +#define ROUTE_METRIC_NULL ((const RouteMetric) {}) void route_metric_done(RouteMetric *metric); int route_metric_copy(const RouteMetric *src, RouteMetric *dest); @@ -33,6 +27,12 @@ int route_metric_copy(const RouteMetric *src, RouteMetric *dest); void route_metric_hash_func(const RouteMetric *metric, struct siphash *state); int route_metric_compare_func(const RouteMetric *a, const RouteMetric *b); +int route_metric_set_full(RouteMetric *metric, uint16_t attr, uint32_t value, bool force); +static inline int route_metric_set(RouteMetric *metric, uint16_t attr, uint32_t value) { + return route_metric_set_full(metric, attr, value, false); +} +uint32_t route_metric_get(const RouteMetric *metric, uint16_t attr); + int route_metric_set_netlink_message(const RouteMetric *metric, sd_netlink_message *m); int route_metric_read_netlink_message(RouteMetric *metric, sd_netlink_message *message); diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 4fe2bd49bd7..0553a663438 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -35,7 +35,6 @@ int route_new(Route **ret) { .type = RTN_UNICAST, .table = RT_TABLE_MAIN, .lifetime_usec = USEC_INFINITY, - .metric = ROUTE_METRIC_NULL, .gateway_onlink = -1, };