summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-04-21 13:51:31 +0200
committerGitHub <noreply@github.com>2021-04-21 13:51:31 +0200
commitb67bbfef14293cb4a1c46573df7a68e53100832d (patch)
treed6319cd195e71472251ca327efb4d1e776b9f648
parentunits: fix repart conditions to run if definitions exist in /sysroot + /sysusr (diff)
parenttest-network: update test for RouteMetric= (diff)
downloadsystemd-b67bbfef14293cb4a1c46573df7a68e53100832d.tar.xz
systemd-b67bbfef14293cb4a1c46573df7a68e53100832d.zip
Merge pull request #19344 from yuwata/network-route-metric-19028
network: add RouteMetric= setting in [Address] and more
-rw-r--r--man/systemd.network.xml47
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c10
-rw-r--r--src/network/networkd-address.c47
-rw-r--r--src/network/networkd-address.h2
-rw-r--r--src/network/networkd-dhcp-common.c10
-rw-r--r--src/network/networkd-dhcp4.c1
-rw-r--r--src/network/networkd-dhcp6.c2
-rw-r--r--src/network/networkd-ipv4ll.c1
-rw-r--r--src/network/networkd-ndisc.c8
-rw-r--r--src/network/networkd-network-gperf.gperf6
-rw-r--r--src/network/networkd-network.c2
-rw-r--r--src/network/networkd-network.h7
-rw-r--r--src/network/networkd-radv.c39
-rw-r--r--src/network/networkd-radv.h2
-rw-r--r--src/network/networkd-route.c4
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network4
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py48
17 files changed, 187 insertions, 53 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 554d1f663c..4024252b39 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1100,6 +1100,15 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>RouteMetric=</varname></term>
+ <listitem>
+ <para>The metric of the prefix route, which is pointing to the subnet of the configured IP
+ address, taking the configured prefix length into account. Takes an unsigned integer in the
+ range 0…4294967295. When unset or set to 0, the kernel's default value is used. This
+ setting will be ignored when <varname>AddPrefixRoute=</varname> is false.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>HomeAddress=</varname></term>
<listitem>
<para>Takes a boolean. Designates this address the "home address" as defined in
@@ -1421,7 +1430,8 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<varlistentry>
<term><varname>Metric=</varname></term>
<listitem>
- <para>The metric of the route (an unsigned integer).</para>
+ <para>The metric of the route. Takes an unsigned integer in the range 0…4294967295.
+ Defaluts to unset, and the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -1837,7 +1847,8 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<varlistentry>
<term><varname>RouteMetric=</varname></term>
<listitem>
- <para>Set the routing metric for routes specified by the DHCP server. Defaults to 1024.</para>
+ <para>Set the routing metric for routes specified by the DHCP server. Takes an unsigned
+ integer in the range 0…4294967295. Defaults to 1024.</para>
</listitem>
</varlistentry>
@@ -1978,13 +1989,6 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
</varlistentry>
<varlistentry>
- <term><varname>RouteMetric=</varname></term>
- <listitem>
- <para>Set the routing metric for routes specified by the DHCP server. Defaults to 1024.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><varname>RapidCommit=</varname></term>
<listitem>
<para>Takes a boolean. The DHCPv6 client can obtain configuration parameters from a DHCPv6 server through
@@ -2158,6 +2162,14 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<para>As in the [Address] section, but defaults to true.</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>RouteMetric=</varname></term>
+ <listitem>
+ <para>The metric of the route to the delegated prefix subnet. Takes an unsigned integer in
+ the range 0…4294967295. When unset or set to 0, the kernel's default value is used.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -2208,6 +2220,14 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
</varlistentry>
<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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>UseAutonomousPrefix=</varname></term>
<listitem>
<para>When true (the default), the autonomous prefix received in the Router Advertisement will be used and take
@@ -2564,6 +2584,15 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<listitem><para>Takes a boolean. When true, adds an address from the prefix. Default to false.
</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>RouteMetric=</varname></term>
+ <listitem>
+ <para>The metric of the prefix route. Takes an unsigned integer in the range 0…4294967295.
+ When unset or set to 0, the kernel's default value is used. This setting is ignored when
+ <varname>Assign=</varname> is false.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index ed7b9a8cd1..5ae15d67bc 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -683,13 +683,13 @@ static const NLType rtnl_address_types[] = {
[IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
- [IFA_BROADCAST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
+ [IFA_BROADCAST] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFA_ANYCAST] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
-/*
- [IFA_ANYCAST],
- [IFA_MULTICAST],
-*/
+ [IFA_MULTICAST] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_FLAGS] = { .type = NETLINK_TYPE_U32 },
+ [IFA_RT_PRIORITY] = { .type = NETLINK_TYPE_U32 },
+ [IFA_TARGET_NETNSID] = { .type = NETLINK_TYPE_S32 },
};
static const NLTypeSystem rtnl_address_type_system = {
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 58b089901b..e589fff150 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -918,6 +918,10 @@ int address_configure(
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
+ r = sd_netlink_message_append_u32(req, IFA_RT_PRIORITY, address->route_metric);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFA_RT_PRIORITY attribute: %m");
+
k = address_add(link, address, &a);
if (k < 0)
return log_link_error_errno(link, k, "Could not add address: %m");
@@ -1091,6 +1095,7 @@ int link_set_addresses(Link *link) {
return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
address->family = AF_INET6;
+ address->route_metric = p->route_metric;
r = static_address_configure(address, link);
if (r < 0)
return r;
@@ -1801,6 +1806,48 @@ int config_parse_address_scope(
return 0;
}
+int config_parse_address_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 = userdata;
+ _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = address_new_static(network, filename, section_line, &n);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to allocate new address, ignoring assignment: %m");
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &n->route_metric);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Could not parse %s=, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ TAKE_PTR(n);
+ return 0;
+}
+
int config_parse_duplicate_address_detection(
const char *unit,
const char *filename,
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index e3ca868c2e..58f44cd4cd 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -28,6 +28,7 @@ typedef struct Address {
unsigned char prefixlen;
unsigned char scope;
uint32_t flags;
+ uint32_t route_metric; /* route metric for prefix route */
char *label;
int set_broadcast;
@@ -83,6 +84,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_label);
CONFIG_PARSER_PROTOTYPE(config_parse_lifetime);
CONFIG_PARSER_PROTOTYPE(config_parse_address_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_address_scope);
+CONFIG_PARSER_PROTOTYPE(config_parse_address_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_duplicate_address_detection);
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c
index f09f0ee50e..bb0b204467 100644
--- a/src/network/networkd-dhcp-common.c
+++ b/src/network/networkd-dhcp-common.c
@@ -332,14 +332,14 @@ int config_parse_dhcp_route_metric(
if (streq_ptr(section, "DHCPv4")) {
network->dhcp_route_metric = metric;
network->dhcp_route_metric_set = true;
- } else if (streq_ptr(section, "DHCPv6")) {
- network->dhcp6_route_metric = metric;
- network->dhcp6_route_metric_set = true;
+ } else if (STRPTR_IN_SET(section, "DHCPv6", "IPv6AcceptRA")) {
+ network->ipv6_accept_ra_route_metric = metric;
+ network->ipv6_accept_ra_route_metric_set = true;
} else { /* [DHCP] section */
if (!network->dhcp_route_metric_set)
network->dhcp_route_metric = metric;
- if (!network->dhcp6_route_metric_set)
- network->dhcp6_route_metric = metric;
+ if (!network->ipv6_accept_ra_route_metric_set)
+ network->ipv6_accept_ra_route_metric = metric;
}
return 0;
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 2157057121..85b909e576 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -893,6 +893,7 @@ static int dhcp4_update_address(Link *link, bool announce) {
if (prefixlen <= 30)
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
+ addr->route_metric = link->network->dhcp_route_metric;
/* allow reusing an existing address and simply update its lifetime
* in case it already exists */
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index f5e66b9457..6f3c02d44d 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -284,6 +284,7 @@ static int dhcp6_set_pd_route(Link *link, const union in_addr_union *prefix, con
route->dst = *prefix;
route->dst_prefixlen = 64;
route->protocol = RTPROT_DHCP;
+ route->priority = link->network->dhcp6_pd_route_metric;
r = route_configure(route, link, dhcp6_pd_route_handler, &ret);
if (r < 0)
@@ -399,6 +400,7 @@ static int dhcp6_set_pd_address(
address->cinfo.ifa_prefered = lifetime_preferred;
address->cinfo.ifa_valid = lifetime_valid;
SET_FLAG(address->flags, IFA_F_MANAGETEMPADDR, link->network->dhcp6_pd_manage_temporary_address);
+ address->route_metric = link->network->dhcp6_pd_route_metric;
r = address_configure(address, link, dhcp6_pd_address_handler, &ret);
if (r < 0)
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 7aad2131fd..5390c53799 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -91,6 +91,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
ll_addr->prefixlen = 16;
ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
ll_addr->scope = RT_SCOPE_LINK;
+ ll_addr->route_metric = IPV4LL_ROUTE_METRIC;
r = address_configure(ll_addr, link, ipv4ll_address_handler, NULL);
if (r < 0)
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 7a975f3a91..b02f67c770 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -530,7 +530,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route->family = AF_INET6;
route->table = table;
- route->priority = link->network->dhcp6_route_metric;
+ route->priority = link->network->ipv6_accept_ra_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw_family = AF_INET6;
@@ -554,7 +554,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
if (!route_gw->table_set)
route_gw->table = table;
if (!route_gw->priority_set)
- route_gw->priority = link->network->dhcp6_route_metric;
+ route_gw->priority = link->network->ipv6_accept_ra_route_metric;
if (!route_gw->protocol_set)
route_gw->protocol = RTPROT_RA;
if (!route_gw->pref_set)
@@ -814,7 +814,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
route->family = AF_INET6;
route->table = link_get_ipv6_accept_ra_route_table(link);
- route->priority = link->network->dhcp6_route_metric;
+ route->priority = link->network->ipv6_accept_ra_route_metric;
route->protocol = RTPROT_RA;
route->flags = RTM_F_PREFIX;
route->dst_prefixlen = prefixlen;
@@ -899,7 +899,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
route->family = AF_INET6;
route->table = link_get_ipv6_accept_ra_route_table(link);
- route->priority = link->network->dhcp6_route_metric;
+ route->priority = link->network->ipv6_accept_ra_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw = gateway;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 4fc368547c..568c34f51b 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -146,6 +146,7 @@ Address.AddPrefixRoute, config_parse_address_flags,
Address.AutoJoin, config_parse_address_flags, IFA_F_MCAUTOJOIN, 0
Address.DuplicateAddressDetection, config_parse_duplicate_address_detection, 0, 0
Address.Scope, config_parse_address_scope, 0, 0
+Address.RouteMetric, config_parse_address_route_metric, 0, 0
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0
IPv6AddressLabel.Label, config_parse_address_label, 0, 0
Neighbor.Address, config_parse_neighbor_address, 0, 0
@@ -243,13 +244,13 @@ DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool,
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra)
DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
-DHCPv6.RouteMetric, config_parse_dhcp_route_metric, 0, 0
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
IPv6AcceptRA.UseDomains, config_parse_ipv6_accept_ra_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0
+IPv6AcceptRA.RouteMetric, config_parse_dhcp_route_metric, 0, 0
IPv6AcceptRA.RouterAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_router)
IPv6AcceptRA.RouterDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_router)
IPv6AcceptRA.PrefixAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_prefix)
@@ -308,6 +309,7 @@ DHCPv6PrefixDelegation.Announce, config_parse_bool,
DHCPv6PrefixDelegation.Assign, config_parse_bool, 0, offsetof(Network, dhcp6_pd_assign)
DHCPv6PrefixDelegation.ManageTemporaryAddress, config_parse_bool, 0, offsetof(Network, dhcp6_pd_manage_temporary_address)
DHCPv6PrefixDelegation.Token, config_parse_dhcp6_pd_token, 0, offsetof(Network, dhcp6_pd_token)
+DHCPv6PrefixDelegation.RouteMetric, config_parse_uint32, 0, offsetof(Network, dhcp6_pd_route_metric)
IPv6SendRA.RouterLifetimeSec, config_parse_sec, 0, offsetof(Network, router_lifetime_usec)
IPv6SendRA.Managed, config_parse_bool, 0, offsetof(Network, router_managed)
IPv6SendRA.OtherInformation, config_parse_bool, 0, offsetof(Network, router_other_information)
@@ -323,6 +325,7 @@ IPv6Prefix.AddressAutoconfiguration, config_parse_prefix_flags,
IPv6Prefix.ValidLifetimeSec, config_parse_prefix_lifetime, 0, 0
IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime, 0, 0
IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0
+IPv6Prefix.RouteMetric, config_parse_prefix_metric, 0, 0
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
LLDP.MUDURL, config_parse_lldp_mud, 0, 0
@@ -491,6 +494,7 @@ DHCP.RapidCommit, config_parse_bool,
DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, 0
DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
+DHCPv6.RouteMetric, config_parse_dhcp_route_metric, 0, 0
IPv6AcceptRA.DenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.BlackList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
TrafficControlQueueingDiscipline.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 320d33645e..6c81f2cca7 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -321,7 +321,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp6_use_hostname = true,
.dhcp6_use_ntp = true,
.dhcp6_rapid_commit = true,
- .dhcp6_route_metric = DHCP_ROUTE_METRIC,
.dhcp6_pd = -1,
.dhcp6_pd_announce = true,
@@ -379,6 +378,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.ipv6_accept_ra_use_autonomous_prefix = true,
.ipv6_accept_ra_use_onlink_prefix = true,
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
+ .ipv6_accept_ra_route_metric = DHCP_ROUTE_METRIC,
.ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
.can_triple_sampling = -1,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 16a445982c..db0fbbdf1a 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -170,8 +170,6 @@ struct Network {
DHCPUseDomains dhcp6_use_domains;
bool dhcp6_use_domains_set;
uint8_t dhcp6_pd_length;
- uint32_t dhcp6_route_metric;
- bool dhcp6_route_metric_set;
char *dhcp6_mudurl;
char **dhcp6_user_class;
char **dhcp6_vendor_class;
@@ -221,6 +219,7 @@ struct Network {
bool dhcp6_pd_assign;
bool dhcp6_pd_manage_temporary_address;
int64_t dhcp6_pd_subnet_id;
+ uint32_t dhcp6_pd_route_metric;
union in_addr_union dhcp6_pd_token;
/* Bridge Support */
@@ -277,10 +276,12 @@ struct Network {
bool ipv6_accept_ra_use_onlink_prefix;
bool active_slave;
bool primary_slave;
- bool ipv6_accept_ra_route_table_set;
DHCPUseDomains ipv6_accept_ra_use_domains;
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;
+ bool ipv6_accept_ra_route_metric_set;
Set *ndisc_deny_listed_router;
Set *ndisc_allow_listed_router;
Set *ndisc_deny_listed_prefix;
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index 19f75e01da..52c9afcc5e 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -382,6 +382,45 @@ int config_parse_prefix_assign(
return 0;
}
+int config_parse_prefix_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 = userdata;
+ _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = prefix_new_static(network, filename, section_line, &p);
+ if (r < 0)
+ return log_oom();
+
+ r = safe_atou32(rvalue, &p->route_metric);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse %s=, ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ TAKE_PTR(p);
+
+ return 0;
+}
+
int config_parse_route_prefix(
const char *unit,
const char *filename,
diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h
index 73d2f24545..f6efd32697 100644
--- a/src/network/networkd-radv.h
+++ b/src/network/networkd-radv.h
@@ -33,6 +33,7 @@ typedef struct Prefix {
sd_radv_prefix *radv_prefix;
bool assign;
+ uint32_t route_metric;
} Prefix;
typedef struct RoutePrefix {
@@ -64,6 +65,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_prefix);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_lifetime);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_assign);
+CONFIG_PARSER_PROTOTYPE(config_parse_prefix_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_radv_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_radv_search_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix);
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index a74541a6c9..9ed30d69ed 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -628,11 +628,11 @@ static void log_route_debug(const Route *route, const char *str, const Link *lin
(void) route_protocol_full_to_string_alloc(route->protocol, &proto);
log_link_debug(link,
- "%s route: dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s, nexthop: %"PRIu32,
+ "%s route: dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32,
str, strna(dst), strna(src), strna(gw), strna(prefsrc),
strna(scope), strna(table), strna(proto),
strna(route_type_to_string(route->type)),
- route->nexthop_id);
+ route->nexthop_id, route->priority);
}
}
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 158f0ffad1..e5acc5d67d 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -147,6 +147,7 @@ Announce=
Assign=
ManageTemporaryAddress=
Token=
+RouteMetric=
[Route]
Destination=
Protocol=
@@ -236,6 +237,7 @@ PreferredLifetimeSec=
AddressAutoconfiguration=
ValidLifetimeSec=
Assign=
+RouteMetric=
[IPv6RoutePrefix]
Route=
LifetimeSec=
@@ -270,6 +272,7 @@ ManageTemporaryAddress=
Broadcast=
Peer=
Label=
+RouteMetric=
[RoutingPolicyRule]
Table=
IncomingInterface=
@@ -317,6 +320,7 @@ Prefix=
[IPv6AcceptRA]
UseDomains=
RouteTable=
+RouteMetric=
UseDNS=
DHCPv6Client=
UseAutonomousPrefix=
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 9d86818610..148ff6e8c0 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -3911,7 +3911,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
@@ -4014,7 +4014,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip address show dev veth99 scope global')
print(output)
self.assertRegex(output, r'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
- self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
+ self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global secondary dynamic veth99')
output = check_output('ip route show dev veth99')
print(output)
@@ -4044,7 +4044,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip route show dev veth99')
print(output)
- self.assertRegex(output, 'metric 24')
+ self.assertIn('default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 24', output)
+ self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.181 metric 24', output)
+ self.assertIn('192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 24', output)
def test_dhcp_client_reassign_static_routes_ipv4(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
@@ -4056,7 +4058,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip address show dev veth99 scope global')
print(output)
- self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+ self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
output = check_output('ip route show dev veth99')
print(output)
@@ -4201,7 +4203,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
output = check_output('ip address show dev veth99 scope global')
@@ -4244,7 +4246,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
print('## ip -d link show dev vrf99')
@@ -4255,14 +4257,14 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print('## ip address show vrf vrf99')
output = check_output('ip address show vrf vrf99')
print(output)
- self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+ self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
self.assertRegex(output, 'inet6 .* scope link')
print('## ip address show dev veth99')
output = check_output('ip address show dev veth99')
print(output)
- self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+ self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
self.assertRegex(output, 'inet6 .* scope link')
@@ -4338,9 +4340,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip -6 address show dev veth99 scope link')
self.assertRegex(output, r'inet6 .* scope link')
output = check_output('ip -4 address show dev veth99 scope global dynamic')
- self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
+ self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
output = check_output('ip -4 address show dev veth99 scope link')
- self.assertNotRegex(output, r'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
+ self.assertNotRegex(output, r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
print('Wait for the dynamic address to be expired')
time.sleep(130)
@@ -4353,9 +4355,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip -6 address show dev veth99 scope link')
self.assertRegex(output, r'inet6 .* scope link')
output = check_output('ip -4 address show dev veth99 scope global dynamic')
- self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
+ self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
output = check_output('ip -4 address show dev veth99 scope link')
- self.assertNotRegex(output, r'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
+ self.assertNotRegex(output, r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
@@ -4375,13 +4377,13 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip -6 address show dev veth99 scope link')
self.assertRegex(output, r'inet6 .* scope link')
output = check_output('ip -4 address show dev veth99 scope global dynamic')
- self.assertNotRegex(output, r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
+ self.assertNotRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
output = check_output('ip -4 address show dev veth99 scope link')
- self.assertRegex(output, r'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
+ self.assertRegex(output, r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
start_dnsmasq(lease_time='2m')
- self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
- self.wait_address_dropped('veth99', r'inet 169\.254\.\d+\.\d+/16 brd 169\.255\.255\.255 scope link', scope='link', ipv='-4')
+ self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
+ self.wait_address_dropped('veth99', r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.255\.255\.255 scope link', scope='link', ipv='-4')
def test_dhcp_client_route_remove_on_renew(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
@@ -4395,7 +4397,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip -4 address show dev veth99 scope global dynamic')
print(output)
- self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+ self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
address1=None
for line in output.splitlines():
if 'brd 192.168.5.255 scope global dynamic veth99' in line:
@@ -4415,10 +4417,10 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip -4 address show dev veth99 scope global dynamic')
print(output)
- self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+ self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
address2=None
for line in output.splitlines():
- if 'brd 192.168.5.255 scope global dynamic veth99' in line:
+ if 'metric 1024 brd 192.168.5.255 scope global dynamic veth99' in line:
address2 = line.split()[1].split('/')[0]
break
@@ -4440,7 +4442,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
time.sleep(3)
@@ -4458,7 +4460,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
time.sleep(3)
@@ -4476,7 +4478,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
time.sleep(3)
@@ -4494,7 +4496,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# link become 'routable' when at least one protocol provide an valid address.
- self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
time.sleep(3)