Merge pull request #30811 from yuwata/network-route-metric
network/route-metric: introduce RouteMetric to unify route metric handling
This commit is contained in:
@@ -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->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;
|
||||
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;
|
||||
|
||||
@@ -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->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)),
|
||||
|
||||
@@ -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->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;
|
||||
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;
|
||||
|
||||
|
||||
+264
-187
@@ -1,50 +1,201 @@
|
||||
/* 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"
|
||||
|
||||
int config_parse_route_metric_mtu(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
void route_metric_done(RouteMetric *metric) {
|
||||
assert(metric);
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
free(metric->metrics);
|
||||
free(metric->metrics_set);
|
||||
free(metric->tcp_congestion_control_algo);
|
||||
}
|
||||
|
||||
int route_metric_copy(const RouteMetric *src, RouteMetric *dest) {
|
||||
assert(src);
|
||||
assert(dest);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void route_metric_hash_func(const RouteMetric *metric, struct siphash *state) {
|
||||
assert(metric);
|
||||
|
||||
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) {
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to allocate route, ignoring assignment: %m");
|
||||
r = memcmp_nn(a->metrics, a->n_metrics * sizeof(uint32_t), b->metrics, b->n_metrics * sizeof(uint32_t));
|
||||
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;
|
||||
}
|
||||
|
||||
r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, AF_UNSPEC, rvalue, &route->mtu, userdata);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
if (metric->n_metrics <= attr)
|
||||
return 0;
|
||||
|
||||
TAKE_PTR(route);
|
||||
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;
|
||||
}
|
||||
|
||||
metric->n_metrics = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_route_metric_advmss(
|
||||
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) {
|
||||
int r;
|
||||
|
||||
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;
|
||||
|
||||
for (size_t i = 0; i < metric->n_metrics; i++) {
|
||||
if (i == RTAX_CC_ALGO)
|
||||
continue;
|
||||
|
||||
if (metric->metrics[i] == 0)
|
||||
continue;
|
||||
|
||||
r = sd_netlink_message_append_u32(m, i, metric->metrics[i]);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
_cleanup_free_ void *data = NULL;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
assert(metric);
|
||||
assert(m);
|
||||
|
||||
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 read RTA_METRICS attribute, ignoring: %m");
|
||||
|
||||
for (struct rtattr *rta = data; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
|
||||
size_t rta_type = RTA_TYPE(rta);
|
||||
|
||||
if (rta_type == RTAX_CC_ALGO) {
|
||||
char *p = memdup_suffix0(RTA_DATA(rta), RTA_PAYLOAD(rta));
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
free_and_replace(metric->tcp_congestion_control_algo, p);
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
static int config_parse_route_metric_advmss_impl(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@@ -56,31 +207,11 @@ int config_parse_route_metric_advmss(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
Network *network = userdata;
|
||||
uint32_t *val = ASSERT_PTR(data);
|
||||
uint64_t u;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to allocate route, ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
route->advmss = 0;
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_size(rvalue, 1024, &u);
|
||||
if (r < 0) {
|
||||
@@ -95,13 +226,11 @@ int config_parse_route_metric_advmss(
|
||||
return 0;
|
||||
}
|
||||
|
||||
route->advmss = u;
|
||||
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
*val = (uint32_t) u;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_route_metric_hop_limit(
|
||||
static int config_parse_route_metric_hop_limit_impl(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@@ -113,31 +242,10 @@ int config_parse_route_metric_hop_limit(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
Network *network = userdata;
|
||||
uint32_t k;
|
||||
uint32_t k, *val = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to allocate route, ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
route->hop_limit = 0;
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &k);
|
||||
if (r < 0) {
|
||||
@@ -151,10 +259,8 @@ int config_parse_route_metric_hop_limit(
|
||||
return 0;
|
||||
}
|
||||
|
||||
route->hop_limit = k;
|
||||
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
*val = k;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_tcp_window(
|
||||
@@ -169,15 +275,10 @@ int config_parse_tcp_window(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
uint32_t *window = ASSERT_PTR(data);
|
||||
uint32_t k;
|
||||
uint32_t k, *val = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = safe_atou32(rvalue, &k);
|
||||
if (r < 0) {
|
||||
@@ -191,11 +292,11 @@ int config_parse_tcp_window(
|
||||
return 0;
|
||||
}
|
||||
|
||||
*window = k;
|
||||
return 0;
|
||||
*val = k;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_route_metric_tcp_window(
|
||||
static int config_parse_route_metric_tcp_rto_impl(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@@ -207,72 +308,11 @@ int config_parse_route_metric_tcp_window(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
Network *network = userdata;
|
||||
uint32_t *d;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to allocate route, ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(lvalue, "InitialCongestionWindow"))
|
||||
d = &route->initcwnd;
|
||||
else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
|
||||
d = &route->initrwnd;
|
||||
else
|
||||
assert_not_reached();
|
||||
|
||||
r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, d, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_route_metric_tcp_rto(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
uint32_t *val = ASSERT_PTR(data);
|
||||
usec_t usec;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to allocate route, ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_sec(rvalue, &usec);
|
||||
if (r < 0) {
|
||||
@@ -288,13 +328,11 @@ int config_parse_route_metric_tcp_rto(
|
||||
return 0;
|
||||
}
|
||||
|
||||
route->tcp_rto_usec = usec;
|
||||
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
*val = (uint32_t) DIV_ROUND_UP(usec, USEC_PER_MSEC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_route_metric_boolean(
|
||||
static int config_parse_route_metric_boolean_impl(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@@ -306,24 +344,10 @@ int config_parse_route_metric_boolean(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
uint32_t *val = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to allocate route, ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r < 0) {
|
||||
@@ -332,17 +356,73 @@ int config_parse_route_metric_boolean(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(lvalue, "QuickAck"))
|
||||
route->quickack = r;
|
||||
else if (streq(lvalue, "FastOpenNoCookie"))
|
||||
route->fast_open_no_cookie = r;
|
||||
else
|
||||
assert_not_reached();
|
||||
|
||||
TAKE_PTR(route);
|
||||
return 0;
|
||||
*val = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define DEFINE_CONFIG_PARSE_ROUTE_METRIC(name, parser) \
|
||||
int config_parse_route_metric_##name( \
|
||||
const char *unit, \
|
||||
const char *filename, \
|
||||
unsigned line, \
|
||||
const char *section, \
|
||||
unsigned section_line, \
|
||||
const char *lvalue, \
|
||||
int ltype, \
|
||||
const char *rvalue, \
|
||||
void *data, \
|
||||
void *userdata) { \
|
||||
\
|
||||
Network *network = ASSERT_PTR(userdata); \
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL; \
|
||||
uint16_t attr_type = ltype; \
|
||||
int r; \
|
||||
\
|
||||
assert(filename); \
|
||||
assert(section); \
|
||||
assert(lvalue); \
|
||||
assert(rvalue); \
|
||||
\
|
||||
r = route_new_static(network, filename, section_line, &route); \
|
||||
if (r == -ENOMEM) \
|
||||
return log_oom(); \
|
||||
if (r < 0) { \
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, \
|
||||
"Failed to allocate route, ignoring assignment: %m"); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
if (isempty(rvalue)) { \
|
||||
route_metric_unset(&route->metric, attr_type); \
|
||||
TAKE_PTR(route); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
uint32_t k; \
|
||||
r = parser(unit, filename, line, section, section_line, \
|
||||
lvalue, /* ltype = */ 0, rvalue, \
|
||||
&k, userdata); \
|
||||
if (r <= 0) \
|
||||
return r; \
|
||||
\
|
||||
if (route_metric_set_full( \
|
||||
&route->metric, \
|
||||
attr_type, \
|
||||
k, \
|
||||
/* force = */ true) < 0) \
|
||||
return log_oom(); \
|
||||
\
|
||||
TAKE_PTR(route); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
DEFINE_CONFIG_PARSE_ROUTE_METRIC(mtu, config_parse_mtu);
|
||||
DEFINE_CONFIG_PARSE_ROUTE_METRIC(advmss, config_parse_route_metric_advmss_impl);
|
||||
DEFINE_CONFIG_PARSE_ROUTE_METRIC(hop_limit, config_parse_route_metric_hop_limit_impl);
|
||||
DEFINE_CONFIG_PARSE_ROUTE_METRIC(tcp_window, config_parse_tcp_window);
|
||||
DEFINE_CONFIG_PARSE_ROUTE_METRIC(tcp_rto, config_parse_route_metric_tcp_rto_impl);
|
||||
DEFINE_CONFIG_PARSE_ROUTE_METRIC(boolean, config_parse_route_metric_boolean_impl);
|
||||
|
||||
int config_parse_route_metric_tcp_congestion(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@@ -355,15 +435,12 @@ int config_parse_route_metric_tcp_congestion(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
Network *network = ASSERT_PTR(userdata);
|
||||
_cleanup_(route_free_or_set_invalidp) Route *route = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_new_static(network, filename, section_line, &route);
|
||||
if (r == -ENOMEM)
|
||||
@@ -375,8 +452,8 @@ int config_parse_route_metric_tcp_congestion(
|
||||
}
|
||||
|
||||
r = config_parse_string(unit, filename, line, section, section_line, lvalue, 0,
|
||||
rvalue, &route->tcp_congestion_control_algo, userdata);
|
||||
if (r < 0)
|
||||
rvalue, &route->metric.tcp_congestion_control_algo, userdata);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(route);
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
/* 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 {
|
||||
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) {})
|
||||
|
||||
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_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);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_mtu);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_advmss);
|
||||
|
||||
@@ -35,8 +35,6 @@ int route_new(Route **ret) {
|
||||
.type = RTN_UNICAST,
|
||||
.table = RT_TABLE_MAIN,
|
||||
.lifetime_usec = USEC_INFINITY,
|
||||
.quickack = -1,
|
||||
.fast_open_no_cookie = -1,
|
||||
.gateway_onlink = -1,
|
||||
};
|
||||
|
||||
@@ -103,11 +101,9 @@ Route *route_free(Route *route) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -139,11 +135,7 @@ static void route_hash_func(const Route *route, struct siphash *state) {
|
||||
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;
|
||||
@@ -221,15 +213,7 @@ static int route_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 = CMP(a->advmss, b->advmss);
|
||||
r = route_metric_compare_func(&a->metric, &b->metric);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
@@ -337,10 +321,10 @@ int route_dup(const Route *src, Route **ret) {
|
||||
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;
|
||||
|
||||
@@ -1187,65 +1171,8 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
|
||||
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;
|
||||
|
||||
@@ -1851,36 +1778,9 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||
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) {
|
||||
|
||||
@@ -36,8 +36,6 @@ struct Route {
|
||||
int family;
|
||||
int gw_family;
|
||||
uint32_t gw_weight;
|
||||
int quickack;
|
||||
int fast_open_no_cookie;
|
||||
|
||||
unsigned char dst_prefixlen;
|
||||
unsigned char src_prefixlen;
|
||||
@@ -47,17 +45,13 @@ struct Route {
|
||||
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;
|
||||
|
||||
@@ -1088,6 +1088,7 @@ int config_parse_string(
|
||||
void *userdata) {
|
||||
|
||||
char **s = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@@ -1095,7 +1096,7 @@ int config_parse_string(
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*s = mfree(*s);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
|
||||
@@ -1116,7 +1117,11 @@ int config_parse_string(
|
||||
return 0;
|
||||
}
|
||||
|
||||
return free_and_strdup_warn(s, empty_to_null(rvalue));
|
||||
r = free_and_strdup_warn(s, empty_to_null(rvalue));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_dns_name(
|
||||
|
||||
Reference in New Issue
Block a user