route->priority = link->network->dhcp_route_metric;
if (!route->table_set)
route->table = link_get_dhcp4_route_table(link);
- if (route->mtu == 0)
- route->mtu = link->network->dhcp_route_mtu;
- if (route->quickack < 0)
- route->quickack = link->network->dhcp_quickack;
- if (route->initcwnd == 0)
- route->initcwnd = link->network->dhcp_initial_congestion_window;
- if (route->initrwnd == 0)
- route->initrwnd = link->network->dhcp_advertised_receive_window;
+ 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;
if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
link->dhcp4_configured = false;
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->mtu),
+ JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route->metric.mtu),
JSON_BUILD_PAIR_UNSIGNED("Preference", route->pref),
JSON_BUILD_PAIR_UNSIGNED("Flags", route->flags),
JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
ndisc_set_route_priority(link, route);
if (!route->protocol_set)
route->protocol = RTPROT_RA;
- if (route->quickack < 0)
- route->quickack = link->network->ipv6_accept_ra_quickack;
- if (route->mtu == 0)
- route->mtu = mtu;
- if (route->hop_limit == 0)
- route->hop_limit = hop_limit;
+ 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;
is_new = route_get(NULL, link, route, NULL) < 0;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "alloc-util.h"
+#include "netlink-util.h"
#include "networkd-route.h"
#include "networkd-route-metric.h"
#include "parse-util.h"
#include "string-util.h"
+void route_metric_done(RouteMetric *metric) {
+ assert(metric);
+
+ free(metric->tcp_congestion_control_algo);
+}
+
+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;
+
+ return free_and_strdup(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo);
+}
+
+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);
+}
+
+int route_metric_compare_func(const RouteMetric *a, const RouteMetric *b) {
+ int r;
+
+ assert(a);
+ assert(b);
+
+ r = CMP(a->initcwnd, b->initcwnd);
+ if (r != 0)
+ return r;
+
+ r = CMP(a->initrwnd, b->initrwnd);
+ if (r != 0)
+ return r;
+
+ return CMP(a->advmss, b->advmss);
+}
+
+int route_metric_set_netlink_message(const RouteMetric *metric, sd_netlink_message *m) {
+ int r;
+
+ assert(metric);
+ assert(m);
+
+ 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;
+ }
+
+ if (metric->quickack >= 0) {
+ r = sd_netlink_message_append_u32(m, RTAX_QUICKACK, metric->quickack);
+ if (r < 0)
+ return r;
+ }
+
+ 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);
+ if (r < 0)
+ return r;
+ }
+
+ if (!isempty(metric->tcp_congestion_control_algo)) {
+ r = sd_netlink_message_append_string(m, RTAX_CC_ALGO, metric->tcp_congestion_control_algo);
+ if (r < 0)
+ 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;
+
+ return 0;
+}
+
+int route_metric_read_netlink_message(RouteMetric *metric, sd_netlink_message *m) {
+ int r;
+
+ assert(metric);
+ assert(m);
+
+ r = sd_netlink_message_enter_container(m, RTA_METRICS);
+ if (r == -ENODATA)
+ return 0;
+ if (r < 0)
+ return log_warning_errno(r, "rtnl: Could not enter RTA_METRICS container, 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");
+
+ 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");
+
+ 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");
+
+ 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");
+
+ return 0;
+}
+
int config_parse_route_metric_mtu(
const char *unit,
const char *filename,
return 0;
}
- r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, AF_UNSPEC, rvalue, &route->mtu, userdata);
+ r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, AF_UNSPEC, rvalue, &route->metric.mtu, userdata);
if (r <= 0)
return r;
}
if (isempty(rvalue)) {
- route->advmss = 0;
+ route->metric.advmss = 0;
TAKE_PTR(route);
return 0;
}
return 0;
}
- route->advmss = u;
+ route->metric.advmss = u;
TAKE_PTR(route);
return 0;
}
if (isempty(rvalue)) {
- route->hop_limit = 0;
+ route->metric.hop_limit = 0;
TAKE_PTR(route);
return 0;
}
return 0;
}
- route->hop_limit = k;
+ route->metric.hop_limit = k;
TAKE_PTR(route);
return 0;
}
if (streq(lvalue, "InitialCongestionWindow"))
- d = &route->initcwnd;
+ d = &route->metric.initcwnd;
else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
- d = &route->initrwnd;
+ d = &route->metric.initrwnd;
else
assert_not_reached();
return 0;
}
- route->tcp_rto_usec = usec;
+ route->metric.tcp_rto_usec = usec;
TAKE_PTR(route);
return 0;
}
if (streq(lvalue, "QuickAck"))
- route->quickack = r;
+ route->metric.quickack = r;
else if (streq(lvalue, "FastOpenNoCookie"))
- route->fast_open_no_cookie = r;
+ route->metric.fast_open_no_cookie = r;
else
assert_not_reached();
}
r = config_parse_string(unit, filename, line, section, section_line, lvalue, 0,
- rvalue, &route->tcp_congestion_control_algo, userdata);
+ rvalue, &route->metric.tcp_congestion_control_algo, userdata);
if (r < 0)
return r;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "sd-netlink.h"
+
#include "conf-parser.h"
+#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;
+} RouteMetric;
+
+#define ROUTE_METRIC_NULL \
+ ((const RouteMetric) { \
+ .quickack = -1, \
+ .fast_open_no_cookie = -1, \
+ })
+
+void route_metric_done(RouteMetric *metric);
+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_netlink_message(const RouteMetric *metric, sd_netlink_message *m);
+int route_metric_read_netlink_message(RouteMetric *metric, sd_netlink_message *message);
CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_advmss);
.type = RTN_UNICAST,
.table = RT_TABLE_MAIN,
.lifetime_usec = USEC_INFINITY,
- .quickack = -1,
- .fast_open_no_cookie = -1,
+ .metric = ROUTE_METRIC_NULL,
.gateway_onlink = -1,
};
set_remove(route->manager->routes, route);
ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
-
+ route_metric_done(&route->metric);
sd_event_source_disable_unref(route->expire);
- free(route->tcp_congestion_control_algo);
-
return mfree(route);
}
siphash24_compress_typesafe(route->protocol, state);
siphash24_compress_typesafe(route->scope, state);
siphash24_compress_typesafe(route->type, state);
-
- siphash24_compress_typesafe(route->initcwnd, state);
- siphash24_compress_typesafe(route->initrwnd, state);
-
- siphash24_compress_typesafe(route->advmss, state);
+ route_metric_hash_func(&route->metric, state);
siphash24_compress_typesafe(route->nexthop_id, state);
break;
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 = CMP(a->advmss, b->advmss);
+ r = route_metric_compare_func(&a->metric, &b->metric);
if (r != 0)
return r;
dest->link = NULL;
dest->manager = NULL;
dest->multipath_routes = NULL;
+ dest->metric = ROUTE_METRIC_NULL;
dest->expire = NULL;
- dest->tcp_congestion_control_algo = NULL;
- r = free_and_strdup(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo);
+ r = route_metric_copy(&src->metric, &dest->metric);
if (r < 0)
return r;
return r;
}
- r = sd_netlink_message_open_container(m, RTA_METRICS);
- if (r < 0)
- return r;
-
- if (route->mtu > 0) {
- r = sd_netlink_message_append_u32(m, RTAX_MTU, route->mtu);
- if (r < 0)
- return r;
- }
-
- if (route->initcwnd > 0) {
- r = sd_netlink_message_append_u32(m, RTAX_INITCWND, route->initcwnd);
- if (r < 0)
- return r;
- }
-
- if (route->initrwnd > 0) {
- r = sd_netlink_message_append_u32(m, RTAX_INITRWND, route->initrwnd);
- if (r < 0)
- return r;
- }
-
- if (route->quickack >= 0) {
- r = sd_netlink_message_append_u32(m, RTAX_QUICKACK, route->quickack);
- if (r < 0)
- return r;
- }
-
- if (route->fast_open_no_cookie >= 0) {
- r = sd_netlink_message_append_u32(m, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
- if (r < 0)
- return r;
- }
-
- if (route->advmss > 0) {
- r = sd_netlink_message_append_u32(m, RTAX_ADVMSS, route->advmss);
- if (r < 0)
- return r;
- }
-
- if (!isempty(route->tcp_congestion_control_algo)) {
- r = sd_netlink_message_append_string(m, RTAX_CC_ALGO, route->tcp_congestion_control_algo);
- if (r < 0)
- return r;
- }
-
- if (route->hop_limit > 0) {
- r = sd_netlink_message_append_u32(m, RTAX_HOPLIMIT, route->hop_limit);
- if (r < 0)
- return r;
- }
-
- if (route->tcp_rto_usec > 0) {
- r = sd_netlink_message_append_u32(m, RTAX_RTO_MIN, DIV_ROUND_UP(route->tcp_rto_usec, USEC_PER_MSEC));
- if (r < 0)
- return r;
- }
-
- r = sd_netlink_message_close_container(m);
+ /* metrics */
+ r = route_metric_set_netlink_message(&route->metric, m);
if (r < 0)
return r;
return 0;
}
- 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, ignoring: %m");
+ /* metrics */
+ if (route_metric_read_netlink_message(&tmp->metric, message) < 0)
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_read_u32(message, RTAX_ADVMSS, &tmp->advmss);
- if (r < 0 && r != -ENODATA) {
- log_link_warning_errno(link, r, "rtnl: received route message with invalid advmss, 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, ignoring: %m");
- return 0;
- }
- }
r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
if (r < 0 && r != -ENODATA) {
int family;
int gw_family;
uint32_t gw_weight;
- int quickack;
- int fast_open_no_cookie;
unsigned char dst_prefixlen;
unsigned char src_prefixlen;
unsigned char tos;
uint32_t priority; /* note that ip(8) calls this 'metric' */
uint32_t table;
- uint32_t mtu;
- uint32_t initcwnd;
- uint32_t initrwnd;
- uint32_t advmss;
- uint32_t hop_limit;
- char *tcp_congestion_control_algo;
unsigned char pref;
unsigned flags;
int gateway_onlink; /* Only used in conf parser and route_section_verify(). */
uint32_t nexthop_id;
- usec_t tcp_rto_usec;
+
+ /* metrics (RTA_METRICS) */
+ RouteMetric metric;
bool scope_set:1;
bool table_set:1;