<varlistentry>
<term><varname>RouteMetric=</varname></term>
<listitem>
- <para>Set the routing metric for the routes received in the Router Advertisement. Takes an
- unsigned integer in the range 0…4294967295. Defaults to 1024.</para>
+ <para>Set the routing metric for the routes received in the Router Advertisement. Takes an unsigned
+ integer in the range 0…4294967295, or three unsigned integer separated with <literal>:</literal>,
+ in that case the first one is used when the router preference is high, the second is for medium
+ preference, and the last is for low preference
+ (<literal><replaceable>high</replaceable>:<replaceable>medium</replaceable>:<replaceable>low</replaceable></literal>).
+ Defaults to <literal>512:1024:2048</literal>.</para>
</listitem>
</varlistentry>
return 0;
}
-int config_parse_dhcp_or_ra_route_metric(
+int config_parse_dhcp_route_metric(
const char* unit,
const char *filename,
unsigned line,
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);
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();
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,
#define UPLINK_INDEX_SELF -2 /* the interface itself is uplink */
#define DHCP_ROUTE_METRIC 1024
+#define IPV6RA_ROUTE_METRIC_HIGH 512
+#define IPV6RA_ROUTE_METRIC_MEDIUM 1024
+#define IPV6RA_ROUTE_METRIC_LOW 2048
#define DHCP6PD_ROUTE_METRIC 256
typedef struct Link Link;
DHCPOptionDataType dhcp_option_data_type_from_string(const char *d) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_or_ra_route_metric);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_route_metric);
+CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
return 1;
}
+static void ndisc_set_route_priority(Link *link, Route *route) {
+ assert(link);
+ assert(route);
+
+ if (route->priority_set)
+ return; /* explicitly configured. */
+
+ switch (route->pref) {
+ case SD_NDISC_PREFERENCE_LOW:
+ route->priority = link->network->ipv6_accept_ra_route_metric_low;
+ break;
+ case SD_NDISC_PREFERENCE_MEDIUM:
+ route->priority = link->network->ipv6_accept_ra_route_metric_medium;
+ break;
+ case SD_NDISC_PREFERENCE_HIGH:
+ route->priority = link->network->ipv6_accept_ra_route_metric_high;
+ break;
+ default:
+ assert_not_reached();
+ }
+}
+
static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = in;
struct in6_addr router;
route->provider.in6 = router;
if (!route->table_set)
route->table = link_get_ipv6_accept_ra_route_table(link);
- if (!route->priority_set)
- route->priority = link->network->ipv6_accept_ra_route_metric;
+ ndisc_set_route_priority(link, route);
if (!route->protocol_set)
route->protocol = RTPROT_RA;
DHCPv4.IAID, config_parse_iaid, AF_INET, 0
DHCPv4.DUIDType, config_parse_network_duid_type, 0, 0
DHCPv4.DUIDRawData, config_parse_network_duid_rawdata, 0, 0
-DHCPv4.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_INET, 0
+DHCPv4.RouteMetric, config_parse_dhcp_route_metric, AF_INET, 0
DHCPv4.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET, 0
DHCPv4.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
IPv6AcceptRA.UseMTU, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_mtu)
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET6, 0
-IPv6AcceptRA.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_INET6, 0
+IPv6AcceptRA.RouteMetric, config_parse_ipv6_accept_ra_route_metric, 0, 0
IPv6AcceptRA.RouterAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_router)
IPv6AcceptRA.RouterDenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_router)
IPv6AcceptRA.PrefixAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_prefix)
DHCP.IAID, config_parse_iaid, AF_INET, 0
DHCP.DUIDType, config_parse_network_duid_type, 0, 0
DHCP.DUIDRawData, config_parse_network_duid_rawdata, 0, 0
-DHCP.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_UNSPEC, 0
+DHCP.RouteMetric, config_parse_dhcp_route_metric, AF_UNSPEC, 0
DHCP.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET, 0
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCP.ForceDHCPv6PDOtherInformation, config_parse_warn_compat, DISABLED_LEGACY, 0
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, AF_INET, 0
DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
-DHCPv6.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_INET6, 0
+DHCPv6.RouteMetric, config_parse_ipv6_accept_ra_route_metric, AF_INET6, 0
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_warn_compat, DISABLED_LEGACY, 0
DHCPv6PrefixDelegation.SubnetId, config_parse_dhcp_pd_subnet_id, 0, offsetof(Network, dhcp_pd_subnet_id)
DHCPv6PrefixDelegation.Announce, config_parse_bool, 0, offsetof(Network, dhcp_pd_announce)
.ipv6_accept_ra_use_onlink_prefix = true,
.ipv6_accept_ra_use_mtu = true,
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
- .ipv6_accept_ra_route_metric = DHCP_ROUTE_METRIC,
+ .ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
+ .ipv6_accept_ra_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
+ .ipv6_accept_ra_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
.ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
.can_termination = -1,
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client;
uint32_t ipv6_accept_ra_route_table;
bool ipv6_accept_ra_route_table_set;
- uint32_t ipv6_accept_ra_route_metric;
+ uint32_t ipv6_accept_ra_route_metric_high;
+ uint32_t ipv6_accept_ra_route_metric_medium;
+ uint32_t ipv6_accept_ra_route_metric_low;
bool ipv6_accept_ra_route_metric_set;
Set *ndisc_deny_listed_router;
Set *ndisc_allow_listed_router;