1
0
mirror of https://github.com/systemd/systemd synced 2026-04-06 23:24:52 +02:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Taiki Sugawara
095eaf7130 hwdb: Add Kensington Expert Mouse Wireless Trackball 2021-11-15 08:17:51 +09:00
Yu Watanabe
26591ffffd resolve: do not clear DNS servers or friends on link which is not managed by networkd
When networkd detects an unmanaged link, then the state is changed in
the following order:
pending -> initialized -> unmanaged

The "initialized" state was added by bd08ce56156751d58584a44e766ef61340cdae2d.
2021-11-15 08:17:34 +09:00
Yu Watanabe
51f6c93d21
Merge pull request #21359 from yuwata/network-split-route
network: log route or nexthop flags
2021-11-15 08:17:07 +09:00
Yu Watanabe
bae62bee43
Merge pull request #21346 from yuwata/network-token-prefixstable
network: extend Token=prefixstable setting
2021-11-15 08:16:48 +09:00
Evgeny Vereshchagin
6f593f7226
Merge pull request #21366 from evverx/ci-follow-ups-3
ci: LGPLv2+ify dependapot config and codeql action and tighten codeql and labeler even more
2021-11-15 00:02:21 +03:00
Evgeny Vereshchagin
510afa460a ci: tighten codeql and labeler even more
by moving the read permissions to the top level and
granting additional permissions to the specific jobs.
It should help to prevent new jobs that could be added
there eventually from having write access to resources they
most likely would never need.
2021-11-14 10:51:07 +00:00
Evgeny Vereshchagin
b3a1fb795a ci: LGPLv2+ify dependapot config and codeql action 2021-11-14 09:48:22 +00:00
Yu Watanabe
b07d8145e1 network: include route or nexthop flags in the debug logs 2021-11-14 14:41:37 +09:00
Yu Watanabe
18b23bd493 network: introduce route_flags_to_string_alloc() 2021-11-14 14:41:37 +09:00
Yu Watanabe
344b3cff36 network: split networkd-route.[ch] 2021-11-14 14:41:37 +09:00
Yu Watanabe
7a2e124b08 test-network: add testcases for Token=prefixstable with UUID 2021-11-14 13:29:44 +09:00
Yu Watanabe
f2a3a133ec network: make Token=prefixstable optionally take secret key
Closes #21345.
2021-11-14 13:29:40 +09:00
Yu Watanabe
c463ae74ae man: fix indentation
Also use variablelist tag for listing Token= options.
2021-11-14 10:30:33 +09:00
21 changed files with 783 additions and 614 deletions

View File

@ -1,3 +1,5 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
version: 2 version: 2
updates: updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"

View File

@ -1,3 +1,7 @@
---
# vi: ts=2 sw=2 et:
# SPDX-License-Identifier: LGPL-2.1-or-later
#
name: "CodeQL" name: "CodeQL"
on: on:
@ -7,6 +11,9 @@ on:
schedule: schedule:
- cron: '0 1 * * *' - cron: '0 1 * * *'
permissions:
contents: read
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze
@ -16,7 +23,6 @@ jobs:
cancel-in-progress: true cancel-in-progress: true
permissions: permissions:
actions: read actions: read
contents: read
security-events: write security-events: write
strategy: strategy:

View File

@ -9,11 +9,12 @@ on:
permissions: permissions:
contents: read contents: read
pull-requests: write
jobs: jobs:
triage: triage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
pull-requests: write
steps: steps:
- uses: actions/labeler@69da01b8e0929f147b8943611bee75ee4175a49e - uses: actions/labeler@69da01b8e0929f147b8943611bee75ee4175a49e
with: with:

View File

@ -274,6 +274,8 @@ mouse:usb:v04b3p3107:name:*
# Kensington Expert Mouse trackball # Kensington Expert Mouse trackball
mouse:usb:v047dp1020:*Kensington Expert Mouse*:* mouse:usb:v047dp1020:*Kensington Expert Mouse*:*
mouse:usb:v047dp8018:name:Kensington Expert Wireless TB Mouse:*
mouse:bluetooth:v047dp8019:name:Expert Wireless TB Mouse:*
ID_INPUT_TRACKBALL=1 ID_INPUT_TRACKBALL=1
MOUSE_DPI=400@125 MOUSE_DPI=400@125

View File

@ -2193,41 +2193,75 @@ Table=1234</programlisting></para>
<term><varname>Token=</varname></term> <term><varname>Token=</varname></term>
<listitem> <listitem>
<para>Specifies an optional address generation mode for the Stateless Address <para>Specifies an optional address generation mode for the Stateless Address
Autoconfiguration (SLAAC). Supported modes are <literal>eui64</literal>, Autoconfiguration (SLAAC). The following values are supported:</para>
<literal>static</literal>, and <literal>prefixstable</literal>.</para>
<para>When the mode is set to <literal>eui64</literal>, then the EUI-64 algorithm will be <variablelist>
used to generate an address for that prefix.</para> <varlistentry>
<term><option>eui64</option></term>
<para>When the mode is set to <literal>static</literal>, an IPv6 address must be <listitem>
specified after a colon (<literal>:</literal>), and the lower bits of the supplied <para>
address are combined with the upper bits of a prefix received in a Router Advertisement The EUI-64 algorithm will be used to generate an address for that prefix.
(RA) message to form a complete address. Note that if multiple prefixes are received in an </para>
RA message, or in multiple RA messages, addresses will be formed from each of them using </listitem>
the supplied address. This mode implements SLAAC but uses a static interface identifier </varlistentry>
instead of an identifier generated by using the EUI-64 algorithm. Because the interface <varlistentry>
identifier is static, if Duplicate Address Detection detects that the computed address is a <term><option>static:<replaceable>ADDRESS</replaceable></option></term>
duplicate (in use by another node on the link), then this mode will fail to provide an <listitem>
address for that prefix. If an IPv6 address without mode is specified, then <para>
<literal>static</literal> mode is assumed.</para> An IPv6 address must be specified after a colon (<literal>:</literal>), and the
lower bits of the supplied address are combined with the upper bits of a prefix
<para>When the mode is set to <literal>prefixstable</literal> the received in a Router Advertisement (RA) message to form a complete address. Note
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> algorithm for generating that if multiple prefixes are received in an RA message, or in multiple RA messages,
interface identifiers will be used. This mode can optionally take an IPv6 address separated addresses will be formed from each of them using the supplied address. This mode
with a colon (<literal>:</literal>). If an IPv6 address is specified, then an interface implements SLAAC but uses a static interface identifier instead of an identifier
identifier is generated only when a prefix received in an RA message matches the supplied generated by using the EUI-64 algorithm. Because the interface identifier is static,
address.</para> if Duplicate Address Detection detects that the computed address is a duplicate
(in use by another node on the link), then this mode will fail to provide an address
for that prefix. If an IPv6 address without mode is specified, then
<literal>static</literal> mode is assumed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>prefixstable[:<replaceable>ADDRESS</replaceable>][,<replaceable>UUID</replaceable>]</option></term>
<listitem>
<para>
The algorithm specified in
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> will be used to
generate interface identifiers. This mode can optionally take an IPv6 address
separated with a colon (<literal>:</literal>). If an IPv6 address is specified,
then an interface identifier is generated only when a prefix received in an RA
message matches the supplied address.
</para>
<para>
This mode can also optionally take a non-null UUID in the format which
<function>sd_id128_from_string()</function> accepts, e.g.
<literal>86b123b969ba4b7eb8b3d8605123525a</literal> or
<literal>86b123b9-69ba-4b7e-b8b3-d8605123525a</literal>. If a UUID is specified, the
value is used as the secret key to generate interface identifiers. If not specified,
then an application specific ID generated with the system's machine-ID will be used
as the secret key. See
<citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_id128_from_string</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
and
<citerefentry><refentrytitle>sd_id128_get_machine</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
</para>
<para>
Note that the <literal>prefixstable</literal> algorithm uses both the interface
name and MAC address as input to the hash to compute the interface identifier, so
if either of those are changed the resulting interface identifier (and address)
will be changed, even if the prefix received in the RA message has not been
changed.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>If no address generation mode is specified (which is the default), or a received <para>If no address generation mode is specified (which is the default), or a received
prefix does not match any of the addresses provided in <literal>prefixstable</literal> prefix does not match any of the addresses provided in <literal>prefixstable</literal>
mode, then the EUI-64 algorithm will be used to form an interface identifier for that mode, then the EUI-64 algorithm will be used to form an interface identifier for that
prefix.</para> prefix.</para>
<para>Note that the <literal>prefixstable</literal> algorithm uses both the interface
name and MAC address as input to the hash to compute the interface identifier, so if either
of those are changed the resulting interface identifier (and address) will be changed, even
if the prefix received in the RA message has not been changed.</para>
<para>This setting can be specified multiple times. If an empty string is assigned, then <para>This setting can be specified multiple times. If an empty string is assigned, then
the all previous assignments are cleared.</para> the all previous assignments are cleared.</para>

View File

@ -115,6 +115,8 @@ sources = files('''
networkd-nexthop.h networkd-nexthop.h
networkd-queue.c networkd-queue.c
networkd-queue.h networkd-queue.h
networkd-route-util.c
networkd-route-util.h
networkd-route.c networkd-route.c
networkd-route.h networkd-route.h
networkd-routing-policy-rule.c networkd-routing-policy-rule.c

View File

@ -4,6 +4,7 @@
#include "sd-id128.h" #include "sd-id128.h"
#include "id128-util.h"
#include "memory-util.h" #include "memory-util.h"
#include "networkd-address-generation.h" #include "networkd-address-generation.h"
#include "networkd-link.h" #include "networkd-link.h"
@ -35,6 +36,7 @@ typedef enum AddressGenerationType {
typedef struct IPv6Token { typedef struct IPv6Token {
AddressGenerationType type; AddressGenerationType type;
struct in6_addr address; struct in6_addr address;
sd_id128_t secret_key;
} IPv6Token; } IPv6Token;
static void generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) { static void generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) {
@ -117,29 +119,35 @@ static void generate_stable_private_address_one(
static int generate_stable_private_address( static int generate_stable_private_address(
Link *link, Link *link,
const sd_id128_t *app_id, const sd_id128_t *app_id,
const sd_id128_t *secret_key,
const struct in6_addr *prefix, const struct in6_addr *prefix,
struct in6_addr *ret) { struct in6_addr *ret) {
sd_id128_t secret_machine_key;
struct in6_addr addr; struct in6_addr addr;
sd_id128_t secret_key;
uint8_t i; uint8_t i;
int r; int r;
assert(link); assert(link);
assert(app_id); assert(app_id);
assert(secret_key);
assert(prefix); assert(prefix);
assert(ret); assert(ret);
r = sd_id128_get_machine_app_specific(*app_id, &secret_key); if (sd_id128_is_null(*secret_key)) {
r = sd_id128_get_machine_app_specific(*app_id, &secret_machine_key);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m"); return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m");
secret_key = &secret_machine_key;
}
/* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop does /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop does
* not actually attempt Duplicate Address Detection; the counter will be incremented only when * not actually attempt Duplicate Address Detection; the counter will be incremented only when
* the address generation algorithm produces an invalid address, and the loop may exit with an * the address generation algorithm produces an invalid address, and the loop may exit with an
* address which ends up being unusable due to duplication on the link. */ * address which ends up being unusable due to duplication on the link. */
for (i = 0; i < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; i++) { for (i = 0; i < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; i++) {
generate_stable_private_address_one(link, &secret_key, prefix, i, &addr); generate_stable_private_address_one(link, secret_key, prefix, i, &addr);
if (stable_private_address_is_valid(&addr)) if (stable_private_address_is_valid(&addr))
break; break;
@ -192,7 +200,7 @@ static int generate_addresses(
if (in6_addr_is_set(&j->address) && !in6_addr_equal(&j->address, &masked)) if (in6_addr_is_set(&j->address) && !in6_addr_equal(&j->address, &masked))
continue; continue;
if (generate_stable_private_address(link, app_id, &masked, &addr) < 0) if (generate_stable_private_address(link, app_id, &j->secret_key, &masked, &addr) < 0)
continue; continue;
break; break;
@ -244,6 +252,7 @@ int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *pref
static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) { static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
siphash24_compress(&p->type, sizeof(p->type), state); siphash24_compress(&p->type, sizeof(p->type), state);
siphash24_compress(&p->address, sizeof(p->address), state); siphash24_compress(&p->address, sizeof(p->address), state);
id128_hash_func(&p->secret_key, state);
} }
static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) { static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
@ -253,7 +262,11 @@ static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
if (r != 0) if (r != 0)
return r; return r;
return memcmp(&a->address, &b->address, sizeof(struct in6_addr)); r = memcmp(&a->address, &b->address, sizeof(struct in6_addr));
if (r != 0)
return r;
return id128_compare_func(&a->secret_key, &b->secret_key);
} }
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
@ -263,12 +276,13 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ipv6_token_compare_func, ipv6_token_compare_func,
free); free);
static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr) { static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr, const sd_id128_t *secret_key) {
IPv6Token *p; IPv6Token *p;
assert(tokens); assert(tokens);
assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX); assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX);
assert(addr); assert(addr);
assert(secret_key);
p = new(IPv6Token, 1); p = new(IPv6Token, 1);
if (!p) if (!p)
@ -277,6 +291,7 @@ static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct
*p = (IPv6Token) { *p = (IPv6Token) {
.type = type, .type = type,
.address = *addr, .address = *addr,
.secret_key = *secret_key,
}; };
return set_ensure_consume(tokens, &ipv6_token_hash_ops, p); return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
@ -294,10 +309,12 @@ int config_parse_address_generation_type(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_free_ char *addr_alloc = NULL;
sd_id128_t secret_key = SD_ID128_NULL;
union in_addr_union buffer = {}; union in_addr_union buffer = {};
AddressGenerationType type; AddressGenerationType type;
Set **tokens = data; Set **tokens = data;
const char *p; const char *addr;
int r; int r;
assert(filename); assert(filename);
@ -310,33 +327,64 @@ int config_parse_address_generation_type(
return 0; return 0;
} }
if ((p = startswith(rvalue, "prefixstable"))) { if ((addr = startswith(rvalue, "prefixstable"))) {
const char *comma;
type = ADDRESS_GENERATION_PREFIXSTABLE; type = ADDRESS_GENERATION_PREFIXSTABLE;
if (*p == ':') if (*addr == ':') {
p++; addr++;
else if (*p == '\0')
p = NULL; comma = strchr(addr, ',');
else { if (comma) {
addr_alloc = strndup(addr, comma - addr);
if (!addr_alloc)
return log_oom();
addr = addr_alloc;
}
} else if (*addr == ',') {
comma = addr;
addr = NULL;
} else if (*addr == '\0') {
comma = NULL;
addr = NULL;
} else {
log_syntax(unit, LOG_WARNING, filename, line, 0, log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid IPv6 token mode in %s=, ignoring assignment: %s", "Invalid IPv6 token mode in %s=, ignoring assignment: %s",
lvalue, rvalue); lvalue, rvalue);
return 0; return 0;
} }
if (comma) {
r = sd_id128_from_string(comma + 1, &secret_key);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse secret key in %s=, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (sd_id128_is_null(secret_key)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Secret key in %s= cannot be null, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
}
} else if (streq(rvalue, "eui64")) { } else if (streq(rvalue, "eui64")) {
type = ADDRESS_GENERATION_EUI64; type = ADDRESS_GENERATION_EUI64;
p = NULL; addr = NULL;
} else { } else {
type = ADDRESS_GENERATION_STATIC; type = ADDRESS_GENERATION_STATIC;
p = startswith(rvalue, "static:"); addr = startswith(rvalue, "static:");
if (!p) if (!addr)
p = rvalue; addr = rvalue;
} }
if (p) { if (addr) {
r = in_addr_from_string(AF_INET6, p, &buffer); r = in_addr_from_string(AF_INET6, addr, &buffer);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse IP address in %s=, ignoring assignment: %s", "Failed to parse IP address in %s=, ignoring assignment: %s",
@ -371,7 +419,7 @@ int config_parse_address_generation_type(
assert_not_reached(); assert_not_reached();
} }
r = ipv6_token_add(tokens, type, &buffer.in6); r = ipv6_token_add(tokens, type, &buffer.in6, &secret_key);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();

View File

@ -16,7 +16,7 @@
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-queue.h" #include "networkd-queue.h"
#include "networkd-route.h" #include "networkd-route-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "socket-netlink.h" #include "socket-netlink.h"
#include "string-table.h" #include "string-table.h"

View File

@ -8,7 +8,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "networkd-conf.h" #include "networkd-conf.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-route.h" #include "networkd-route-util.h"
%} %}
struct ConfigPerfItem; struct ConfigPerfItem;
%null_strings %null_strings

View File

@ -12,7 +12,7 @@
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-nexthop.h" #include "networkd-nexthop.h"
#include "networkd-queue.h" #include "networkd-queue.h"
#include "networkd-route.h" #include "networkd-route-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "set.h" #include "set.h"
#include "stdio-util.h" #include "stdio-util.h"
@ -346,7 +346,7 @@ static int nexthop_acquire_id(Manager *manager, NextHop *nexthop) {
} }
static void log_nexthop_debug(const NextHop *nexthop, const char *str, const Link *link) { static void log_nexthop_debug(const NextHop *nexthop, const char *str, const Link *link) {
_cleanup_free_ char *state = NULL, *gw = NULL, *group = NULL; _cleanup_free_ char *state = NULL, *gw = NULL, *group = NULL, *flags = NULL;
struct nexthop_grp *nhg; struct nexthop_grp *nhg;
assert(nexthop); assert(nexthop);
@ -359,13 +359,14 @@ static void log_nexthop_debug(const NextHop *nexthop, const char *str, const Lin
(void) network_config_state_to_string_alloc(nexthop->state, &state); (void) network_config_state_to_string_alloc(nexthop->state, &state);
(void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw); (void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw);
(void) route_flags_to_string_alloc(nexthop->flags, &flags);
HASHMAP_FOREACH(nhg, nexthop->group) HASHMAP_FOREACH(nhg, nexthop->group)
(void) strextendf_with_separator(&group, ",", "%"PRIu32":%"PRIu32, nhg->id, nhg->weight+1); (void) strextendf_with_separator(&group, ",", "%"PRIu32":%"PRIu32, nhg->id, nhg->weight+1);
log_link_debug(link, "%s %s nexthop (%s): id: %"PRIu32", gw: %s, blackhole: %s, group: %s", log_link_debug(link, "%s %s nexthop (%s): id: %"PRIu32", gw: %s, blackhole: %s, group: %s, flags: %s",
str, strna(network_config_source_to_string(nexthop->source)), strna(state), str, strna(network_config_source_to_string(nexthop->source)), strna(state),
nexthop->id, strna(gw), yes_no(nexthop->blackhole), strna(group)); nexthop->id, strna(gw), yes_no(nexthop->blackhole), strna(group), strna(flags));
} }
static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {

View File

@ -15,7 +15,7 @@
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-queue.h" #include "networkd-queue.h"
#include "networkd-radv.h" #include "networkd-radv.h"
#include "networkd-route.h" #include "networkd-route-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "radv-internal.h" #include "radv-internal.h"
#include "string-util.h" #include "string-util.h"

View File

@ -0,0 +1,419 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/rtnetlink.h>
#include "alloc-util.h"
#include "networkd-address.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-route-util.h"
#include "networkd-route.h"
#include "parse-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "sysctl-util.h"
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
unsigned routes_max(void) {
static thread_local unsigned cached = 0;
_cleanup_free_ char *s4 = NULL, *s6 = NULL;
unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
if (cached > 0)
return cached;
if (sysctl_read_ip_property(AF_INET, NULL, "route/max_size", &s4) >= 0)
if (safe_atou(s4, &val4) >= 0 && val4 == 2147483647U)
/* This is the default "no limit" value in the kernel */
val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
if (sysctl_read_ip_property(AF_INET6, NULL, "route/max_size", &s6) >= 0)
(void) safe_atou(s6, &val6);
cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
return cached;
}
static Route *link_find_default_gateway(Link *link, int family, Route *gw) {
Route *route;
assert(link);
SET_FOREACH(route, link->routes) {
if (!route_exists(route))
continue;
if (family != AF_UNSPEC && route->family != family)
continue;
if (route->dst_prefixlen != 0)
continue;
if (route->src_prefixlen != 0)
continue;
if (route->table != RT_TABLE_MAIN)
continue;
if (route->type != RTN_UNICAST)
continue;
if (route->scope != RT_SCOPE_UNIVERSE)
continue;
if (!in_addr_is_set(route->gw_family, &route->gw))
continue;
if (gw) {
if (route->gw_weight > gw->gw_weight)
continue;
if (route->priority >= gw->priority)
continue;
}
gw = route;
}
return gw;
}
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret) {
Route *gw = NULL;
Link *link;
assert(m);
assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
/* Looks for a suitable "uplink", via black magic: an interface that is up and where the
* default route with the highest priority points to. */
HASHMAP_FOREACH(link, m->links_by_index) {
if (link == exclude)
continue;
if (link->state != LINK_STATE_CONFIGURED)
continue;
gw = link_find_default_gateway(link, family, gw);
}
if (!gw)
return -ENOENT;
if (ret) {
assert(gw->link);
*ret = gw->link;
}
return 0;
}
static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) {
Route *route;
Address *a;
assert(link);
assert(link->manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
SET_FOREACH(route, link->routes) {
if (!route_exists(route))
continue;
if (route->family != family)
continue;
if (!in_addr_is_set(route->family, &route->dst))
continue;
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) > 0)
return true;
}
if (link->manager->manage_foreign_routes)
return false;
/* If we do not manage foreign routes, then there may exist a prefix route we do not know,
* which was created on configuring an address. Hence, also check the addresses. */
SET_FOREACH(a, link->addresses) {
if (!address_is_ready(a))
continue;
if (a->family != family)
continue;
if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
continue;
if (in_addr_is_set(a->family, &a->in_addr_peer))
continue;
if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, address) > 0)
return true;
}
return false;
}
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw) {
assert(link);
assert(gw);
if (onlink)
return true;
if (!in_addr_is_set(family, gw))
return true;
if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
return true;
return link_address_is_reachable(link, family, gw);
}
static const char * const route_type_table[__RTN_MAX] = {
[RTN_UNICAST] = "unicast",
[RTN_LOCAL] = "local",
[RTN_BROADCAST] = "broadcast",
[RTN_ANYCAST] = "anycast",
[RTN_MULTICAST] = "multicast",
[RTN_BLACKHOLE] = "blackhole",
[RTN_UNREACHABLE] = "unreachable",
[RTN_PROHIBIT] = "prohibit",
[RTN_THROW] = "throw",
[RTN_NAT] = "nat",
[RTN_XRESOLVE] = "xresolve",
};
assert_cc(__RTN_MAX <= UCHAR_MAX);
DEFINE_STRING_TABLE_LOOKUP(route_type, int);
static const char * const route_scope_table[] = {
[RT_SCOPE_UNIVERSE] = "global",
[RT_SCOPE_SITE] = "site",
[RT_SCOPE_LINK] = "link",
[RT_SCOPE_HOST] = "host",
[RT_SCOPE_NOWHERE] = "nowhere",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(route_scope, int, UINT8_MAX);
static const char * const route_protocol_table[] = {
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(route_protocol, int, UINT8_MAX);
static const char * const route_protocol_full_table[] = {
[RTPROT_REDIRECT] = "redirect",
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
[RTPROT_GATED] = "gated",
[RTPROT_RA] = "ra",
[RTPROT_MRT] = "mrt",
[RTPROT_ZEBRA] = "zebra",
[RTPROT_BIRD] = "bird",
[RTPROT_DNROUTED] = "dnrouted",
[RTPROT_XORP] = "xorp",
[RTPROT_NTK] = "ntk",
[RTPROT_DHCP] = "dhcp",
[RTPROT_MROUTED] = "mrouted",
[RTPROT_BABEL] = "babel",
[RTPROT_BGP] = "bgp",
[RTPROT_ISIS] = "isis",
[RTPROT_OSPF] = "ospf",
[RTPROT_RIP] = "rip",
[RTPROT_EIGRP] = "eigrp",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(route_protocol_full, int, UINT8_MAX);
int route_flags_to_string_alloc(uint32_t flags, char **ret) {
_cleanup_free_ char *str = NULL;
static const struct {
uint32_t flag;
const char *name;
} map[] = {
{ RTNH_F_DEAD, "dead" }, /* Nexthop is dead (used by multipath) */
{ RTNH_F_PERVASIVE, "pervasive" }, /* Do recursive gateway lookup */
{ RTNH_F_ONLINK, "onlink" }, /* Gateway is forced on link */
{ RTNH_F_OFFLOAD, "offload" }, /* Nexthop is offloaded */
{ RTNH_F_LINKDOWN, "linkdown" }, /* carrier-down on nexthop */
{ RTNH_F_UNRESOLVED, "unresolved" }, /* The entry is unresolved (ipmr) */
{ RTNH_F_TRAP, "trap" }, /* Nexthop is trapping packets */
};
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (flags & map[i].flag &&
!strextend_with_separator(&str, ",", map[i].name))
return -ENOMEM;
*ret = TAKE_PTR(str);
return 0;
}
static const char * const route_table_table[] = {
[RT_TABLE_DEFAULT] = "default",
[RT_TABLE_MAIN] = "main",
[RT_TABLE_LOCAL] = "local",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
int manager_get_route_table_from_string(const Manager *m, const char *s, uint32_t *ret) {
uint32_t t;
int r;
assert(m);
assert(s);
assert(ret);
r = route_table_from_string(s);
if (r >= 0) {
*ret = (uint32_t) r;
return 0;
}
t = PTR_TO_UINT32(hashmap_get(m->route_table_numbers_by_name, s));
if (t != 0) {
*ret = t;
return 0;
}
r = safe_atou32(s, &t);
if (r < 0)
return r;
if (t == 0)
return -ERANGE;
*ret = t;
return 0;
}
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret) {
_cleanup_free_ char *str = NULL;
const char *s;
int r;
assert(m);
assert(ret);
if (table == 0)
return -EINVAL;
s = route_table_to_string(table);
if (!s)
s = hashmap_get(m->route_table_names_by_number, UINT32_TO_PTR(table));
if (s)
/* Currently, this is only used in debugging logs. To not confuse any bug
* reports, let's include the table number. */
r = asprintf(&str, "%s(%" PRIu32 ")", s, table);
else
r = asprintf(&str, "%" PRIu32, table);
if (r < 0)
return -ENOMEM;
*ret = TAKE_PTR(str);
return 0;
}
int config_parse_route_table_names(
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) {
Manager *m = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(userdata);
if (isempty(rvalue)) {
m->route_table_names_by_number = hashmap_free(m->route_table_names_by_number);
m->route_table_numbers_by_name = hashmap_free(m->route_table_numbers_by_name);
return 0;
}
for (const char *p = rvalue;;) {
_cleanup_free_ char *name = NULL;
uint32_t table;
char *num;
r = extract_first_word(&p, &name, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid RouteTable=, ignoring assignment: %s", rvalue);
return 0;
}
if (r == 0)
return 0;
num = strchr(name, ':');
if (!num) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid route table name and number pair, ignoring assignment: %s", name);
continue;
}
*num++ = '\0';
if (STR_IN_SET(name, "default", "main", "local")) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Route table name %s already predefined. Ignoring assignment: %s:%s", name, name, num);
continue;
}
r = safe_atou32(num, &table);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse route table number '%s', ignoring assignment: %s:%s", num, name, num);
continue;
}
if (table == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid route table number, ignoring assignment: %s:%s", name, num);
continue;
}
r = hashmap_ensure_put(&m->route_table_numbers_by_name, &string_hash_ops_free, name, UINT32_TO_PTR(table));
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name, num);
continue;
}
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to store route table name and number pair, ignoring assignment: %s:%s", name, num);
continue;
}
if (r == 0)
/* The entry is duplicated. It should not be added to route_table_names_by_number hashmap. */
continue;
r = hashmap_ensure_put(&m->route_table_names_by_number, NULL, UINT32_TO_PTR(table), name);
if (r < 0) {
hashmap_remove(m->route_table_numbers_by_name, name);
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST)
log_syntax(unit, LOG_WARNING, filename, line, r,
"Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name, num);
else
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to store route table name and number pair, ignoring assignment: %s:%s", name, num);
continue;
}
assert(r > 0);
TAKE_PTR(name);
}
}

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include "conf-parser.h"
typedef struct Link Link;
typedef struct Manager Manager;
unsigned routes_max(void);
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw);
int route_type_from_string(const char *s) _pure_;
const char *route_type_to_string(int t) _const_;
int route_scope_from_string(const char *s);
int route_scope_to_string_alloc(int t, char **ret);
int route_protocol_from_string(const char *s);
int route_protocol_to_string_alloc(int t, char **ret);
int route_protocol_full_from_string(const char *s);
int route_protocol_full_to_string_alloc(int t, char **ret);
int route_flags_to_string_alloc(uint32_t flags, char **ret);
int manager_get_route_table_from_string(const Manager *m, const char *table, uint32_t *ret);
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret);
CONFIG_PARSER_PROTOTYPE(config_parse_route_table_names);

View File

@ -13,166 +13,13 @@
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-nexthop.h" #include "networkd-nexthop.h"
#include "networkd-queue.h" #include "networkd-queue.h"
#include "networkd-route-util.h"
#include "networkd-route.h" #include "networkd-route.h"
#include "parse-util.h" #include "parse-util.h"
#include "string-table.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "strxcpyx.h"
#include "sysctl-util.h"
#include "vrf.h" #include "vrf.h"
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
static const char * const route_type_table[__RTN_MAX] = {
[RTN_UNICAST] = "unicast",
[RTN_LOCAL] = "local",
[RTN_BROADCAST] = "broadcast",
[RTN_ANYCAST] = "anycast",
[RTN_MULTICAST] = "multicast",
[RTN_BLACKHOLE] = "blackhole",
[RTN_UNREACHABLE] = "unreachable",
[RTN_PROHIBIT] = "prohibit",
[RTN_THROW] = "throw",
[RTN_NAT] = "nat",
[RTN_XRESOLVE] = "xresolve",
};
assert_cc(__RTN_MAX <= UCHAR_MAX);
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_type, int);
static const char * const route_scope_table[] = {
[RT_SCOPE_UNIVERSE] = "global",
[RT_SCOPE_SITE] = "site",
[RT_SCOPE_LINK] = "link",
[RT_SCOPE_HOST] = "host",
[RT_SCOPE_NOWHERE] = "nowhere",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_scope, int);
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_scope, int, UINT8_MAX);
static const char * const route_table_table[] = {
[RT_TABLE_DEFAULT] = "default",
[RT_TABLE_MAIN] = "main",
[RT_TABLE_LOCAL] = "local",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
int manager_get_route_table_from_string(const Manager *m, const char *s, uint32_t *ret) {
uint32_t t;
int r;
assert(m);
assert(s);
assert(ret);
r = route_table_from_string(s);
if (r >= 0) {
*ret = (uint32_t) r;
return 0;
}
t = PTR_TO_UINT32(hashmap_get(m->route_table_numbers_by_name, s));
if (t != 0) {
*ret = t;
return 0;
}
r = safe_atou32(s, &t);
if (r < 0)
return r;
if (t == 0)
return -ERANGE;
*ret = t;
return 0;
}
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret) {
_cleanup_free_ char *str = NULL;
const char *s;
int r;
assert(m);
assert(ret);
if (table == 0)
return -EINVAL;
s = route_table_to_string(table);
if (!s)
s = hashmap_get(m->route_table_names_by_number, UINT32_TO_PTR(table));
if (s)
/* Currently, this is only used in debugging logs. To not confuse any bug
* reports, let's include the table number. */
r = asprintf(&str, "%s(%" PRIu32 ")", s, table);
else
r = asprintf(&str, "%" PRIu32, table);
if (r < 0)
return -ENOMEM;
*ret = TAKE_PTR(str);
return 0;
}
static const char * const route_protocol_table[] = {
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(route_protocol, int, UINT8_MAX);
static const char * const route_protocol_full_table[] = {
[RTPROT_REDIRECT] = "redirect",
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
[RTPROT_GATED] = "gated",
[RTPROT_RA] = "ra",
[RTPROT_MRT] = "mrt",
[RTPROT_ZEBRA] = "zebra",
[RTPROT_BIRD] = "bird",
[RTPROT_DNROUTED] = "dnrouted",
[RTPROT_XORP] = "xorp",
[RTPROT_NTK] = "ntk",
[RTPROT_DHCP] = "dhcp",
[RTPROT_MROUTED] = "mrouted",
[RTPROT_BABEL] = "babel",
[RTPROT_BGP] = "bgp",
[RTPROT_ISIS] = "isis",
[RTPROT_OSPF] = "ospf",
[RTPROT_RIP] = "rip",
[RTPROT_EIGRP] = "eigrp",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_protocol_full, int, UINT8_MAX);
static unsigned routes_max(void) {
static thread_local unsigned cached = 0;
_cleanup_free_ char *s4 = NULL, *s6 = NULL;
unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
if (cached > 0)
return cached;
if (sysctl_read_ip_property(AF_INET, NULL, "route/max_size", &s4) >= 0)
if (safe_atou(s4, &val4) >= 0 && val4 == 2147483647U)
/* This is the default "no limit" value in the kernel */
val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
if (sysctl_read_ip_property(AF_INET6, NULL, "route/max_size", &s6) >= 0)
(void) safe_atou(s6, &val6);
cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
return cached;
}
int route_new(Route **ret) { int route_new(Route **ret) {
_cleanup_(route_freep) Route *route = NULL; _cleanup_(route_freep) Route *route = NULL;
@ -695,115 +542,9 @@ void link_mark_routes(Link *link, NetworkConfigSource source, const struct in6_a
} }
} }
static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) {
Route *route;
Address *a;
assert(link);
assert(link->manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
SET_FOREACH(route, link->routes) {
if (!route_exists(route))
continue;
if (route->family != family)
continue;
if (!in_addr_is_set(route->family, &route->dst))
continue;
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) > 0)
return true;
}
if (link->manager->manage_foreign_routes)
return false;
/* If we do not manage foreign routes, then there may exist a prefix route we do not know,
* which was created on configuring an address. Hence, also check the addresses. */
SET_FOREACH(a, link->addresses) {
if (!address_is_ready(a))
continue;
if (a->family != family)
continue;
if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
continue;
if (in_addr_is_set(a->family, &a->in_addr_peer))
continue;
if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, address) > 0)
return true;
}
return false;
}
static Route *link_find_default_gateway(Link *link, int family, Route *gw) {
Route *route;
assert(link);
SET_FOREACH(route, link->routes) {
if (!route_exists(route))
continue;
if (family != AF_UNSPEC && route->family != family)
continue;
if (route->dst_prefixlen != 0)
continue;
if (route->src_prefixlen != 0)
continue;
if (route->table != RT_TABLE_MAIN)
continue;
if (route->type != RTN_UNICAST)
continue;
if (route->scope != RT_SCOPE_UNIVERSE)
continue;
if (!in_addr_is_set(route->gw_family, &route->gw))
continue;
if (gw) {
if (route->gw_weight > gw->gw_weight)
continue;
if (route->priority >= gw->priority)
continue;
}
gw = route;
}
return gw;
}
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret) {
Route *gw = NULL;
Link *link;
assert(m);
assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
/* Looks for a suitable "uplink", via black magic: an interface that is up and where the
* default route with the highest priority points to. */
HASHMAP_FOREACH(link, m->links_by_index) {
if (link == exclude)
continue;
if (link->state != LINK_STATE_CONFIGURED)
continue;
gw = link_find_default_gateway(link, family, gw);
}
if (!gw)
return -ENOENT;
if (ret) {
assert(gw->link);
*ret = gw->link;
}
return 0;
}
static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) { static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
_cleanup_free_ char *state = NULL, *dst = NULL, *src = NULL, *gw_alloc = NULL, *prefsrc = NULL, _cleanup_free_ char *state = NULL, *dst = NULL, *src = NULL, *gw_alloc = NULL, *prefsrc = NULL,
*table = NULL, *scope = NULL, *proto = NULL; *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
const char *gw = NULL; const char *gw = NULL;
assert(route); assert(route);
@ -851,15 +592,16 @@ static void log_route_debug(const Route *route, const char *str, const Link *lin
(void) route_scope_to_string_alloc(route->scope, &scope); (void) route_scope_to_string_alloc(route->scope, &scope);
(void) manager_get_route_table_to_string(manager, route->table, &table); (void) manager_get_route_table_to_string(manager, route->table, &table);
(void) route_protocol_full_to_string_alloc(route->protocol, &proto); (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
(void) route_flags_to_string_alloc(route->flags, &flags);
log_link_debug(link, log_link_debug(link,
"%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, " "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
"proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32, "proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32", flags: %s",
str, strna(network_config_source_to_string(route->source)), strna(state), str, strna(network_config_source_to_string(route->source)), strna(state),
strna(dst), strna(src), strna(gw), strna(prefsrc), strna(dst), strna(src), strna(gw), strna(prefsrc),
strna(scope), strna(table), strna(proto), strna(scope), strna(table), strna(proto),
strna(route_type_to_string(route->type)), strna(route_type_to_string(route->type)),
route->nexthop_id, route->priority); route->nexthop_id, route->priority, strna(flags));
} }
static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) { static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) {
@ -1628,22 +1370,6 @@ int link_request_static_routes(Link *link, bool only_ipv4) {
return 0; return 0;
} }
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw) {
assert(link);
assert(gw);
if (onlink)
return true;
if (!in_addr_is_set(family, gw))
return true;
if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
return true;
return link_address_is_reachable(link, family, gw);
}
static int route_is_ready_to_configure(const Route *route, Link *link) { static int route_is_ready_to_configure(const Route *route, Link *link) {
int r; int r;
@ -2958,112 +2684,6 @@ int config_parse_multipath_route(
return 0; return 0;
} }
int config_parse_route_table_names(
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) {
Manager *m = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(userdata);
if (isempty(rvalue)) {
m->route_table_names_by_number = hashmap_free(m->route_table_names_by_number);
m->route_table_numbers_by_name = hashmap_free(m->route_table_numbers_by_name);
return 0;
}
for (const char *p = rvalue;;) {
_cleanup_free_ char *name = NULL;
uint32_t table;
char *num;
r = extract_first_word(&p, &name, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid RouteTable=, ignoring assignment: %s", rvalue);
return 0;
}
if (r == 0)
return 0;
num = strchr(name, ':');
if (!num) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid route table name and number pair, ignoring assignment: %s", name);
continue;
}
*num++ = '\0';
if (STR_IN_SET(name, "default", "main", "local")) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Route table name %s already predefined. Ignoring assignment: %s:%s", name, name, num);
continue;
}
r = safe_atou32(num, &table);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse route table number '%s', ignoring assignment: %s:%s", num, name, num);
continue;
}
if (table == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid route table number, ignoring assignment: %s:%s", name, num);
continue;
}
r = hashmap_ensure_put(&m->route_table_numbers_by_name, &string_hash_ops_free, name, UINT32_TO_PTR(table));
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name, num);
continue;
}
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to store route table name and number pair, ignoring assignment: %s:%s", name, num);
continue;
}
if (r == 0)
/* The entry is duplicated. It should not be added to route_table_names_by_number hashmap. */
continue;
r = hashmap_ensure_put(&m->route_table_names_by_number, NULL, UINT32_TO_PTR(table), name);
if (r < 0) {
hashmap_remove(m->route_table_numbers_by_name, name);
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST)
log_syntax(unit, LOG_WARNING, filename, line, r,
"Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name, num);
else
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to store route table name and number pair, ignoring assignment: %s:%s", name, num);
continue;
}
assert(r > 0);
TAKE_PTR(name);
}
}
static int route_section_verify(Route *route, Network *network) { static int route_section_verify(Route *route, Network *network) {
if (section_is_invalid(route->section)) if (section_is_invalid(route->section))
return -EINVAL; return -EINVAL;

View File

@ -80,8 +80,6 @@ int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li
int route_remove(Route *route); int route_remove(Route *route);
int route_get(Manager *manager, Link *link, const Route *in, Route **ret); int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw);
int link_drop_routes(Link *link); int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link); int link_drop_foreign_routes(Link *link);
@ -104,9 +102,6 @@ int network_add_ipv4ll_route(Network *network);
int network_add_default_route_on_device(Network *network); int network_add_default_route_on_device(Network *network);
void network_drop_invalid_routes(Network *network); void network_drop_invalid_routes(Network *network);
int manager_get_route_table_from_string(const Manager *m, const char *table, uint32_t *ret);
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Route, route); DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Route, route);
void link_mark_routes(Link *link, NetworkConfigSource source, const struct in6_addr *router); void link_mark_routes(Link *link, NetworkConfigSource source, const struct in6_addr *router);
@ -124,5 +119,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window);
CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu); CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route); CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route);
CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss); CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss);
CONFIG_PARSER_PROTOTYPE(config_parse_route_table_names);
CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop); CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop);

View File

@ -13,7 +13,7 @@
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-queue.h" #include "networkd-queue.h"
#include "networkd-route.h" #include "networkd-route-util.h"
#include "networkd-routing-policy-rule.h" #include "networkd-routing-policy-rule.h"
#include "networkd-util.h" #include "networkd-util.h"
#include "parse-util.h" #include "parse-util.h"

View File

@ -12,7 +12,7 @@
#include "network-internal.h" #include "network-internal.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-route.h" #include "networkd-route-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "tests.h" #include "tests.h"

View File

@ -565,7 +565,7 @@ static int link_is_managed(Link *l) {
if (r < 0) if (r < 0)
return r; return r;
return !STR_IN_SET(state, "pending", "unmanaged"); return !STR_IN_SET(state, "pending", "initialized", "unmanaged");
} }
static void link_read_settings(Link *l) { static void link_read_settings(Link *l) {

View File

@ -7,3 +7,4 @@ IPv6AcceptRA=true
[IPv6AcceptRA] [IPv6AcceptRA]
Token=prefixstable Token=prefixstable
Token=prefixstable,86b123b969ba4b7eb8b3d8605123525a

View File

@ -7,7 +7,12 @@ IPv6AcceptRA=true
[IPv6AcceptRA] [IPv6AcceptRA]
Token=prefixstable:2002:da8:1:: Token=prefixstable:2002:da8:1::
Token=prefixstable:2002:da8:1::,86b123b969ba4b7eb8b3d8605123525a
# invalid tokens # invalid tokens
Token=prefixstable:2002:da8:1::,00000000000000000000000000000000
Token=prefixstable:2002:da8:1::,
Token=prefixstable,00000000000000000000000000000000
Token=prefixstable,
Token=prefixstable@ Token=prefixstable@
Token=static Token=static
Token=static: Token=static:

View File

@ -3951,8 +3951,8 @@ class NetworkdRATests(unittest.TestCase, Utilities):
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env) output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output) print(output)
self.assertRegex(output, '2002:da8:1:0') self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
self.assertRegex(output, '2002:da8:2:0.*78:9abc') # EUI self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
def test_ipv6_token_prefixstable_without_address(self): def test_ipv6_token_prefixstable_without_address(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network') copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
@ -3961,8 +3961,8 @@ class NetworkdRATests(unittest.TestCase, Utilities):
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env) output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output) print(output)
self.assertRegex(output, '2002:da8:1:0') self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
self.assertRegex(output, '2002:da8:2:0') self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
class NetworkdDHCPServerTests(unittest.TestCase, Utilities): class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
links = [ links = [