diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-10-28 12:55:59 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-10-28 15:48:28 +0900 |
commit | 6f812d289946a3e0e386378263b40d09e125752e (patch) | |
tree | 0d617bec9c7a5791cae07285fa4179dbda6c4eac /src/network/networkd-dhcp-common.c | |
parent | 6fadf01cf3cdd98f78b7829f4c6c892306958394 (diff) | |
download | systemd-6f812d289946a3e0e386378263b40d09e125752e.tar.gz |
network: adjust route priority based on preference
Even if different preference is specified, the kernel merges multiple
routes with the same preference. This is problematic when a network has
multiple routers.
Fixes #25138.
Diffstat (limited to 'src/network/networkd-dhcp-common.c')
-rw-r--r-- | src/network/networkd-dhcp-common.c | 73 |
1 files changed, 65 insertions, 8 deletions
diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 6526d3378f..2a80b1766e 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -303,7 +303,7 @@ int config_parse_dhcp( return 0; } -int config_parse_dhcp_or_ra_route_metric( +int config_parse_dhcp_route_metric( const char* unit, const char *filename, unsigned line, @@ -321,7 +321,7 @@ int config_parse_dhcp_or_ra_route_metric( assert(filename); assert(lvalue); - assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6)); + assert(IN_SET(ltype, AF_UNSPEC, AF_INET)); assert(rvalue); assert(data); @@ -337,16 +337,15 @@ int config_parse_dhcp_or_ra_route_metric( network->dhcp_route_metric = metric; network->dhcp_route_metric_set = true; break; - case AF_INET6: - network->ipv6_accept_ra_route_metric = metric; - network->ipv6_accept_ra_route_metric_set = true; - break; case AF_UNSPEC: /* For backward compatibility. */ if (!network->dhcp_route_metric_set) network->dhcp_route_metric = metric; - if (!network->ipv6_accept_ra_route_metric_set) - network->ipv6_accept_ra_route_metric = metric; + if (!network->ipv6_accept_ra_route_metric_set) { + network->ipv6_accept_ra_route_metric_high = metric; + network->ipv6_accept_ra_route_metric_medium = metric; + network->ipv6_accept_ra_route_metric_low = metric; + } break; default: assert_not_reached(); @@ -355,6 +354,64 @@ int config_parse_dhcp_or_ra_route_metric( return 0; } +int config_parse_ipv6_accept_ra_route_metric( + 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); + uint32_t metric_high, metric_medium, metric_low; + int r, s, t; + + assert(filename); + assert(rvalue); + + if (safe_atou32(rvalue, &metric_low) >= 0) + metric_high = metric_medium = metric_low; + else { + _cleanup_free_ char *high = NULL, *medium = NULL, *low = NULL; + const char *p = rvalue; + + r = extract_many_words(&p, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &high, &medium, &low, NULL); + if (r == -ENOMEM) + return log_oom(); + if (r != 3 || !isempty(p)) { + log_syntax(unit, LOG_WARNING, filename, line, r < 0 ? r : 0, + "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue); + return 0; + } + + r = safe_atou32(high, &metric_high); + s = safe_atou32(medium, &metric_medium); + t = safe_atou32(low, &metric_low); + if (r < 0 || s < 0 || t < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r < 0 ? r : s < 0 ? s : t, + "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue); + return 0; + } + + if (metric_high >= metric_medium || metric_medium >= metric_low) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid RouteTable=%s, ignoring assignment: %m", rvalue); + return 0; + } + } + + network->ipv6_accept_ra_route_metric_high = metric_high; + network->ipv6_accept_ra_route_metric_medium = metric_medium; + network->ipv6_accept_ra_route_metric_low = metric_low; + network->ipv6_accept_ra_route_metric_set = true; + + return 0; +} + int config_parse_dhcp_use_dns( const char* unit, const char *filename, |