1
0
mirror of https://github.com/systemd/systemd synced 2026-04-06 15:14:49 +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
updates:
- 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"
on:
@ -7,6 +11,9 @@ on:
schedule:
- cron: '0 1 * * *'
permissions:
contents: read
jobs:
analyze:
name: Analyze
@ -16,7 +23,6 @@ jobs:
cancel-in-progress: true
permissions:
actions: read
contents: read
security-events: write
strategy:

View File

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

View File

@ -274,6 +274,8 @@ mouse:usb:v04b3p3107:name:*
# Kensington Expert Mouse trackball
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
MOUSE_DPI=400@125

View File

@ -2185,219 +2185,253 @@ Table=1234</programlisting></para>
<refsect1>
<title>[IPv6AcceptRA] Section Options</title>
<para>The [IPv6AcceptRA] section configures the IPv6 Router Advertisement (RA) client, if it is enabled
with the <varname>IPv6AcceptRA=</varname> setting described above:</para>
<para>The [IPv6AcceptRA] section configures the IPv6 Router Advertisement (RA) client, if it is enabled
with the <varname>IPv6AcceptRA=</varname> setting described above:</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Token=</varname></term>
<listitem>
<para>Specifies an optional address generation mode for the Stateless Address
Autoconfiguration (SLAAC). Supported modes are <literal>eui64</literal>,
<literal>static</literal>, and <literal>prefixstable</literal>.</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Token=</varname></term>
<listitem>
<para>Specifies an optional address generation mode for the Stateless Address
Autoconfiguration (SLAAC). The following values are supported:</para>
<para>When the mode is set to <literal>eui64</literal>, then the EUI-64 algorithm will be
used to generate an address for that prefix.</para>
<variablelist>
<varlistentry>
<term><option>eui64</option></term>
<listitem>
<para>
The EUI-64 algorithm will be used to generate an address for that prefix.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>static:<replaceable>ADDRESS</replaceable></option></term>
<listitem>
<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
received in a Router Advertisement (RA) message to form a complete address. Note
that if multiple prefixes are received in an RA message, or in multiple RA messages,
addresses will be formed from each of them using the supplied address. This mode
implements SLAAC but uses a static interface identifier instead of an identifier
generated by using the EUI-64 algorithm. Because the interface identifier is static,
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>When the mode is set to <literal>static</literal>, 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 received in a Router Advertisement
(RA) message to form a complete address. Note that if multiple prefixes are received in an
RA message, or in multiple RA messages, addresses will be formed from each of them using
the supplied address. This mode implements SLAAC but uses a static interface identifier
instead of an identifier generated by using the EUI-64 algorithm. Because the interface
identifier is static, 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>
<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>
mode, then the EUI-64 algorithm will be used to form an interface identifier for that
prefix.</para>
<para>When the mode is set to <literal>prefixstable</literal> the
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> algorithm for generating
interface identifiers will be used. 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 setting can be specified multiple times. If an empty string is assigned, then
the all previous assignments are cleared.</para>
<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>
mode, then the EUI-64 algorithm will be used to form an interface identifier for that
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
the all previous assignments are cleared.</para>
<para>Examples:
<programlisting>Token=eui64
<para>Examples:
<programlisting>Token=eui64
Token=::1a:2b:3c:4d
Token=static:::1a:2b:3c:4d
Token=prefixstable
Token=prefixstable:2002:da8:1::</programlisting></para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseDNS=</varname></term>
<listitem>
<para>When true (the default), the DNS servers received in the Router Advertisement will be used.</para>
<varlistentry>
<term><varname>UseDNS=</varname></term>
<listitem>
<para>When true (the default), the DNS servers received in the Router Advertisement will be used.</para>
<para>This corresponds to the <option>nameserver</option> option in <citerefentry
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<para>This corresponds to the <option>nameserver</option> option in <citerefentry
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseDomains=</varname></term>
<listitem>
<para>Takes a boolean, or the special value <literal>route</literal>. When true, the domain name
received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
effect of the <option>Domains=</option> setting when the argument is prefixed with
<literal>~</literal>. Defaults to false.</para>
<varlistentry>
<term><varname>UseDomains=</varname></term>
<listitem>
<para>Takes a boolean, or the special value <literal>route</literal>. When true, the domain name
received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
effect of the <option>Domains=</option> setting when the argument is prefixed with
<literal>~</literal>. Defaults to false.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
<para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteTable=<replaceable>num</replaceable></varname></term>
<listitem>
<para>The table identifier for the routes received in the Router Advertisement
(a number between 1 and 4294967295, or 0 to unset).
The table can be retrieved using <command>ip route show table <replaceable>num</replaceable></command>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteTable=<replaceable>num</replaceable></varname></term>
<listitem>
<para>The table identifier for the routes received in the Router Advertisement
(a number between 1 and 4294967295, or 0 to unset).
The table can be retrieved using <command>ip route show table <replaceable>num</replaceable></command>.
</para>
</listitem>
</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>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>UseMTU=</varname></term>
<listitem>
<para>Takes a boolean. When true, the MTU received in the Router Advertisement will be
used. Defaults to true.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseMTU=</varname></term>
<listitem>
<para>Takes a boolean. When true, the MTU received in the Router Advertisement will be
used. Defaults to true.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseGateway=</varname></term>
<listitem>
<para>When true (the default), the router address will be configured as the default gateway.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseGateway=</varname></term>
<listitem>
<para>When true (the default), the router address will be configured as the default gateway.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseRoutePrefix=</varname></term>
<listitem>
<para>When true (the default), the routes corresponding to the route prefixes received in
the Router Advertisement will be configured.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseRoutePrefix=</varname></term>
<listitem>
<para>When true (the default), the routes corresponding to the route prefixes received in
the Router Advertisement will be configured.</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
precedence over any statically configured ones.</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
precedence over any statically configured ones.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseOnLinkPrefix=</varname></term>
<listitem>
<para>When true (the default), the onlink prefix received in the Router Advertisement will be
used and takes precedence over any statically configured ones.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseOnLinkPrefix=</varname></term>
<listitem>
<para>When true (the default), the onlink prefix received in the Router Advertisement will be
used and takes precedence over any statically configured ones.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouterDenyList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
take a prefix length after <literal>/</literal>. Any information advertised by the listed
router is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouterDenyList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
take a prefix length after <literal>/</literal>. Any information advertised by the listed
router is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouterAllowList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
take a prefix length after <literal>/</literal>. Only information advertised by the listed
router is accepted. Note that if <varname>RouterAllowList=</varname> is configured then
<varname>RouterDenyList=</varname> is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouterAllowList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
take a prefix length after <literal>/</literal>. Only information advertised by the listed
router is accepted. Note that if <varname>RouterAllowList=</varname> is configured then
<varname>RouterDenyList=</varname> is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PrefixDenyList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
in the list are ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PrefixDenyList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
in the list are ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PrefixAllowList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
in the list are allowed. Note that if <varname>PrefixAllowList=</varname> is configured
then <varname>PrefixDenyList=</varname> is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PrefixAllowList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
in the list are allowed. Note that if <varname>PrefixAllowList=</varname> is configured
then <varname>PrefixDenyList=</varname> is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteDenyList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
advertisements in the list are ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteDenyList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
advertisements in the list are ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteAllowList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
advertisements in the list are allowed. Note that if <varname>RouteAllowList=</varname> is
configured then <varname>RouteDenyList=</varname> is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteAllowList=</varname></term>
<listitem>
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
advertisements in the list are allowed. Note that if <varname>RouteAllowList=</varname> is
configured then <varname>RouteDenyList=</varname> is ignored.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>DHCPv6Client=</varname></term>
<listitem>
<para>Takes a boolean, or the special value <literal>always</literal>. When true, the
DHCPv6 client will be started when the RA has the managed or other information flag. If set
to <literal>always</literal>, the DHCPv6 client will be started in managed mode when an RA
is received, even if neither managed nor other information flag is set in the RA. This will
be ignored when <varname>WithoutRA=</varname> in the [DHCPv6] section is enabled, or
<varname>UplinkInterface=:self</varname> in the [DHCPv6PrefixDelegation] section is
specified. Defaults to true.</para>
</listitem>
</varlistentry>
</variablelist>
<varlistentry>
<term><varname>DHCPv6Client=</varname></term>
<listitem>
<para>Takes a boolean, or the special value <literal>always</literal>. When true, the
DHCPv6 client will be started when the RA has the managed or other information flag. If set
to <literal>always</literal>, the DHCPv6 client will be started in managed mode when an RA
is received, even if neither managed nor other information flag is set in the RA. This will
be ignored when <varname>WithoutRA=</varname> in the [DHCPv6] section is enabled, or
<varname>UplinkInterface=:self</varname> in the [DHCPv6PrefixDelegation] section is
specified. Defaults to true.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>

View File

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

View File

@ -4,6 +4,7 @@
#include "sd-id128.h"
#include "id128-util.h"
#include "memory-util.h"
#include "networkd-address-generation.h"
#include "networkd-link.h"
@ -35,6 +36,7 @@ typedef enum AddressGenerationType {
typedef struct IPv6Token {
AddressGenerationType type;
struct in6_addr address;
sd_id128_t secret_key;
} IPv6Token;
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(
Link *link,
const sd_id128_t *app_id,
const sd_id128_t *secret_key,
const struct in6_addr *prefix,
struct in6_addr *ret) {
sd_id128_t secret_machine_key;
struct in6_addr addr;
sd_id128_t secret_key;
uint8_t i;
int r;
assert(link);
assert(app_id);
assert(secret_key);
assert(prefix);
assert(ret);
r = sd_id128_get_machine_app_specific(*app_id, &secret_key);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m");
if (sd_id128_is_null(*secret_key)) {
r = sd_id128_get_machine_app_specific(*app_id, &secret_machine_key);
if (r < 0)
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
* 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
* address which ends up being unusable due to duplication on the link. */
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))
break;
@ -192,7 +200,7 @@ static int generate_addresses(
if (in6_addr_is_set(&j->address) && !in6_addr_equal(&j->address, &masked))
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;
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) {
siphash24_compress(&p->type, sizeof(p->type), 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) {
@ -253,7 +262,11 @@ static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
if (r != 0)
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(
@ -263,12 +276,13 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ipv6_token_compare_func,
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;
assert(tokens);
assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX);
assert(addr);
assert(secret_key);
p = new(IPv6Token, 1);
if (!p)
@ -277,6 +291,7 @@ static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct
*p = (IPv6Token) {
.type = type,
.address = *addr,
.secret_key = *secret_key,
};
return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
@ -294,10 +309,12 @@ int config_parse_address_generation_type(
void *data,
void *userdata) {
_cleanup_free_ char *addr_alloc = NULL;
sd_id128_t secret_key = SD_ID128_NULL;
union in_addr_union buffer = {};
AddressGenerationType type;
Set **tokens = data;
const char *p;
const char *addr;
int r;
assert(filename);
@ -310,33 +327,64 @@ int config_parse_address_generation_type(
return 0;
}
if ((p = startswith(rvalue, "prefixstable"))) {
if ((addr = startswith(rvalue, "prefixstable"))) {
const char *comma;
type = ADDRESS_GENERATION_PREFIXSTABLE;
if (*p == ':')
p++;
else if (*p == '\0')
p = NULL;
else {
if (*addr == ':') {
addr++;
comma = strchr(addr, ',');
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,
"Invalid IPv6 token mode in %s=, ignoring assignment: %s",
lvalue, rvalue);
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")) {
type = ADDRESS_GENERATION_EUI64;
p = NULL;
addr = NULL;
} else {
type = ADDRESS_GENERATION_STATIC;
p = startswith(rvalue, "static:");
if (!p)
p = rvalue;
addr = startswith(rvalue, "static:");
if (!addr)
addr = rvalue;
}
if (p) {
r = in_addr_from_string(AF_INET6, p, &buffer);
if (addr) {
r = in_addr_from_string(AF_INET6, addr, &buffer);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse IP address in %s=, ignoring assignment: %s",
@ -371,7 +419,7 @@ int config_parse_address_generation_type(
assert_not_reached();
}
r = ipv6_token_add(tokens, type, &buffer.in6);
r = ipv6_token_add(tokens, type, &buffer.in6, &secret_key);
if (r < 0)
return log_oom();

View File

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

View File

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

View File

@ -12,7 +12,7 @@
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-route-util.h"
#include "parse-util.h"
#include "set.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) {
_cleanup_free_ char *state = NULL, *gw = NULL, *group = NULL;
_cleanup_free_ char *state = NULL, *gw = NULL, *group = NULL, *flags = NULL;
struct nexthop_grp *nhg;
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) in_addr_to_string(nexthop->family, &nexthop->gw, &gw);
(void) route_flags_to_string_alloc(nexthop->flags, &flags);
HASHMAP_FOREACH(nhg, nexthop->group)
(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),
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) {

View File

@ -15,7 +15,7 @@
#include "networkd-network.h"
#include "networkd-queue.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-route-util.h"
#include "parse-util.h"
#include "radv-internal.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-nexthop.h"
#include "networkd-queue.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 "strxcpyx.h"
#include "sysctl-util.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) {
_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) {
_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;
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) manager_get_route_table_to_string(manager, route->table, &table);
(void) route_protocol_full_to_string_alloc(route->protocol, &proto);
(void) route_flags_to_string_alloc(route->flags, &flags);
log_link_debug(link,
"%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),
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->priority);
route->nexthop_id, route->priority, strna(flags));
}
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;
}
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) {
int r;
@ -2958,112 +2684,6 @@ int config_parse_multipath_route(
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) {
if (section_is_invalid(route->section))
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_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_foreign_routes(Link *link);
@ -104,9 +102,6 @@ int network_add_ipv4ll_route(Network *network);
int network_add_default_route_on_device(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);
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_multipath_route);
CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss);
CONFIG_PARSER_PROTOTYPE(config_parse_route_table_names);
CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop);

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,12 @@ IPv6AcceptRA=true
[IPv6AcceptRA]
Token=prefixstable:2002:da8:1::
Token=prefixstable:2002:da8:1::,86b123b969ba4b7eb8b3d8605123525a
# invalid tokens
Token=prefixstable:2002:da8:1::,00000000000000000000000000000000
Token=prefixstable:2002:da8:1::,
Token=prefixstable,00000000000000000000000000000000
Token=prefixstable,
Token=prefixstable@
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)
print(output)
self.assertRegex(output, '2002:da8:1:0')
self.assertRegex(output, '2002:da8:2:0.*78:9abc') # EUI
self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
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')
@ -3961,8 +3961,8 @@ class NetworkdRATests(unittest.TestCase, Utilities):
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '2002:da8:1:0')
self.assertRegex(output, '2002:da8:2:0')
self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
links = [