Compare commits

...

29 Commits

Author SHA1 Message Date
Lennart Poettering 0cfb490fe9
Merge pull request #16585 from yuwata/network-dhcp6-fixes
network: fix several DHCP6 PD issues, and cleanup DHCP4 and NDISC
2020-07-29 15:59:11 +02:00
Lennart Poettering ee56c072b9
Merge pull request #16590 from keszybz/test-fs-util-relax
Small adjustements to let various tests pass in overloaded Fedora infra and related changes
2020-07-29 15:54:51 +02:00
Lennart Poettering f8528230b3
Merge pull request #16576 from keszybz/bump-tmp-size
Increase /tmp size to 50% of RAM
2020-07-29 15:53:30 +02:00
Gaurav Singh b1d666ac58 test-cgroup-util: Handle result=NULL as empty string
Signed-off-by: Gaurav Singh <gaurav1086@gmail.com>
2020-07-29 15:36:38 +02:00
Daan De Meyer f649325ba7 firstboot: Update help string with --root-shell options 2020-07-29 15:35:59 +02:00
Zbigniew Jędrzejewski-Szmek c550cb7f8c test-sleep: add more logging, show secure boot mode
In https://bugzilla.redhat.com/show_bug.cgi?id=1858219 a user
reported that hibernation is not supported. This is probably caused
by secure boot, but our current logging does not make this
obvious.
2020-07-29 11:12:13 +02:00
Zbigniew Jędrzejewski-Szmek 02e1eb6d02 NEWS: mention new tmpfs limits 2020-07-29 11:07:29 +02:00
Zbigniew Jędrzejewski-Szmek 362a55fc14 Bump /tmp size back to 50% of RAM
This should be enough to fix https://bugzilla.redhat.com/show_bug.cgi?id=1856514.
But the limit should be significantly higher than 10% anyway. By setting a
limit on /tmp at 10% we'll break many reasonable use cases, even though the
machine would deal fine with a much larger fraction devoted to /tmp.
(In the first version of this patch I made it 25% with the comment that
"Even 25% might be too low.". The kernel default is 50%, and we have been using
that seemingly without trouble since https://fedoraproject.org/wiki/Features/tmp-on-tmpfs.
So let's just make it 50% again.)

See 7d85383edb.

(Another consideration is that we learned from from the whole initiative with
zram in Fedora that a reasonable size for zram is 0.5-1.5 of RAM, and that pretty
much all systems benefit from having zram or zswap enabled. Thus it is reasonable
to assume that it'll become widely used. Taking the usual compression effectiveness
of 0.2 into account, machines have effective memory available of between
1.0 - 0.2*0.5 + 0.5 = 1.4 (for zram sized to 0.5 of RAM) and
1.0 - 0.2*1.5 + 1.5 = 2.2 (for zram 1.5 sized to 1.5 of RAM) times RAM size.
This means that the 10% was really like 7-4% of effective memory.)

A comment is added to mount-util.h to clarify that tmp.mount is separate.
2020-07-29 11:07:04 +02:00
Yu Watanabe 99e015e28c network: rename settings about DHCPv6 Prefix Delegation
Closes #16602.
2020-07-29 05:50:08 +09:00
Yu Watanabe 61c0ef4ff3 network: make RADVPrefixDelegation enum bitfield
This should not change any behavior.
2020-07-29 05:09:42 +09:00
Yu Watanabe ea121d8f25 network: update address infomation even if link is in failed or linger state
As the link may be reconfigured later. If we do not update the address
information, then its setup state or operstate may not be updated
correctly.
2020-07-29 02:05:05 +09:00
Yu Watanabe e55265184b network: do not assume static addresses are configured
link_request_set_routes() is also called when a dynamic address is
configured. At that time, static addresses may not be configured yet.

Fixes #16546.
2020-07-29 02:05:05 +09:00
Yu Watanabe 15797d6a2b network: check at least one dynamic address is assigned when DHCP is enabled 2020-07-29 02:05:05 +09:00
Yu Watanabe 1633c45731 network: dhcp6: drop addresses and delegated prefixes on client stop
Previously, we did not drop addresses and delegated prefixes when
DHCP6 client is stopped.

Fixes #15455.
Fixes #13564.
2020-07-29 02:05:05 +09:00
Yu Watanabe 1c09d84e42 network: rename ipv4ll_address -> ipv4ll_address_configured 2020-07-29 02:05:05 +09:00
Yu Watanabe b0b9776656 network: ndisc: also remove old DNSSL or RDNSS records after an SLAAC address is ready 2020-07-29 02:05:05 +09:00
Yu Watanabe 69203fba70 network: ndisc: remove old addresses and routes after at least one SLAAC address becomes ready
Otherwise, the old addresses will exist in deperecated state.
2020-07-29 02:05:05 +09:00
Yu Watanabe 6e537f62d7 network: dhcp4: release old lease after the new address become ready
Previously, on DHCPv4 address renewal, the old address may be removed
while the new address is not ready yet.

This also simplifies the logic of removing address and routes.
2020-07-29 02:05:05 +09:00
Yu Watanabe 80b0e86084 network: make address/route_configure optionally return created Address/Route object 2020-07-29 02:05:05 +09:00
Yu Watanabe 8eec0b9da5 network: set key destructor in several hash_ops 2020-07-29 02:05:05 +09:00
Yu Watanabe 5f58af25e6 network: make link_check_ready() return earlier if the link is not in 'configuring' state 2020-07-29 02:05:05 +09:00
Yu Watanabe 3336e946da network: ndisc: do not set configured flags when addresses or routes are not assigned yet
Just for safety.
2020-07-29 02:05:05 +09:00
Yu Watanabe 5d8c3ec1e9 network: make link enter failed state if address_update() failed 2020-07-29 02:05:05 +09:00
Yu Watanabe 97f000744f network: introduce callback called when an address becomes ready 2020-07-29 02:05:00 +09:00
Yu Watanabe c9d223e803 test-network: add tests for prefix routes 2020-07-29 01:50:54 +09:00
Yu Watanabe 3606ca659e network: add debug log for configuring address 2020-07-29 01:50:54 +09:00
Zbigniew Jędrzejewski-Szmek c21ed6812e test-ndisc-rs: increase timeouts
Timestamp: Mon 2020-07-27 13:50:50 UTC
Monotonic: 985702942708
Hop limit: 64
Flags: <|MANAGED>
Preference: medium
Lifetime: 180
No MTU set
>> Option 3
Valid Lifetime: 500
Preferred Lifetime: 440
Flags: <ONLINK|AUTO>
Prefix Length: 64
Prefix: 2001:db8:dead:beef::
>> Option 25
DNS: 2001:db8:dead:beef::1
Lifetime: 60
>> Option 31
Domain: lab.intra
Lifetime: 60
>> Option 1
Address: 782bcbb36d53
NDISC: Started IPv6 Router Solicitation client
backoff timeout interval  1 3.600s <= 3.987s <= 4.400s
NDISC: Sent Router Solicitation, next solicitation in 3s
backoff timeout interval  2 7.576s <= 8.114s <= 8.374s
NDISC: Sent Router Solicitation, next solicitation in 8s
Assertion 'false' failed at src/libsystemd-network/test-ndisc-rs.c:172, function test_rs_hangcheck(). Aborting.
2020-07-28 10:49:13 +02:00
Zbigniew Jędrzejewski-Szmek 500727c220 test-path: increase timeout
The tests fail in Fedora's koji with a timeout. Let's just bump
the timeout:
--- stderr ---
Failed to connect to system bus: No such file or directory
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-exists.service: Failed to create cgroup /system.slice/kojid.service/path-exists.service: Permission denied
path-exists.service: Succeeded.
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-exists.service: Failed to create cgroup /system.slice/kojid.service/path-exists.service: Permission denied
path-exists.service: Succeeded.
path-exists.path: Succeeded.
Failed to connect to system bus: No such file or directory
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-existsglob.service: Failed to create cgroup /system.slice/kojid.service/path-existsglob.service: Permission denied
path-existsglob.service: Succeeded.
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-existsglob.service: Failed to create cgroup /system.slice/kojid.service/path-existsglob.service: Permission denied
path-existsglob.service: Succeeded.
path-existsglob.path: Succeeded.
Failed to connect to system bus: No such file or directory
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-changed.service: Failed to create cgroup /system.slice/kojid.service/path-changed.service: Permission denied
path-changed.service: Succeeded.
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-changed.service: Failed to create cgroup /system.slice/kojid.service/path-changed.service: Permission denied
path-changed.service: Succeeded.
path-changed.path: Succeeded.
Failed to connect to system bus: No such file or directory
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-modified.service: Failed to create cgroup /system.slice/kojid.service/path-modified.service: Permission denied
path-modified.service: Succeeded.
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-modified.service: Failed to create cgroup /system.slice/kojid.service/path-modified.service: Permission denied
path-modified.service: Succeeded.
path-modified.path: Succeeded.
Failed to connect to system bus: No such file or directory
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-mycustomunit.service: Failed to create cgroup /system.slice/kojid.service/path-mycustomunit.service: Permission denied
path-mycustomunit.service: Succeeded.
path-unit.path: Succeeded.
Failed to connect to system bus: No such file or directory
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-directorynotempty.service: Failed to create cgroup /system.slice/kojid.service/path-directorynotempty.service: Permission denied
path-directorynotempty.service: Succeeded.
-.slice: Failed to enable/disable controllers on cgroup /system.slice/kojid.service, ignoring: Permission denied
path-directorynotempty.service: Failed to create cgroup /system.slice/kojid.service/path-directorynotempty.service: Permission denied
path-directorynotempty.service: Failed to attach to cgroup /system.slice/kojid.service/path-directorynotempty.service: No such file or directory
path-directorynotempty.service: Failed at step CGROUP spawning /bin/true: No such file or directory
path-directorynotempty.service: Main process exited, code=exited, status=219/CGROUP
path-directorynotempty.service: Failed with result 'exit-code'.
Test timeout when testing path-directorynotempty.path
2020-07-28 10:47:15 +02:00
Zbigniew Jędrzejewski-Szmek 933ab8199d test-fs-util: do not assume /dev is always real
When building in Fedora's koji, test-fs-util would fail:
--- command ---
10:18:29 SYSTEMD_LANGUAGE_FALLBACK_MAP='/builddir/build/BUILD/systemd-246-rc2/src/locale/language-fallback-map' PATH='/builddir/build/BUILD/systemd-246-rc2/x86_64-redhat-linux-gnu:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin' SYSTEMD_KBD_MODEL_MAP='/builddir/build/BUILD/systemd-246-rc2/src/locale/kbd-model-map' /builddir/build/BUILD/systemd-246-rc2/x86_64-redhat-linux-gnu/test-fs-util
--- stderr ---
/* test_chase_symlinks */
/* test_unlink_noerrno */
/* test_readlink_and_make_absolute */
/* test_var_tmp */
/* test_dot_or_dot_dot */
/* test_access_fd */
/* test_touch_file */
/* test_unlinkat_deallocate */
/* test_fsync_directory_of_file */
/* test_rename_noreplace */
/* test_path_is_encrypted */
/home encrypted: yes
/var encrypted: yes
/ encrypted: yes
/proc encrypted: no
/sys encrypted: no
/dev encrypted: yes
Assertion 'expect < 0 || ((r > 0) == (expect > 0))' failed at src/test/test-fs-util.c:863, function test_path_is_encrypted_one(). Aborting.
-------

It seems / is encrypted, but /dev is just a normal directory.
2020-07-28 10:39:41 +02:00
37 changed files with 1944 additions and 1400 deletions

4
NEWS
View File

@ -112,6 +112,10 @@ CHANGES WITH 246:
read and even write access to all these otherwise unmappable files, read and even write access to all these otherwise unmappable files,
which is quite likely a major security problem. which is quite likely a major security problem.
* tmpfs mounts automatically created by systemd (/tmp, /run, /dev/shm,
and others) now have a size and inode limits applied (50% of RAM for
/tmp, 10% of RAM for /dev/shm, etc.)
* nss-mymachines lost support for resolution of users and groups, and * nss-mymachines lost support for resolution of users and groups, and
now only does resolution of hostnames. This functionality is now now only does resolution of hostnames. This functionality is now
provided by nss-systemd. Thus, the 'mymachines' entry should be provided by nss-systemd. Thus, the 'mymachines' entry should be

View File

@ -809,16 +809,6 @@
<literal>false</literal>. See the [IPv6PrefixDelegation] and the [IPv6Prefix] sections for more <literal>false</literal>. See the [IPv6PrefixDelegation] and the [IPv6Prefix] sections for more
configuration options.</para></listitem> configuration options.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>IPv6PDSubnetId=</varname></term>
<listitem><para>Configure a specific subnet ID on the interface from a (previously) received prefix delegation.
You can either set "auto" (the default) or a specific subnet ID
(as defined in <ulink url="https://tools.ietf.org/html/rfc4291#section-2.5.4">RFC 4291</ulink>, section 2.5.4),
in which case the allowed value is hexadecimal, from 0 to 0x7fffffffffffffff inclusive.
This option is only effective when used together with <varname>IPv6PrefixDelegation=</varname>
and the corresponding configuration on the upstream interface.
</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>IPv6MTUBytes=</varname></term> <term><varname>IPv6MTUBytes=</varname></term>
<listitem><para>Configures IPv6 maximum transmission unit (MTU). <listitem><para>Configures IPv6 maximum transmission unit (MTU).
@ -1893,25 +1883,6 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>AssignAcquiredDelegatedPrefixAddress=</varname></term>
<listitem>
<para>Takes a boolean. Specifies whether to add an address from the delegated prefixes which are received
from the WAN interface by the <varname>IPv6PrefixDelegation=</varname>. When true (on LAN interfce), the EUI-64
algorithm will be used to form an interface identifier from the delegated prefixes. Defaults to true.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>AssignAcquiredDelegatedPrefixToken=</varname></term>
<listitem>
<para>Specifies an optional address generation mode for <varname>AssignAcquiredDelegatedPrefixAddress=</varname>.
Takes an IPv6 address. When set, the lower bits of the supplied address are combined with the upper bits of a
delegatad prefix received from the WAN interface by the <varname>IPv6PrefixDelegation=</varname> prefixes to
form a complete address.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>PrefixDelegationHint=</varname></term> <term><varname>PrefixDelegationHint=</varname></term>
<listitem> <listitem>
@ -1966,6 +1937,48 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>[DHCPv6PrefixDelegation] Section Options</title>
<para>The [DHCPv6PrefixDelegation] section configures delegated prefix assigned by DHCPv6 server.
The settings in this section are used only when <varname>IPv6PrefixDelegation=</varname> setting is
enabled, or set to <literal>dhcp6</literal>.</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>SubnetId=</varname></term>
<listitem>
<para>Configure a specific subnet ID on the interface from a (previously) received prefix
delegation. You can either set "auto" (the default) or a specific subnet ID (as defined in
<ulink url="https://tools.ietf.org/html/rfc4291#section-2.5.4">RFC 4291</ulink>, section
2.5.4), in which case the allowed value is hexadecimal, from 0 to 0x7fffffffffffffff
inclusive. This option is only effective when used together with
<varname>IPv6PrefixDelegation=</varname> and the corresponding configuration on the upstream
interface.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Assign=</varname></term>
<listitem>
<para>Takes a boolean. Specifies whether to add an address from the delegated prefixes which
are received from the WAN interface by the <varname>IPv6PrefixDelegation=</varname>. When
true (on LAN interfce), the EUI-64 algorithm will be used to form an interface identifier
from the delegated prefixes. Defaults to true.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Token=</varname></term>
<listitem>
<para>Specifies an optional address generation mode for <varname>Assign=</varname>. Takes an
IPv6 address. When set, the lower bits of the supplied address are combined with the upper
bits of a delegatad prefix received from the WAN interface by the
<varname>IPv6PrefixDelegation=</varname> prefixes to form a complete address.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>[IPv6AcceptRA] Section Options</title> <title>[IPv6AcceptRA] Section Options</title>
<para>The [IPv6AcceptRA] section configures the IPv6 Router Advertisement (RA) client, if it is enabled <para>The [IPv6AcceptRA] section configures the IPv6 Router Advertisement (RA) client, if it is enabled

View File

@ -999,16 +999,19 @@ static int help(void) {
" --root-password=PASSWORD Set root password from plaintext password\n" " --root-password=PASSWORD Set root password from plaintext password\n"
" --root-password-file=FILE Set root password from file\n" " --root-password-file=FILE Set root password from file\n"
" --root-password-hashed=HASHED_PASSWORD Set root password from hashed password\n" " --root-password-hashed=HASHED_PASSWORD Set root password from hashed password\n"
" --root-shell=SHELL Set root shell\n"
" --prompt-locale Prompt the user for locale settings\n" " --prompt-locale Prompt the user for locale settings\n"
" --prompt-keymap Prompt the user for keymap settings\n" " --prompt-keymap Prompt the user for keymap settings\n"
" --prompt-timezone Prompt the user for timezone\n" " --prompt-timezone Prompt the user for timezone\n"
" --prompt-hostname Prompt the user for hostname\n" " --prompt-hostname Prompt the user for hostname\n"
" --prompt-root-password Prompt the user for root password\n" " --prompt-root-password Prompt the user for root password\n"
" --prompt-root-shell Prompt the user for root shell\n"
" --prompt Prompt for all of the above\n" " --prompt Prompt for all of the above\n"
" --copy-locale Copy locale from host\n" " --copy-locale Copy locale from host\n"
" --copy-keymap Copy keymap from host\n" " --copy-keymap Copy keymap from host\n"
" --copy-timezone Copy timezone from host\n" " --copy-timezone Copy timezone from host\n"
" --copy-root-password Copy root password from host\n" " --copy-root-password Copy root password from host\n"
" --copy-root-shell Copy root shell from host\n"
" --copy Copy locale, keymap, timezone, root password\n" " --copy Copy locale, keymap, timezone, root password\n"
" --setup-machine-id Generate a new random machine ID\n" " --setup-machine-id Generate a new random machine ID\n"
" --force Overwrite existing files\n" " --force Overwrite existing files\n"

View File

@ -291,7 +291,7 @@ static void test_rs(void) {
assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0); assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
time_now + 2 *USEC_PER_SEC, 0, time_now + 30 * USEC_PER_SEC, 0,
test_rs_hangcheck, NULL) >= 0); test_rs_hangcheck, NULL) >= 0);
assert_se(sd_ndisc_stop(nd) >= 0); assert_se(sd_ndisc_stop(nd) >= 0);
@ -393,7 +393,7 @@ static void test_timeout(void) {
assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
time_now + 2U * USEC_PER_SEC, 0, time_now + 30 * USEC_PER_SEC, 0,
test_rs_hangcheck, NULL) >= 0); test_rs_hangcheck, NULL) >= 0);
assert_se(sd_ndisc_start(nd) >= 0); assert_se(sd_ndisc_start(nd) >= 0);

View File

@ -125,6 +125,17 @@ void address_free(Address *address) {
if (address->link && !address->acd) { if (address->link && !address->acd) {
set_remove(address->link->addresses, address); set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address); set_remove(address->link->addresses_foreign, address);
set_remove(address->link->static_addresses, address);
if (address->link->dhcp_address == address)
address->link->dhcp_address = NULL;
if (address->link->dhcp_address_old == address)
address->link->dhcp_address_old = NULL;
set_remove(address->link->dhcp6_addresses, address);
set_remove(address->link->dhcp6_addresses_old, address);
set_remove(address->link->dhcp6_pd_addresses, address);
set_remove(address->link->dhcp6_pd_addresses_old, address);
set_remove(address->link->ndisc_addresses, address);
set_remove(address->link->ndisc_addresses_old, address);
if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address)) if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
@ -205,7 +216,7 @@ static int address_compare_func(const Address *a1, const Address *a2) {
} }
} }
DEFINE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func); DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
bool address_equal(Address *a1, Address *a2) { bool address_equal(Address *a1, Address *a2) {
if (a1 == a2) if (a1 == a2)
@ -344,11 +355,8 @@ int address_update(
int r; int r;
assert(address); assert(address);
assert(address->link);
assert(cinfo); assert(cinfo);
assert_return(address->link, 1);
if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
ready = address_is_ready(address); ready = address_is_ready(address);
@ -356,19 +364,28 @@ int address_update(
address->scope = scope; address->scope = scope;
address->cinfo = *cinfo; address->cinfo = *cinfo;
if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
link_update_operstate(address->link, true); link_update_operstate(address->link, true);
link_check_ready(address->link); link_check_ready(address->link);
if (!ready && if (!ready && address_is_ready(address)) {
address_is_ready(address) && if (address->callback) {
address->family == AF_INET6 && r = address->callback(address);
if (r < 0)
return r;
}
if (address->family == AF_INET6 &&
in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { IN6_IS_ADDR_UNSPECIFIED(&address->link->ipv6ll_address) > 0) {
r = link_ipv6ll_gained(address->link, &address->in_addr.in6); r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
if (r < 0) if (r < 0)
return r; return r;
} }
}
return 0; return 0;
} }
@ -586,9 +603,11 @@ int address_configure(
Address *address, Address *address,
Link *link, Link *link,
link_netlink_message_handler_t callback, link_netlink_message_handler_t callback,
bool update) { bool update,
Address **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
Address *a;
int r; int r;
assert(address); assert(address);
@ -609,6 +628,13 @@ int address_configure(
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m"); return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
if (DEBUG_LOGGING) {
_cleanup_free_ char *str = NULL;
(void) in_addr_to_string(address->family, &address->in_addr, &str);
log_link_debug(link, "%s address: %s", update ? "Updating" : "Configuring", strna(str));
}
if (update) if (update)
r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
link->ifindex, address->family); link->ifindex, address->family);
@ -690,9 +716,9 @@ int address_configure(
link_ref(link); link_ref(link);
if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer)) if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, NULL); r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, &a);
else else
r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); r = address_add(link, address->family, &address->in_addr, address->prefixlen, &a);
if (r < 0) { if (r < 0) {
address_release(address); address_release(address);
return log_link_error_errno(link, r, "Could not add address: %m"); return log_link_error_errno(link, r, "Could not add address: %m");
@ -712,6 +738,9 @@ int address_configure(
log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m"); log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
} }
if (ret)
*ret = a;
return 1; return 1;
} }

View File

@ -20,6 +20,7 @@ typedef struct Address Address;
typedef struct Network Network; typedef struct Network Network;
typedef struct Link Link; typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection; typedef struct NetworkConfigSection NetworkConfigSection;
typedef int (*address_ready_callback_t)(Address *address);
struct Address { struct Address {
Network *network; Network *network;
@ -47,6 +48,9 @@ struct Address {
bool autojoin:1; bool autojoin:1;
AddressFamily duplicate_address_detection; AddressFamily duplicate_address_detection;
/* Called when address become ready */
address_ready_callback_t callback;
sd_ipv4acd *acd; sd_ipv4acd *acd;
LIST_FIELDS(Address, addresses); LIST_FIELDS(Address, addresses);
@ -60,7 +64,7 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi
bool address_exists(Link *link, int family, const union in_addr_union *in_addr); bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo); int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo);
int address_drop(Address *address); int address_drop(Address *address);
int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update); int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback); int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
bool address_equal(Address *a1, Address *a2); bool address_equal(Address *a1, Address *a2);
bool address_is_ready(const Address *a); bool address_is_ready(const Address *a);

View File

@ -20,38 +20,58 @@
#include "sysctl-util.h" #include "sysctl-util.h"
#include "web-util.h" #include "web-util.h"
static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback);
static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback);
static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback);
static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, link_netlink_message_handler_t callback);
static int dhcp4_update_address(Link *link, bool announce); static int dhcp4_update_address(Link *link, bool announce);
static int dhcp4_remove_all(Link *link); static int dhcp4_remove_all(Link *link);
static int dhcp4_release_old_lease(Link *link, bool force);
static void dhcp4_release_old_lease(Link *link) { static int dhcp4_address_callback(Address *address) {
struct in_addr address = {}, address_old = {}; assert(address);
assert(address->link);
/* Do not call this callback again. */
address->callback = NULL;
return dhcp4_release_old_lease(address->link, true);
}
static int dhcp4_release_old_lease(Link *link, bool force) {
Route *route;
Iterator i;
int k, r = 0;
assert(link); assert(link);
if (!link->dhcp_lease_old) if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
return; return 0;
assert(link->dhcp_lease); if (!force && (link->dhcp_address && !address_is_ready(link->dhcp_address))) {
log_link_debug(link, "New DHCPv4 address is not ready. The old lease will be removed later.");
link->dhcp_address->callback = dhcp4_address_callback;
return 0;
}
(void) sd_dhcp_lease_get_address(link->dhcp_lease_old, &address_old); log_link_debug(link, "Removing old DHCPv4 address and routes.");
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
(void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false, NULL);
(void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false, NULL);
(void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false, NULL);
if (!in4_addr_equal(&address_old, &address))
(void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old, NULL);
link->dhcp_lease_old = sd_dhcp_lease_unref(link->dhcp_lease_old);
link_dirty(link); link_dirty(link);
SET_FOREACH(route, link->dhcp_routes_old, i) {
k = route_remove(route, link, NULL);
if (k < 0)
r = k;
}
if (link->dhcp_address_old) {
k = address_remove(link->dhcp_address_old, link, NULL);
if (k < 0)
r = k;
}
return r;
} }
static void dhcp4_check_ready(Link *link) { static void dhcp4_check_ready(Link *link) {
int r;
if (link->network->dhcp_send_decline && !link->dhcp4_address_bind) if (link->network->dhcp_send_decline && !link->dhcp4_address_bind)
return; return;
@ -59,8 +79,14 @@ static void dhcp4_check_ready(Link *link) {
return; return;
link->dhcp4_configured = true; link->dhcp4_configured = true;
/* New address and routes are configured now. Let's release old lease. */ /* New address and routes are configured now. Let's release old lease. */
dhcp4_release_old_lease(link); r = dhcp4_release_old_lease(link, false);
if (r < 0) {
link_enter_failed(link);
return;
}
link_check_ready(link); link_check_ready(link);
} }
@ -124,27 +150,25 @@ static bool link_prefixroute(Link *link) {
link->manager->dhcp4_prefix_root_cannot_set_table; link->manager->dhcp4_prefix_root_cannot_set_table;
} }
static int dhcp_route_configure(Route **route, Link *link) { static int dhcp_route_configure(Route *route, Link *link) {
Route *ret;
int r; int r;
assert(route); assert(route);
assert(*route);
assert(link); assert(link);
if (set_contains(link->dhcp_routes, *route)) r = route_configure(route, link, dhcp4_route_handler, &ret);
return 0; if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv4 route: %m");
r = route_configure(*route, link, dhcp4_route_handler);
if (r <= 0)
return r;
link->dhcp4_messages++; link->dhcp4_messages++;
r = set_put(link->dhcp_routes, *route); r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, ret);
if (r < 0) if (r < 0)
return r; return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
(void) set_remove(link->dhcp_routes_old, ret);
TAKE_PTR(*route);
return 0; return 0;
} }
@ -187,7 +211,7 @@ static int link_set_dns_routes(Link *link, const struct in_addr *address) {
route->priority = link->network->dhcp_route_metric; route->priority = link->network->dhcp_route_metric;
route->table = table; route->table = table;
r = dhcp_route_configure(&route, link); r = dhcp_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set route to DNS server: %m"); return log_link_error_errno(link, r, "Could not set route to DNS server: %m");
} }
@ -231,6 +255,7 @@ static int link_set_dhcp_routes(Link *link) {
struct in_addr address; struct in_addr address;
int r, n, i; int r, n, i;
uint32_t table; uint32_t table;
Route *rt;
assert(link); assert(link);
@ -245,12 +270,11 @@ static int link_set_dhcp_routes(Link *link) {
* the addresses now, let's not configure the routes either. */ * the addresses now, let's not configure the routes either. */
return 0; return 0;
r = set_ensure_allocated(&link->dhcp_routes, &route_hash_ops); while ((rt = set_steal_first(link->dhcp_routes))) {
r = set_ensure_put(&link->dhcp_routes_old, &route_hash_ops, rt);
if (r < 0) if (r < 0)
return log_oom(); return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
}
/* Clear old entries in case the set was already allocated */
set_clear(link->dhcp_routes);
table = link_get_dhcp_route_table(link); table = link_get_dhcp_route_table(link);
@ -265,7 +289,7 @@ static int link_set_dhcp_routes(Link *link) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not create prefix route: %m"); return log_link_error_errno(link, r, "Could not create prefix route: %m");
r = dhcp_route_configure(&prefix_route, link); r = dhcp_route_configure(prefix_route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set prefix route: %m"); return log_link_error_errno(link, r, "Could not set prefix route: %m");
} }
@ -316,7 +340,7 @@ static int link_set_dhcp_routes(Link *link) {
if (set_contains(link->dhcp_routes, route)) if (set_contains(link->dhcp_routes, route))
continue; continue;
r = dhcp_route_configure(&route, link); r = dhcp_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set route: %m"); return log_link_error_errno(link, r, "Could not set route: %m");
} }
@ -356,7 +380,7 @@ static int link_set_dhcp_routes(Link *link) {
route_gw->table = table; route_gw->table = table;
route_gw->mtu = link->network->dhcp_route_mtu; route_gw->mtu = link->network->dhcp_route_mtu;
r = dhcp_route_configure(&route_gw, link); r = dhcp_route_configure(route_gw, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set host route: %m"); return log_link_error_errno(link, r, "Could not set host route: %m");
@ -372,12 +396,11 @@ static int link_set_dhcp_routes(Link *link) {
route->table = table; route->table = table;
route->mtu = link->network->dhcp_route_mtu; route->mtu = link->network->dhcp_route_mtu;
r = dhcp_route_configure(&route, link); r = dhcp_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set router: %m"); return log_link_error_errno(link, r, "Could not set router: %m");
} }
Route *rt;
LIST_FOREACH(routes, rt, link->network->static_routes) { LIST_FOREACH(routes, rt, link->network->static_routes) {
if (!rt->gateway_from_dhcp) if (!rt->gateway_from_dhcp)
continue; continue;
@ -387,272 +410,15 @@ static int link_set_dhcp_routes(Link *link) {
rt->gw.in = router[0]; rt->gw.in = router[0];
r = route_configure(rt, link, dhcp4_route_handler); r = dhcp_route_configure(rt, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m"); return log_link_error_errno(link, r, "Could not set gateway: %m");
if (r > 0)
link->dhcp4_messages++;
} }
} }
return link_set_dns_routes(link, &address); return link_set_dns_routes(link, &address);
} }
static int dhcp_route_remove(Route *route, Link *link, link_netlink_message_handler_t callback) {
int r;
r = route_remove(route, link, callback);
if (r < 0)
return r;
if (callback)
link->dhcp4_remove_messages++;
return 0;
}
static int dhcp_remove_routes(
Link *link,
sd_dhcp_lease *lease,
const struct in_addr *address,
bool remove_all,
link_netlink_message_handler_t callback) {
_cleanup_free_ sd_dhcp_route **routes = NULL;
uint32_t table;
int n, i, r;
assert(link);
assert(address);
if (!link->network->dhcp_use_routes)
return 0;
n = sd_dhcp_lease_get_routes(lease, &routes);
if (IN_SET(n, 0, -ENODATA))
return 0;
else if (n < 0)
return log_link_error_errno(link, n, "DHCP error: Failed to get routes: %m");
table = link_get_dhcp_route_table(link);
for (i = 0; i < n; i++) {
_cleanup_(route_freep) Route *route = NULL;
r = route_new(&route);
if (r < 0)
return log_oom();
route->family = AF_INET;
assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
route->priority = link->network->dhcp_route_metric;
route->table = table;
route->scope = route_scope_from_address(route, address);
if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
route->prefsrc.in = *address;
if (!remove_all && set_contains(link->dhcp_routes, route))
continue;
r = dhcp_route_remove(route, link, callback);
if (r < 0)
return r;
}
return n;
}
static int dhcp_remove_router(
Link *link,
sd_dhcp_lease *lease,
const struct in_addr *address,
bool remove_all,
link_netlink_message_handler_t callback) {
_cleanup_(route_freep) Route *route_gw = NULL, *route = NULL;
const struct in_addr *router;
uint32_t table;
int r;
assert(link);
assert(address);
if (!link->network->dhcp_use_gateway)
return 0;
r = sd_dhcp_lease_get_router(lease, &router);
if (IN_SET(r, 0, -ENODATA)) {
log_link_debug(link, "DHCP: No gateway received from DHCP server.");
return 0;
} else if (r < 0)
return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
else if (in4_addr_is_null(&router[0])) {
log_link_info(link, "DHCP: Received gateway is null, ignoring.");
return 0;
}
table = link_get_dhcp_route_table(link);
r = route_new(&route_gw);
if (r < 0)
return log_oom();
route_gw->family = AF_INET;
route_gw->dst.in = router[0];
route_gw->dst_prefixlen = 32;
route_gw->prefsrc.in = *address;
route_gw->scope = RT_SCOPE_LINK;
route_gw->protocol = RTPROT_DHCP;
route_gw->priority = link->network->dhcp_route_metric;
route_gw->table = table;
if (remove_all || !set_contains(link->dhcp_routes, route_gw)) {
r = dhcp_route_remove(route_gw, link, callback);
if (r < 0)
return r;
}
r = route_new(&route);
if (r < 0)
return log_oom();
route->family = AF_INET;
route->gw.in = router[0];
route->prefsrc.in = *address;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = table;
if (remove_all || !set_contains(link->dhcp_routes, route)) {
r = dhcp_route_remove(route, link, callback);
if (r < 0)
return r;
}
Route *rt;
LIST_FOREACH(routes, rt, link->network->static_routes) {
if (!rt->gateway_from_dhcp)
continue;
if (rt->family != AF_INET)
continue;
if (!remove_all && in4_addr_equal(router, &rt->gw.in))
continue;
r = dhcp_route_remove(rt, link, callback);
if (r < 0)
return r;
}
return 0;
}
static int dhcp_remove_dns_routes(
Link *link,
sd_dhcp_lease *lease,
const struct in_addr *address,
bool remove_all,
link_netlink_message_handler_t callback) {
const struct in_addr *dns;
uint32_t table;
int i, n, r;
assert(link);
assert(lease);
assert(link->network);
if (!link->network->dhcp_use_dns ||
!link->network->dhcp_routes_to_dns)
return 0;
n = sd_dhcp_lease_get_dns(lease, &dns);
if (IN_SET(n, 0, -ENODATA))
return 0;
if (n < 0)
return log_link_warning_errno(link, n, "DHCP error: could not get DNS servers: %m");
table = link_get_dhcp_route_table(link);
for (i = 0; i < n; i ++) {
_cleanup_(route_freep) Route *route = NULL;
r = route_new(&route);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
route->family = AF_INET;
route->dst.in = dns[i];
route->dst_prefixlen = 32;
route->prefsrc.in = *address;
route->scope = RT_SCOPE_LINK;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = table;
if (!remove_all && set_contains(link->dhcp_routes, route))
continue;
r = dhcp_route_remove(route, link, callback);
if (r < 0)
return r;
}
if (!link_prefixroute(link)) {
_cleanup_(route_freep) Route *prefix_route = NULL;
r = dhcp_prefix_route_from_lease(lease, table, address, &prefix_route);
if (r < 0)
return log_link_warning_errno(link, r, "Could not create prefix route: %m");
if (remove_all || !set_contains(link->dhcp_routes, prefix_route)) {
r = dhcp_route_remove(prefix_route, link, callback);
if (r < 0)
return r;
}
}
return 0;
}
static int dhcp_remove_address(
Link *link, sd_dhcp_lease *lease,
const struct in_addr *address,
link_netlink_message_handler_t callback) {
_cleanup_(address_freep) Address *a = NULL;
struct in_addr netmask;
int r;
assert(link);
assert(address);
if (in4_addr_is_null(address))
return 0;
r = address_new(&a);
if (r < 0)
return log_oom();
a->family = AF_INET;
a->in_addr.in = *address;
if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0)
a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
r = address_remove(a, link, callback);
if (r < 0)
return r;
if (callback)
link->dhcp4_remove_messages++;
return 0;
}
static int dhcp_reset_mtu(Link *link) { static int dhcp_reset_mtu(Link *link) {
uint16_t mtu; uint16_t mtu;
int r; int r;
@ -756,37 +522,33 @@ static int dhcp4_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
} }
static int dhcp4_remove_all(Link *link) { static int dhcp4_remove_all(Link *link) {
struct in_addr address; Route *route;
int r; Iterator i;
int k, r = 0;
assert(link); assert(link);
assert(link->dhcp_lease);
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); SET_FOREACH(route, link->dhcp_routes, i) {
if (r < 0) k = route_remove(route, link, dhcp4_remove_route_handler);
return log_link_error_errno(link, r, "Failed to get DHCPv4 address: %m"); if (k < 0)
r = k;
else
link->dhcp4_remove_messages++;
}
if (link->dhcp_address) {
k = address_remove(link->dhcp_address, link, dhcp4_remove_address_handler);
if (k < 0)
r = k;
else
link->dhcp4_remove_messages++;
}
r = dhcp_remove_routes(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler);
if (r < 0)
return r; return r;
r = dhcp_remove_router(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler);
if (r < 0)
return r;
r = dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler);
if (r < 0)
return r;
r = dhcp_remove_address(link, link->dhcp_lease, &address, dhcp4_remove_address_handler);
if (r < 0)
return r;
return 0;
} }
static int dhcp_lease_lost(Link *link) { static int dhcp_lease_lost(Link *link) {
int r; int k, r;
assert(link); assert(link);
assert(link->dhcp_lease); assert(link->dhcp_lease);
@ -796,24 +558,26 @@ static int dhcp_lease_lost(Link *link) {
link->dhcp4_configured = false; link->dhcp4_configured = false;
/* dhcp_lease_lost() may be called during renewing IP address. */ /* dhcp_lease_lost() may be called during renewing IP address. */
dhcp4_release_old_lease(link); k = dhcp4_release_old_lease(link, true);
if (k < 0)
r = k;
r = dhcp4_remove_all(link); k = dhcp4_remove_all(link);
if (r < 0) if (k < 0)
return r; r = k;
r = dhcp_reset_mtu(link); k = dhcp_reset_mtu(link);
if (r < 0) if (k < 0)
return r; r = k;
r = dhcp_reset_hostname(link); k = dhcp_reset_hostname(link);
if (r < 0) if (k < 0)
return r; r = k;
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link); link_dirty(link);
return 0; return r;
} }
static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) { static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
@ -975,6 +739,7 @@ static int dhcp4_update_address(Link *link, bool announce) {
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
struct in_addr address, netmask; struct in_addr address, netmask;
unsigned prefixlen; unsigned prefixlen;
Address *ret;
int r; int r;
assert(link); assert(link);
@ -1049,9 +814,13 @@ static int dhcp4_update_address(Link *link, bool announce) {
/* allow reusing an existing address and simply update its lifetime /* allow reusing an existing address and simply update its lifetime
* in case it already exists */ * in case it already exists */
r = address_configure(addr, link, dhcp4_address_handler, true); r = address_configure(addr, link, dhcp4_address_handler, true, &ret);
if (r < 0) if (r < 0)
return r; return log_link_error_errno(link, r, "Failed to set DHCPv4 address: %m");
if (!address_equal(link->dhcp_address, ret))
link->dhcp_address_old = link->dhcp_address;
link->dhcp_address = ret;
return 0; return 0;
} }
@ -1151,32 +920,11 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) { static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
int r; int r;
link->dhcp_lease_old = TAKE_PTR(link->dhcp_lease);
/* On IP address change, to keep the connectability, we would like to assign new address and
* routes, and then release old lease. There are two possible success paths:
*
* 1. new address and routes are configured.
* -> handled by dhcp_release_old_lease() in dhcp4_route_handler().
* 2. new address is configured and no route is requested.
* -> handled by dhcp_release_old_lease() in dhcp4_address_handler().
*
* On error in assigning new address and routes, then the link always enters to the failed
* state. And link_enter_failed() leads to the DHCP client to be stopped. So,
* dhcp_release_old_lease() will be also called by link_stop_clients().
*/
r = dhcp_lease_acquired(client, link); r = dhcp_lease_acquired(client, link);
if (r < 0) { if (r < 0)
/* If it fails, then the new address is not configured yet.
* So, let's simply drop the old lease. */
sd_dhcp_lease_unref(link->dhcp_lease);
link->dhcp_lease = TAKE_PTR(link->dhcp_lease_old);
(void) dhcp_lease_lost(link); (void) dhcp_lease_lost(link);
return r;
}
return 0; return r;
} }
static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) { static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) {

File diff suppressed because it is too large Load Diff

View File

@ -17,17 +17,26 @@ typedef enum DHCP6ClientStartMode {
typedef struct Link Link; typedef struct Link Link;
typedef struct Manager Manager; typedef struct Manager Manager;
bool dhcp6_get_prefix_delegation(Link *link); typedef struct DHCP6DelegatedPrefix {
int dhcp6_request_prefix_delegation(Link *link); struct in6_addr prefix; /* Prefix assigned to the link */
struct in6_addr pd_prefix; /* PD prefix provided by DHCP6 lease */
Link *link;
} DHCP6DelegatedPrefix;
DHCP6DelegatedPrefix *dhcp6_pd_free(DHCP6DelegatedPrefix *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
bool link_dhcp6_pd_is_enabled(Link *link);
int dhcp6_pd_remove(Link *link);
int dhcp6_configure(Link *link); int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link, int ir); int dhcp6_request_address(Link *link, int ir);
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link); int dhcp6_request_prefix_delegation(Link *link);
int dhcp6_prefix_remove(Manager *m, struct in6_addr *addr);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_delegated_prefix_token);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_subnet_id);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_token);
const char* dhcp6_client_start_mode_to_string(DHCP6ClientStartMode i) _const_; const char* dhcp6_client_start_mode_to_string(DHCP6ClientStartMode i) _const_;
DHCP6ClientStartMode dhcp6_client_start_mode_from_string(const char *s) _pure_; DHCP6ClientStartMode dhcp6_client_start_mode_from_string(const char *s) _pure_;

View File

@ -17,7 +17,7 @@ static int ipv4ll_address_lost(Link *link) {
assert(link); assert(link);
link->ipv4ll_address = false; link->ipv4ll_address_configured = false;
r = sd_ipv4ll_get_address(link->ipv4ll, &addr); r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
if (r < 0) if (r < 0)
@ -47,7 +47,7 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
int r; int r;
assert(link); assert(link);
assert(!link->ipv4ll_address); assert(!link->ipv4ll_address_configured);
r = sd_netlink_message_get_errno(m); r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) { if (r < 0 && r != -EEXIST) {
@ -57,7 +57,7 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
} else if (r >= 0) } else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager); (void) manager_rtnl_process_address(rtnl, m, link->manager);
link->ipv4ll_address = true; link->ipv4ll_address_configured = true;
link_check_ready(link); link_check_ready(link);
return 1; return 1;
@ -71,7 +71,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
assert(ll); assert(ll);
assert(link); assert(link);
link->ipv4ll_address = false; link->ipv4ll_address_configured = false;
r = sd_ipv4ll_get_address(ll, &address); r = sd_ipv4ll_get_address(ll, &address);
if (r == -ENOENT) if (r == -ENOENT)
@ -92,7 +92,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen); ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
ll_addr->scope = RT_SCOPE_LINK; ll_addr->scope = RT_SCOPE_LINK;
r = address_configure(ll_addr, link, ipv4ll_address_handler, false); r = address_configure(ll_addr, link, ipv4ll_address_handler, false, NULL);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -691,7 +691,6 @@ static void link_free_engines(Link *link) {
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server); link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client); link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link->dhcp_routes = set_free(link->dhcp_routes);
link->lldp = sd_lldp_unref(link->lldp); link->lldp = sd_lldp_unref(link->lldp);
@ -699,6 +698,7 @@ static void link_free_engines(Link *link) {
link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll); link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll);
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
link->ndisc = sd_ndisc_unref(link->ndisc); link->ndisc = sd_ndisc_unref(link->ndisc);
link->radv = sd_radv_unref(link->radv); link->radv = sd_radv_unref(link->radv);
} }
@ -711,17 +711,32 @@ static Link *link_free(Link *link) {
link_ntp_settings_clear(link); link_ntp_settings_clear(link);
link_dns_settings_clear(link); link_dns_settings_clear(link);
link->routes = set_free_with_destructor(link->routes, route_free); link->routes = set_free(link->routes);
link->routes_foreign = set_free_with_destructor(link->routes_foreign, route_free); link->routes_foreign = set_free(link->routes_foreign);
link->dhcp_routes = set_free(link->dhcp_routes);
link->dhcp_routes_old = set_free(link->dhcp_routes_old);
link->dhcp6_routes = set_free(link->dhcp6_routes);
link->dhcp6_routes_old = set_free(link->dhcp6_routes_old);
link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes);
link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old);
link->ndisc_routes = set_free(link->ndisc_routes);
link->ndisc_routes_old = set_free(link->ndisc_routes_old);
link->nexthops = set_free_with_destructor(link->nexthops, nexthop_free); link->nexthops = set_free(link->nexthops);
link->nexthops_foreign = set_free_with_destructor(link->nexthops_foreign, nexthop_free); link->nexthops_foreign = set_free(link->nexthops_foreign);
link->neighbors = set_free_with_destructor(link->neighbors, neighbor_free); link->neighbors = set_free(link->neighbors);
link->neighbors_foreign = set_free_with_destructor(link->neighbors_foreign, neighbor_free); link->neighbors_foreign = set_free(link->neighbors_foreign);
link->addresses = set_free_with_destructor(link->addresses, address_free); link->addresses = set_free(link->addresses);
link->addresses_foreign = set_free_with_destructor(link->addresses_foreign, address_free); link->addresses_foreign = set_free(link->addresses_foreign);
link->static_addresses = set_free(link->static_addresses);
link->dhcp6_addresses = set_free(link->dhcp6_addresses);
link->dhcp6_addresses_old = set_free(link->dhcp6_addresses_old);
link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses);
link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
link->ndisc_addresses = set_free(link->ndisc_addresses);
link->ndisc_addresses_old = set_free(link->ndisc_addresses_old);
while ((address = link->pool_addresses)) { while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address); LIST_REMOVE(addresses, link->pool_addresses, address);
@ -834,6 +849,12 @@ int link_stop_clients(Link *link, bool may_keep_dhcp) {
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m"); r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
} }
if (link_dhcp6_pd_is_enabled(link)) {
k = dhcp6_pd_remove(link);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
}
if (link->ndisc) { if (link->ndisc) {
k = sd_ndisc_stop(link->ndisc); k = sd_ndisc_stop(link->ndisc);
if (k < 0) if (k < 0)
@ -1037,12 +1058,13 @@ int link_request_set_routes(Link *link) {
assert(link); assert(link);
assert(link->network); assert(link->network);
assert(link->addresses_configured);
assert(link->address_messages == 0);
assert(link->state != _LINK_STATE_INVALID); assert(link->state != _LINK_STATE_INVALID);
link->static_routes_configured = false; link->static_routes_configured = false;
if (!link->addresses_ready)
return 0;
if (!link_has_carrier(link) && !link->network->configure_without_carrier) if (!link_has_carrier(link) && !link->network->configure_without_carrier)
/* During configuring addresses, the link lost its carrier. As networkd is dropping /* During configuring addresses, the link lost its carrier. As networkd is dropping
* the addresses now, let's not configure the routes either. */ * the addresses now, let's not configure the routes either. */
@ -1061,7 +1083,7 @@ int link_request_set_routes(Link *link) {
if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY)) if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
continue; continue;
r = route_configure(rt, link, route_handler); r = route_configure(rt, link, route_handler, NULL);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Could not set routes: %m"); return log_link_warning_errno(link, r, "Could not set routes: %m");
if (r > 0) if (r > 0)
@ -1082,12 +1104,14 @@ int link_request_set_routes(Link *link) {
void link_check_ready(Link *link) { void link_check_ready(Link *link) {
Address *a; Address *a;
Iterator i; Iterator i;
int r;
assert(link); assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) { if (link->state == LINK_STATE_CONFIGURED)
log_link_debug(link, "%s(): link is in failed or linger state.", __func__); return;
if (link->state != LINK_STATE_CONFIGURING) {
log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
return; return;
} }
@ -1113,15 +1137,6 @@ void link_check_ready(Link *link) {
return; return;
} }
if (!link->addresses_ready) {
link->addresses_ready = true;
r = link_request_set_routes(link);
if (r < 0)
link_enter_failed(link);
log_link_debug(link, "%s(): static addresses are configured. Configuring static routes.", __func__);
return;
}
if (!link->static_routes_configured) { if (!link->static_routes_configured) {
log_link_debug(link, "%s(): static routes are not configured.", __func__); log_link_debug(link, "%s(): static routes are not configured.", __func__);
return; return;
@ -1149,7 +1164,7 @@ void link_check_ready(Link *link) {
if (link_has_carrier(link) || !link->network->configure_without_carrier) { if (link_has_carrier(link) || !link->network->configure_without_carrier) {
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address) { if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__); log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
return; return;
} }
@ -1160,17 +1175,19 @@ void link_check_ready(Link *link) {
return; return;
} }
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && set_isempty(link->addresses)) { if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no address is assigned yet.", __func__); !link->dhcp_address && set_isempty(link->dhcp6_addresses) && set_isempty(link->ndisc_addresses) &&
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
return; return;
} }
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || dhcp6_get_prefix_delegation(link) || link_ipv6_accept_ra_enabled(link)) { if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || link_ipv6_accept_ra_enabled(link)) {
if (!link->dhcp4_configured && if (!link->dhcp4_configured &&
!(link->dhcp6_address_configured && link->dhcp6_route_configured) && !(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) && !(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) && !(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address)) { !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
/* When DHCP or RA is enabled, at least one protocol must provide an address, or /* When DHCP or RA is enabled, at least one protocol must provide an address, or
* an IPv4ll fallback address must be configured. */ * an IPv4ll fallback address must be configured. */
log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__); log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
@ -1189,7 +1206,6 @@ void link_check_ready(Link *link) {
} }
} }
if (link->state != LINK_STATE_CONFIGURED)
link_enter_configured(link); link_enter_configured(link);
return; return;
@ -1222,6 +1238,50 @@ static int link_request_set_neighbors(Link *link) {
return 0; return 0;
} }
static int link_set_bridge_fdb(Link *link) {
FdbEntry *fdb_entry;
int r;
LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
r = fdb_entry_configure(link, fdb_entry);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
}
return 0;
}
static int static_address_ready_callback(Address *address) {
Address *a;
Iterator i;
Link *link;
assert(address);
assert(address->link);
link = address->link;
if (!link->addresses_configured)
return 0;
SET_FOREACH(a, link->static_addresses, i)
if (!address_is_ready(a)) {
_cleanup_free_ char *str = NULL;
(void) in_addr_to_string(a->family, &a->in_addr, &str);
log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen);
return 0;
}
/* This should not be called again */
SET_FOREACH(a, link->static_addresses, i)
a->callback = NULL;
link->addresses_ready = true;
return link_request_set_routes(link);
}
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -1247,23 +1307,50 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
(void) manager_rtnl_process_address(rtnl, m, link->manager); (void) manager_rtnl_process_address(rtnl, m, link->manager);
if (link->address_messages == 0) { if (link->address_messages == 0) {
Address *a;
log_link_debug(link, "Addresses set"); log_link_debug(link, "Addresses set");
link->addresses_configured = true; link->addresses_configured = true;
link_check_ready(link);
/* When all static addresses are already ready, then static_address_ready_callback()
* will not be called automatically. So, call it here. */
a = set_first(link->static_addresses);
if (!a) {
log_link_warning(link, "No static address is stored.");
link_enter_failed(link);
return 1;
}
if (!a->callback) {
log_link_warning(link, "Address ready callback is not set.");
link_enter_failed(link);
return 1;
}
r = a->callback(a);
if (r < 0)
link_enter_failed(link);
} }
return 1; return 1;
} }
static int link_set_bridge_fdb(Link *link) { static int static_address_configure(Address *address, Link *link, bool update) {
FdbEntry *fdb_entry; Address *ret;
int r; int r;
LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) { assert(address);
r = fdb_entry_configure(link, fdb_entry); assert(link);
r = address_configure(address, link, address_handler, update, &ret);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m"); return log_link_warning_errno(link, r, "Could not configure static address: %m");
}
link->address_messages++;
r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store static address: %m");
ret->callback = static_address_ready_callback;
return 0; return 0;
} }
@ -1302,16 +1389,12 @@ static int link_request_set_addresses(Link *link) {
else else
update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0; update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
r = address_configure(ad, link, address_handler, update); r = static_address_configure(ad, link, update);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Could not set addresses: %m"); return r;
if (r > 0)
link->address_messages++;
} }
if (IN_SET(link->network->router_prefix_delegation, if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC)
RADV_PREFIX_DELEGATION_STATIC,
RADV_PREFIX_DELEGATION_BOTH))
LIST_FOREACH(prefixes, p, link->network->static_prefixes) { LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
_cleanup_(address_freep) Address *address = NULL; _cleanup_(address_freep) Address *address = NULL;
@ -1320,22 +1403,20 @@ static int link_request_set_addresses(Link *link) {
r = address_new(&address); r = address_new(&address);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not allocate address: %m"); return log_oom();
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen); r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
if (r < 0) if (r < 0)
return r; return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6); r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0) if (r < 0)
return r; return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
address->family = AF_INET6; address->family = AF_INET6;
r = address_configure(address, link, address_handler, true); r = static_address_configure(address, link, true);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Could not set addresses: %m"); return r;
if (r > 0)
link->address_messages++;
} }
LIST_FOREACH(labels, label, link->network->address_labels) { LIST_FOREACH(labels, label, link->network->address_labels) {
@ -1346,8 +1427,7 @@ static int link_request_set_addresses(Link *link) {
link->address_label_messages++; link->address_label_messages++;
} }
/* now that we can figure out a default address for the dhcp server, /* now that we can figure out a default address for the dhcp server, start it */
start it */
if (link_dhcp4_server_enabled(link) && (link->flags & IFF_UP)) { if (link_dhcp4_server_enabled(link) && (link->flags & IFF_UP)) {
r = dhcp4_server_configure(link); r = dhcp4_server_configure(link);
if (r < 0) if (r < 0)
@ -1357,7 +1437,10 @@ static int link_request_set_addresses(Link *link) {
if (link->address_messages == 0) { if (link->address_messages == 0) {
link->addresses_configured = true; link->addresses_configured = true;
link_check_ready(link); link->addresses_ready = true;
r = link_request_set_routes(link);
if (r < 0)
return r;
} else { } else {
log_link_debug(link, "Setting addresses"); log_link_debug(link, "Setting addresses");
link_set_state(link, LINK_STATE_CONFIGURING); link_set_state(link, LINK_STATE_CONFIGURING);
@ -1617,7 +1700,9 @@ static int link_acquire_ipv6_conf(Link *link) {
log_link_debug(link, "Acquiring DHCPv6 lease"); log_link_debug(link, "Acquiring DHCPv6 lease");
} }
(void) dhcp6_request_prefix_delegation(link); r = dhcp6_request_prefix_delegation(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request DHCPv6 prefix delegation: %m");
return 0; return 0;
} }
@ -4235,7 +4320,6 @@ int link_save(Link *link) {
if (link->network) { if (link->network) {
char **dhcp6_domains = NULL, **dhcp_domains = NULL; char **dhcp6_domains = NULL, **dhcp_domains = NULL;
const char *dhcp_domainname = NULL, *p; const char *dhcp_domainname = NULL, *p;
sd_dhcp6_lease *dhcp6_lease = NULL;
bool space; bool space;
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
@ -4247,12 +4331,6 @@ int link_save(Link *link) {
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "", st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : ""); st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
if (link->dhcp6_client) {
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
if (r < 0 && r != -ENOMSG)
log_link_debug_errno(link, r, "Failed to get DHCPv6 lease: %m");
}
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename); fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
/************************************************************/ /************************************************************/
@ -4269,7 +4347,7 @@ int link_save(Link *link) {
link->dhcp_lease, link->dhcp_lease,
link->network->dhcp_use_dns, link->network->dhcp_use_dns,
SD_DHCP_LEASE_DNS, SD_DHCP_LEASE_DNS,
dhcp6_lease, link->dhcp6_lease,
link->network->dhcp6_use_dns, link->network->dhcp6_use_dns,
sd_dhcp6_lease_get_dns, sd_dhcp6_lease_get_dns,
NULL); NULL);
@ -4293,7 +4371,7 @@ int link_save(Link *link) {
link->dhcp_lease, link->dhcp_lease,
link->network->dhcp_use_ntp, link->network->dhcp_use_ntp,
SD_DHCP_LEASE_NTP, SD_DHCP_LEASE_NTP,
dhcp6_lease, link->dhcp6_lease,
link->network->dhcp6_use_ntp, link->network->dhcp6_use_ntp,
sd_dhcp6_lease_get_ntp_addrs, sd_dhcp6_lease_get_ntp_addrs,
sd_dhcp6_lease_get_ntp_fqdn); sd_dhcp6_lease_get_ntp_fqdn);
@ -4312,8 +4390,8 @@ int link_save(Link *link) {
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname); (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains); (void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
} }
if (dhcp6_lease) if (link->dhcp6_lease)
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains); (void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
} }
fputs("DOMAINS=", f); fputs("DOMAINS=", f);

View File

@ -87,6 +87,7 @@ typedef struct Link {
Set *addresses; Set *addresses;
Set *addresses_foreign; Set *addresses_foreign;
Set *static_addresses;
Set *neighbors; Set *neighbors;
Set *neighbors_foreign; Set *neighbors_foreign;
Set *routes; Set *routes;
@ -95,32 +96,20 @@ typedef struct Link {
Set *nexthops_foreign; Set *nexthops_foreign;
sd_dhcp_client *dhcp_client; sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease, *dhcp_lease_old; sd_dhcp_lease *dhcp_lease;
Set *dhcp_routes; Address *dhcp_address, *dhcp_address_old;
Set *dhcp_routes, *dhcp_routes_old;
char *lease_file; char *lease_file;
uint32_t original_mtu; uint32_t original_mtu;
unsigned dhcp4_messages; unsigned dhcp4_messages;
unsigned dhcp4_remove_messages; unsigned dhcp4_remove_messages;
unsigned dhcp6_address_messages;
unsigned dhcp6_route_messages;
unsigned dhcp6_pd_address_messages;
unsigned dhcp6_pd_route_messages;
bool dhcp4_route_failed:1; bool dhcp4_route_failed:1;
bool dhcp4_route_retrying:1; bool dhcp4_route_retrying:1;
bool dhcp4_configured:1; bool dhcp4_configured:1;
bool dhcp4_address_bind:1; bool dhcp4_address_bind:1;
bool dhcp6_address_configured:1;
bool dhcp6_route_configured:1;
bool dhcp6_pd_address_configured:1;
bool dhcp6_pd_route_configured:1;
unsigned ndisc_addresses_messages;
unsigned ndisc_routes_messages;
bool ndisc_addresses_configured:1;
bool ndisc_routes_configured:1;
sd_ipv4ll *ipv4ll; sd_ipv4ll *ipv4ll;
bool ipv4ll_address:1; bool ipv4ll_address_configured:1;
bool addresses_configured:1; bool addresses_configured:1;
bool addresses_ready:1; bool addresses_ready:1;
@ -141,10 +130,30 @@ typedef struct Link {
sd_ndisc *ndisc; sd_ndisc *ndisc;
Set *ndisc_rdnss; Set *ndisc_rdnss;
Set *ndisc_dnssl; Set *ndisc_dnssl;
Set *ndisc_addresses, *ndisc_addresses_old;
Set *ndisc_routes, *ndisc_routes_old;
unsigned ndisc_addresses_messages;
unsigned ndisc_routes_messages;
bool ndisc_addresses_configured:1;
bool ndisc_routes_configured:1;
sd_radv *radv; sd_radv *radv;
sd_dhcp6_client *dhcp6_client; sd_dhcp6_client *dhcp6_client;
sd_dhcp6_lease *dhcp6_lease;
Set *dhcp6_addresses, *dhcp6_addresses_old;
Set *dhcp6_routes, *dhcp6_routes_old;
Set *dhcp6_pd_addresses, *dhcp6_pd_addresses_old;
Set *dhcp6_pd_routes, *dhcp6_pd_routes_old;
unsigned dhcp6_address_messages;
unsigned dhcp6_route_messages;
unsigned dhcp6_pd_address_messages;
unsigned dhcp6_pd_route_messages;
bool dhcp6_address_configured:1;
bool dhcp6_route_configured:1;
bool dhcp6_pd_address_configured:1;
bool dhcp6_pd_route_configured:1;
bool dhcp6_pd_prefixes_assigned:1;
/* This is about LLDP reception */ /* This is about LLDP reception */
sd_lldp *lldp; sd_lldp *lldp;

View File

@ -857,8 +857,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
valid_str ? "for " : "forever", strempty(valid_str)); valid_str ? "for " : "forever", strempty(valid_str));
} }
/* address_update() logs internally, so we don't need to. */ /* address_update() logs internally, so we don't need to here. */
(void) address_update(address, flags, scope, &cinfo); r = address_update(address, flags, scope, &cinfo);
if (r < 0)
link_enter_failed(link);
break; break;
@ -1821,27 +1823,20 @@ int manager_new(Manager **ret) {
} }
void manager_free(Manager *m) { void manager_free(Manager *m) {
struct in6_addr *a;
AddressPool *pool; AddressPool *pool;
Link *link; Link *link;
Iterator i;
if (!m) if (!m)
return; return;
free(m->state_file); free(m->state_file);
while ((a = hashmap_first_key(m->dhcp6_prefixes))) HASHMAP_FOREACH(link, m->links, i)
(void) dhcp6_prefix_remove(m, a);
m->dhcp6_prefixes = hashmap_free(m->dhcp6_prefixes);
while ((link = hashmap_steal_first(m->links))) {
if (link->dhcp6_client)
(void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);
(void) link_stop_clients(link, true); (void) link_stop_clients(link, true);
link_unref(link); m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
} m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref); m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
@ -1857,9 +1852,9 @@ void manager_free(Manager *m) {
/* routing_policy_rule_free() access m->rules and m->rules_foreign. /* routing_policy_rule_free() access m->rules and m->rules_foreign.
* So, it is necessary to set NULL after the sets are freed. */ * So, it is necessary to set NULL after the sets are freed. */
m->rules = set_free_with_destructor(m->rules, routing_policy_rule_free); m->rules = set_free(m->rules);
m->rules_foreign = set_free_with_destructor(m->rules_foreign, routing_policy_rule_free); m->rules_foreign = set_free(m->rules_foreign);
set_free_with_destructor(m->rules_saved, routing_policy_rule_free); set_free(m->rules_saved);
sd_netlink_unref(m->rtnl); sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl); sd_netlink_unref(m->genl);

View File

@ -44,6 +44,7 @@ struct Manager {
Hashmap *netdevs; Hashmap *netdevs;
OrderedHashmap *networks; OrderedHashmap *networks;
Hashmap *dhcp6_prefixes; Hashmap *dhcp6_prefixes;
Set *dhcp6_pd_prefixes;
LIST_HEAD(AddressPool, address_pools); LIST_HEAD(AddressPool, address_pools);
usec_t network_dirs_ts_usec; usec_t network_dirs_ts_usec;

View File

@ -35,6 +35,79 @@
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e) #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
static int ndisc_remove_old(Link *link, bool force);
static int ndisc_address_callback(Address *address) {
Address *a;
Iterator i;
assert(address);
assert(address->link);
/* Make this called only once */
SET_FOREACH(a, address->link->ndisc_addresses, i)
a->callback = NULL;
return ndisc_remove_old(address->link, true);
}
static int ndisc_remove_old(Link *link, bool force) {
Address *address;
Route *route;
NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss;
Iterator i;
int k, r = 0;
assert(link);
if (!force) {
bool set_callback = !set_isempty(link->ndisc_addresses);
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
return 0;
SET_FOREACH(address, link->ndisc_addresses, i)
if (address_is_ready(address)) {
set_callback = false;
break;
}
if (set_callback) {
SET_FOREACH(address, link->ndisc_addresses, i)
address->callback = ndisc_address_callback;
return 0;
}
}
if (!set_isempty(link->ndisc_addresses_old) || !set_isempty(link->ndisc_routes_old))
log_link_debug(link, "Removing old NDisc addresses and routes.");
link_dirty(link);
SET_FOREACH(address, link->ndisc_addresses_old, i) {
k = address_remove(address, link, NULL);
if (k < 0)
r = k;
}
SET_FOREACH(route, link->ndisc_routes_old, i) {
k = route_remove(route, link, NULL);
if (k < 0)
r = k;
}
SET_FOREACH(rdnss, link->ndisc_rdnss, i)
if (rdnss->marked)
free(set_remove(link->ndisc_rdnss, rdnss));
SET_FOREACH(dnssl, link->ndisc_dnssl, i)
if (dnssl->marked)
free(set_remove(link->ndisc_dnssl, dnssl));
return r;
}
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -56,6 +129,13 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
if (link->ndisc_routes_messages == 0) { if (link->ndisc_routes_messages == 0) {
log_link_debug(link, "NDisc routes set."); log_link_debug(link, "NDisc routes set.");
link->ndisc_routes_configured = true; link->ndisc_routes_configured = true;
r = ndisc_remove_old(link, false);
if (r < 0) {
link_enter_failed(link);
return 1;
}
link_check_ready(link); link_check_ready(link);
} }
@ -84,6 +164,13 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
if (link->ndisc_addresses_messages == 0) { if (link->ndisc_addresses_messages == 0) {
log_link_debug(link, "NDisc SLAAC addresses set."); log_link_debug(link, "NDisc SLAAC addresses set.");
link->ndisc_addresses_configured = true; link->ndisc_addresses_configured = true;
r = ndisc_remove_old(link, false);
if (r < 0) {
link_enter_failed(link);
return 1;
}
r = link_request_set_routes(link); r = link_request_set_routes(link);
if (r < 0) { if (r < 0) {
link_enter_failed(link); link_enter_failed(link);
@ -94,6 +181,50 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1; return 1;
} }
static int ndisc_route_configure(Route *route, Link *link) {
Route *ret;
int r;
assert(route);
assert(link);
r = route_configure(route, link, ndisc_route_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
link->ndisc_routes_messages++;
r = set_ensure_put(&link->ndisc_routes, &route_hash_ops, ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc route: %m");
(void) set_remove(link->ndisc_routes_old, ret);
return 0;
}
static int ndisc_address_configure(Address *address, Link *link) {
Address *ret;
int r;
assert(address);
assert(link);
r = address_configure(address, link, ndisc_address_handler, true, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m");
link->ndisc_addresses_messages++;
r = set_ensure_put(&link->ndisc_addresses, &address_hash_ops, ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
(void) set_remove(link->ndisc_addresses_old, ret);
return 0;
}
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = NULL; _cleanup_(route_freep) Route *route = NULL;
union in_addr_union gateway; union in_addr_union gateway;
@ -155,11 +286,9 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route->lifetime = time_now + lifetime * USEC_PER_SEC; route->lifetime = time_now + lifetime * USEC_PER_SEC;
route->mtu = mtu; route->mtu = mtu;
r = route_configure(route, link, ndisc_route_handler); r = ndisc_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set default route: %m"); return log_link_error_errno(link, r, "Could not set default route: %m");
if (r > 0)
link->ndisc_routes_messages++;
Route *route_gw; Route *route_gw;
LIST_FOREACH(routes, route_gw, link->network->static_routes) { LIST_FOREACH(routes, route_gw, link->network->static_routes) {
@ -171,11 +300,9 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route_gw->gw = gateway; route_gw->gw = gateway;
r = route_configure(route_gw, link, ndisc_route_handler); r = ndisc_route_configure(route_gw, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m"); return log_link_error_errno(link, r, "Could not set gateway: %m");
if (r > 0)
link->ndisc_routes_messages++;
} }
return 0; return 0;
@ -387,11 +514,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
address->in_addr.in6 = *a; address->in_addr.in6 = *a;
r = address_configure(address, link, ndisc_address_handler, true); r = ndisc_address_configure(address, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set SLAAC address: %m"); return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
if (r > 0)
link->ndisc_addresses_messages++;
} }
return 0; return 0;
@ -435,11 +560,9 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix address: %m"); return log_link_error_errno(link, r, "Failed to get prefix address: %m");
r = route_configure(route, link, ndisc_route_handler); r = ndisc_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set prefix route: %m");; return log_link_error_errno(link, r, "Could not set prefix route: %m");;
if (r > 0)
link->ndisc_routes_messages++;
return 0; return 0;
} }
@ -494,11 +617,9 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get route address: %m"); return log_link_error_errno(link, r, "Failed to get route address: %m");
r = route_configure(route, link, ndisc_route_handler); r = ndisc_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set additional route: %m"); return log_link_error_errno(link, r, "Could not set additional route: %m");
if (r > 0)
link->ndisc_routes_messages++;
return 0; return 0;
} }
@ -511,12 +632,19 @@ static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
return memcmp(&a->address, &b->address, sizeof(a->address)); return memcmp(&a->address, &b->address, sizeof(a->address));
} }
DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops, NDiscRDNSS, ndisc_rdnss_hash_func, ndisc_rdnss_compare_func); DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ndisc_rdnss_hash_ops,
NDiscRDNSS,
ndisc_rdnss_hash_func,
ndisc_rdnss_compare_func,
free);
static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
uint32_t lifetime; uint32_t lifetime;
const struct in6_addr *a; const struct in6_addr *a;
NDiscRDNSS *rdnss;
usec_t time_now; usec_t time_now;
Iterator i;
int n, r; int n, r;
assert(link); assert(link);
@ -534,28 +662,27 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
if (n < 0) if (n < 0)
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m"); return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
for (int i = 0; i < n; i++) { SET_FOREACH(rdnss, link->ndisc_rdnss, i)
rdnss->marked = true;
if (lifetime == 0)
return 0;
if (n >= (int) NDISC_RDNSS_MAX) {
log_link_warning(link, "Too many RDNSS records per link. Only first %i records will be used.", NDISC_RDNSS_MAX);
n = NDISC_RDNSS_MAX;
}
for (int j = 0; j < n; j++) {
_cleanup_free_ NDiscRDNSS *x = NULL; _cleanup_free_ NDiscRDNSS *x = NULL;
NDiscRDNSS d = { NDiscRDNSS d = {
.address = a[i], .address = a[j],
}, *y; };
if (lifetime == 0) { rdnss = set_get(link->ndisc_rdnss, &d);
(void) set_remove(link->ndisc_rdnss, &d); if (rdnss) {
link_dirty(link); rdnss->marked = false;
continue; rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
}
y = set_get(link->ndisc_rdnss, &d);
if (y) {
y->valid_until = time_now + lifetime * USEC_PER_SEC;
continue;
}
ndisc_vacuum(link);
if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
log_link_warning(link, "Too many RDNSS records per link, ignoring.");
continue; continue;
} }
@ -564,7 +691,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
return log_oom(); return log_oom();
*x = (NDiscRDNSS) { *x = (NDiscRDNSS) {
.address = a[i], .address = a[j],
.valid_until = time_now + lifetime * USEC_PER_SEC, .valid_until = time_now + lifetime * USEC_PER_SEC,
}; };
@ -572,8 +699,6 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
assert(r > 0); assert(r > 0);
link_dirty(link);
} }
return 0; return 0;
@ -587,13 +712,20 @@ static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b)); return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
} }
DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops, NDiscDNSSL, ndisc_dnssl_hash_func, ndisc_dnssl_compare_func); DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ndisc_dnssl_hash_ops,
NDiscDNSSL,
ndisc_dnssl_hash_func,
ndisc_dnssl_compare_func,
free);
static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
uint32_t lifetime; uint32_t lifetime;
usec_t time_now; usec_t time_now;
char **i; NDiscDNSSL *dnssl;
Iterator i;
char **j;
int r; int r;
assert(link); assert(link);
@ -611,32 +743,31 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m"); return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
STRV_FOREACH(i, l) { SET_FOREACH(dnssl, link->ndisc_dnssl, i)
_cleanup_free_ NDiscDNSSL *s = NULL; dnssl->marked = true;
NDiscDNSSL *x;
s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1); if (lifetime == 0)
return 0;
if (strv_length(l) >= NDISC_DNSSL_MAX) {
log_link_warning(link, "Too many DNSSL records per link. Only first %i records will be used.", NDISC_DNSSL_MAX);
STRV_FOREACH(j, l + NDISC_DNSSL_MAX)
*j = mfree(*j);
}
STRV_FOREACH(j, l) {
_cleanup_free_ NDiscDNSSL *s = NULL;
s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
if (!s) if (!s)
return log_oom(); return log_oom();
strcpy(NDISC_DNSSL_DOMAIN(s), *i); strcpy(NDISC_DNSSL_DOMAIN(s), *j);
if (lifetime == 0) { dnssl = set_get(link->ndisc_dnssl, s);
(void) set_remove(link->ndisc_dnssl, s); if (dnssl) {
link_dirty(link); dnssl->marked = false;
continue; dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
}
x = set_get(link->ndisc_dnssl, s);
if (x) {
x->valid_until = time_now + lifetime * USEC_PER_SEC;
continue;
}
ndisc_vacuum(link);
if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
log_link_warning(link, "Too many DNSSL records per link, ignoring.");
continue; continue;
} }
@ -646,8 +777,6 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
assert(r > 0); assert(r > 0);
link_dirty(link);
} }
return 0; return 0;
@ -736,6 +865,8 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
} }
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
Address *address;
Route *route;
uint64_t flags; uint64_t flags;
int r; int r;
@ -744,6 +875,23 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
assert(link->manager); assert(link->manager);
assert(rt); assert(rt);
link->ndisc_addresses_configured = false;
link->ndisc_routes_configured = false;
link_dirty(link);
while ((address = set_steal_first(link->ndisc_addresses))) {
r = set_ensure_put(&link->ndisc_addresses_old, &address_hash_ops, address);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store old NDisc SLAAC address: %m");
}
while ((route = set_steal_first(link->ndisc_routes))) {
r = set_ensure_put(&link->ndisc_routes_old, &route_hash_ops, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store old NDisc route: %m");
}
r = sd_ndisc_router_get_flags(rt, &flags); r = sd_ndisc_router_get_flags(rt, &flags);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA flags: %m"); return log_link_error_errno(link, r, "Failed to get RA flags: %m");
@ -757,10 +905,8 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED)); r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
if (r < 0 && r != -EBUSY) if (r < 0 && r != -EBUSY)
return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m"); return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
else { else
log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request"); log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
r = 0;
}
} }
r = ndisc_router_process_default(link, rt); r = ndisc_router_process_default(link, rt);
@ -770,30 +916,6 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return r; return r;
return r;
}
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
Link *link = userdata;
int r;
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
switch (event) {
case SD_NDISC_EVENT_ROUTER:
link->ndisc_addresses_configured = false;
link->ndisc_routes_configured = false;
r = ndisc_router_handler(link, rt);
if (r < 0) {
link_enter_failed(link);
return;
}
if (link->ndisc_addresses_messages == 0) if (link->ndisc_addresses_messages == 0)
link->ndisc_addresses_configured = true; link->ndisc_addresses_configured = true;
else { else {
@ -811,18 +933,44 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r
else else
log_link_debug(link, "Setting NDisc routes."); log_link_debug(link, "Setting NDisc routes.");
r = ndisc_remove_old(link, false);
if (r < 0)
return r;
if (link->ndisc_addresses_configured && link->ndisc_routes_configured) if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
link_check_ready(link); link_check_ready(link);
else else
link_set_state(link, LINK_STATE_CONFIGURING); link_set_state(link, LINK_STATE_CONFIGURING);
return 0;
}
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
Link *link = userdata;
int r;
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
switch (event) {
case SD_NDISC_EVENT_ROUTER:
r = ndisc_router_handler(link, rt);
if (r < 0) {
link_enter_failed(link);
return;
}
break; break;
case SD_NDISC_EVENT_TIMEOUT: case SD_NDISC_EVENT_TIMEOUT:
log_link_debug(link, "NDisc handler get timeout event"); log_link_debug(link, "NDisc handler get timeout event");
if (link->ndisc_addresses_messages == 0 && link->ndisc_routes_messages == 0) {
link->ndisc_addresses_configured = true; link->ndisc_addresses_configured = true;
link->ndisc_routes_configured = true; link->ndisc_routes_configured = true;
link_check_ready(link); link_check_ready(link);
}
break; break;
default: default:
assert_not_reached("Unknown NDisc event"); assert_not_reached("Unknown NDisc event");
@ -862,6 +1010,7 @@ void ndisc_vacuum(Link *link) {
NDiscDNSSL *d; NDiscDNSSL *d;
Iterator i; Iterator i;
usec_t time_now; usec_t time_now;
bool updated = false;
assert(link); assert(link);
@ -872,14 +1021,17 @@ void ndisc_vacuum(Link *link) {
SET_FOREACH(r, link->ndisc_rdnss, i) SET_FOREACH(r, link->ndisc_rdnss, i)
if (r->valid_until < time_now) { if (r->valid_until < time_now) {
free(set_remove(link->ndisc_rdnss, r)); free(set_remove(link->ndisc_rdnss, r));
link_dirty(link); updated = true;
} }
SET_FOREACH(d, link->ndisc_dnssl, i) SET_FOREACH(d, link->ndisc_dnssl, i)
if (d->valid_until < time_now) { if (d->valid_until < time_now) {
free(set_remove(link->ndisc_dnssl, d)); free(set_remove(link->ndisc_dnssl, d));
link_dirty(link); updated = true;
} }
if (updated)
link_dirty(link);
} }
void ndisc_flush(Link *link) { void ndisc_flush(Link *link) {
@ -887,8 +1039,8 @@ void ndisc_flush(Link *link) {
/* Removes all RDNSS and DNSSL entries, without exception */ /* Removes all RDNSS and DNSSL entries, without exception */
link->ndisc_rdnss = set_free_free(link->ndisc_rdnss); link->ndisc_rdnss = set_free(link->ndisc_rdnss);
link->ndisc_dnssl = set_free_free(link->ndisc_dnssl); link->ndisc_dnssl = set_free(link->ndisc_dnssl);
} }
int ipv6token_new(IPv6Token **ret) { int ipv6token_new(IPv6Token **ret) {

View File

@ -24,11 +24,15 @@ typedef enum IPv6AcceptRAStartDHCP6Client {
} IPv6AcceptRAStartDHCP6Client; } IPv6AcceptRAStartDHCP6Client;
typedef struct NDiscRDNSS { typedef struct NDiscRDNSS {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
usec_t valid_until; usec_t valid_until;
struct in6_addr address; struct in6_addr address;
} NDiscRDNSS; } NDiscRDNSS;
typedef struct NDiscDNSSL { typedef struct NDiscDNSSL {
/* Used when GC'ing old domains when configuration changes. */
bool marked;
usec_t valid_until; usec_t valid_until;
/* The domain name follows immediately. */ /* The domain name follows immediately. */
} NDiscDNSSL; } NDiscDNSSL;

View File

@ -247,7 +247,7 @@ static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
return memcmp(&a->lladdr, &b->lladdr, a->lladdr_size); return memcmp(&a->lladdr, &b->lladdr, a->lladdr_size);
} }
DEFINE_PRIVATE_HASH_OPS(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func); DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func, neighbor_free);
int neighbor_get(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) { int neighbor_get(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
Neighbor neighbor, *existing; Neighbor neighbor, *existing;

View File

@ -213,8 +213,6 @@ DHCPv6.UserClass, config_parse_dhcp_user_class,
DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class) DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class)
DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options) DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options)
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv6.AssignAcquiredDelegatedPrefixAddress, config_parse_bool, 0, offsetof(Network, dhcp6_pd_assign_prefix)
DHCPv6.AssignAcquiredDelegatedPrefixToken, config_parse_dhcp6_delegated_prefix_token, 0, 0
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0 DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra) DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra)
DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options) DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
@ -271,7 +269,9 @@ BridgeVLAN.PVID, config_parse_brvlan_pvid,
BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0 BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0 BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
Network.IPv6PrefixDelegation, config_parse_router_prefix_delegation, 0, offsetof(Network, router_prefix_delegation) Network.IPv6PrefixDelegation, config_parse_router_prefix_delegation, 0, offsetof(Network, router_prefix_delegation)
Network.IPv6PDSubnetId, config_parse_router_prefix_subnet_id, 0, 0 DHCPv6PrefixDelegation.SubnetId, config_parse_dhcp6_pd_subnet_id, 0, offsetof(Network, dhcp6_pd_subnet_id)
DHCPv6PrefixDelegation.Assign, config_parse_bool, 0, offsetof(Network, dhcp6_pd_assign)
DHCPv6PrefixDelegation.Token, config_parse_dhcp6_pd_token, 0, offsetof(Network, dhcp6_pd_token)
IPv6PrefixDelegation.RouterLifetimeSec, config_parse_sec, 0, offsetof(Network, router_lifetime_usec) IPv6PrefixDelegation.RouterLifetimeSec, config_parse_sec, 0, offsetof(Network, router_lifetime_usec)
IPv6PrefixDelegation.Managed, config_parse_bool, 0, offsetof(Network, router_managed) IPv6PrefixDelegation.Managed, config_parse_bool, 0, offsetof(Network, router_managed)
IPv6PrefixDelegation.OtherInformation, config_parse_bool, 0, offsetof(Network, router_other_information) IPv6PrefixDelegation.OtherInformation, config_parse_bool, 0, offsetof(Network, router_other_information)

View File

@ -420,7 +420,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp6_use_ntp = true, .dhcp6_use_ntp = true,
.dhcp6_use_dns = true, .dhcp6_use_dns = true,
.dhcp6_pd_assign_prefix = true, .dhcp6_pd_subnet_id = -1,
.dhcp6_pd_assign = true,
.dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true, .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
.dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true, .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
@ -429,7 +430,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp_server_emit_router = true, .dhcp_server_emit_router = true,
.dhcp_server_emit_timezone = true, .dhcp_server_emit_timezone = true,
.router_prefix_subnet_id = -1,
.router_emit_dns = true, .router_emit_dns = true,
.router_emit_domains = true, .router_emit_domains = true,

View File

@ -184,7 +184,6 @@ struct Network {
/* IPv6 prefix delegation support */ /* IPv6 prefix delegation support */
RADVPrefixDelegation router_prefix_delegation; RADVPrefixDelegation router_prefix_delegation;
int64_t router_prefix_subnet_id;
usec_t router_lifetime_usec; usec_t router_lifetime_usec;
uint8_t router_preference; uint8_t router_preference;
bool router_managed; bool router_managed;
@ -198,8 +197,11 @@ struct Network {
bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O' bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
RA flag is set, see RFC 7084, RA flag is set, see RFC 7084,
WPD-4 */ WPD-4 */
bool dhcp6_pd_assign_prefix;
union in_addr_union dhcp6_delegation_prefix_token; /* DHCPv6 Prefix Delegation support */
int64_t dhcp6_pd_subnet_id;
bool dhcp6_pd_assign;
union in_addr_union dhcp6_pd_token;
/* Bridge Support */ /* Bridge Support */
int use_bpdu; int use_bpdu;

View File

@ -650,10 +650,7 @@ int radv_configure(Link *link) {
return r; return r;
} }
if (IN_SET(link->network->router_prefix_delegation, if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
RADV_PREFIX_DELEGATION_STATIC,
RADV_PREFIX_DELEGATION_BOTH)) {
LIST_FOREACH(prefixes, p, link->network->static_prefixes) { LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
r = sd_radv_add_prefix(link->radv, p->radv_prefix, false); r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
if (r == -EEXIST) if (r == -EEXIST)
@ -673,13 +670,12 @@ int radv_configure(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
} }
} }
return 0; return 0;
} }
int radv_add_prefix(Link *link, struct in6_addr *prefix, uint8_t prefix_len, int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
uint32_t lifetime_preferred, uint32_t lifetime_valid) { uint32_t lifetime_preferred, uint32_t lifetime_valid) {
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
int r; int r;
@ -870,46 +866,3 @@ int config_parse_router_preference(const char *unit,
return 0; return 0;
} }
int config_parse_router_prefix_subnet_id(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
uint64_t t;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue) || streq(rvalue, "auto")) {
network->router_prefix_subnet_id = -1;
return 0;
}
r = safe_atoux64(rvalue, &t);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (t > INT64_MAX) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid subnet id '%s', ignoring assignment.",
rvalue);
return 0;
}
network->router_prefix_subnet_id = (int64_t)t;
return 0;
}

View File

@ -14,10 +14,10 @@ typedef struct Prefix Prefix;
typedef struct RoutePrefix RoutePrefix; typedef struct RoutePrefix RoutePrefix;
typedef enum RADVPrefixDelegation { typedef enum RADVPrefixDelegation {
RADV_PREFIX_DELEGATION_NONE, RADV_PREFIX_DELEGATION_NONE = 0,
RADV_PREFIX_DELEGATION_STATIC, RADV_PREFIX_DELEGATION_STATIC = 1 << 0,
RADV_PREFIX_DELEGATION_DHCP6, RADV_PREFIX_DELEGATION_DHCP6 = 1 << 1,
RADV_PREFIX_DELEGATION_BOTH, RADV_PREFIX_DELEGATION_BOTH = RADV_PREFIX_DELEGATION_STATIC | RADV_PREFIX_DELEGATION_DHCP6,
_RADV_PREFIX_DELEGATION_MAX, _RADV_PREFIX_DELEGATION_MAX,
_RADV_PREFIX_DELEGATION_INVALID = -1, _RADV_PREFIX_DELEGATION_INVALID = -1,
} RADVPrefixDelegation; } RADVPrefixDelegation;
@ -52,7 +52,7 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
int radv_emit_dns(Link *link); int radv_emit_dns(Link *link);
int radv_configure(Link *link); int radv_configure(Link *link);
int radv_add_prefix(Link *link, struct in6_addr *prefix, uint8_t prefix_len, int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
uint32_t lifetime_preferred, uint32_t lifetime_valid); uint32_t lifetime_preferred, uint32_t lifetime_valid);
const char* radv_prefix_delegation_to_string(RADVPrefixDelegation i) _const_; const char* radv_prefix_delegation_to_string(RADVPrefixDelegation i) _const_;
@ -60,7 +60,6 @@ RADVPrefixDelegation radv_prefix_delegation_from_string(const char *s) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_router_prefix_delegation); CONFIG_PARSER_PROTOTYPE(config_parse_router_prefix_delegation);
CONFIG_PARSER_PROTOTYPE(config_parse_router_preference); CONFIG_PARSER_PROTOTYPE(config_parse_router_preference);
CONFIG_PARSER_PROTOTYPE(config_parse_router_prefix_subnet_id);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix); CONFIG_PARSER_PROTOTYPE(config_parse_prefix);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_flags); CONFIG_PARSER_PROTOTYPE(config_parse_prefix_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_lifetime); CONFIG_PARSER_PROTOTYPE(config_parse_prefix_lifetime);

View File

@ -144,6 +144,14 @@ void route_free(Route *route) {
if (route->link) { if (route->link) {
set_remove(route->link->routes, route); set_remove(route->link->routes, route);
set_remove(route->link->routes_foreign, route); set_remove(route->link->routes_foreign, route);
set_remove(route->link->dhcp_routes, route);
set_remove(route->link->dhcp_routes_old, route);
set_remove(route->link->dhcp6_routes, route);
set_remove(route->link->dhcp6_routes_old, route);
set_remove(route->link->dhcp6_pd_routes, route);
set_remove(route->link->dhcp6_pd_routes_old, route);
set_remove(route->link->ndisc_routes, route);
set_remove(route->link->ndisc_routes_old, route);
} }
ordered_set_free_free(route->multipath_routes); ordered_set_free_free(route->multipath_routes);
@ -597,7 +605,8 @@ static int append_nexthops(Route *route, sd_netlink_message *req) {
int route_configure( int route_configure(
Route *route, Route *route,
Link *link, Link *link,
link_netlink_message_handler_t callback) { link_netlink_message_handler_t callback,
Route **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
@ -803,6 +812,9 @@ int route_configure(
sd_event_source_unref(route->expire); sd_event_source_unref(route->expire);
route->expire = TAKE_PTR(expire); route->expire = TAKE_PTR(expire);
if (ret)
*ret = route;
return 1; return 1;
} }

View File

@ -66,7 +66,7 @@ extern const struct hash_ops route_hash_ops;
int route_new(Route **ret); int route_new(Route **ret);
void route_free(Route *route); void route_free(Route *route);
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback); int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback); int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
int route_get(Link *link, Route *in, Route **ret); int route_get(Link *link, Route *in, Route **ret);

View File

@ -227,7 +227,12 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
} }
} }
DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func); DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
routing_policy_rule_hash_ops,
RoutingPolicyRule,
routing_policy_rule_hash_func,
routing_policy_rule_compare_func,
routing_policy_rule_free);
int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) { int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {

View File

@ -53,7 +53,7 @@ static void test_rule_serialization(const char *title, const char *ruleset, cons
log_info("$ %s", cmd); log_info("$ %s", cmd);
assert_se(system(cmd) == 0); assert_se(system(cmd) == 0);
set_free_with_destructor(rules, routing_policy_rule_free); set_free(rules);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {

View File

@ -8,21 +8,27 @@
#include "errno-util.h" #include "errno-util.h"
#include "macro.h" #include "macro.h"
/* 4MB for contents of regular files, 64k inodes for directories, symbolic links and device specials, /* 4MB for contents of regular files, 64k inodes for directories, symbolic links and device specials, using
using large storage array systems as a baseline */ * large storage array systems as a baseline */
#define TMPFS_LIMITS_DEV ",size=4m,nr_inodes=64k" #define TMPFS_LIMITS_DEV ",size=4m,nr_inodes=64k"
/* Very little, if any use expected */ /* Very little, if any use expected */
#define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k" #define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k"
#define TMPFS_LIMITS_SYS TMPFS_LIMITS_EMPTY_OR_ALMOST #define TMPFS_LIMITS_SYS TMPFS_LIMITS_EMPTY_OR_ALMOST
#define TMPFS_LIMITS_SYS_FS_CGROUP TMPFS_LIMITS_EMPTY_OR_ALMOST #define TMPFS_LIMITS_SYS_FS_CGROUP TMPFS_LIMITS_EMPTY_OR_ALMOST
/* On an extremely small device with only 256MB of RAM, 20% of RAM for /run should be enough for re-exec of
PID1 because 16MB of free space is required. */ /* On an extremely small device with only 256MB of RAM, 20% of RAM should be enough for the re-execution of
* PID1 because 16MB of free space is required. */
#define TMPFS_LIMITS_RUN ",size=20%,nr_inodes=800k" #define TMPFS_LIMITS_RUN ",size=20%,nr_inodes=800k"
/* 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25%
translates to 1M inodes */ /* The limit used for various tmpfs mounts, but not /tmp itself.
* 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25%
* translates to 1M inodes.
* /tmp is configured through a .mount unit file. */
#define TMPFS_LIMITS_TMP ",size=10%,nr_inodes=400k" #define TMPFS_LIMITS_TMP ",size=10%,nr_inodes=400k"
#define TMPFS_LIMITS_DEV_SHM TMPFS_LIMITS_TMP #define TMPFS_LIMITS_DEV_SHM TMPFS_LIMITS_TMP
#define TMPFS_LIMITS_TEMPORARY_FS TMPFS_LIMITS_TMP #define TMPFS_LIMITS_TEMPORARY_FS TMPFS_LIMITS_TMP
/* More space for volatile root and /var */ /* More space for volatile root and /var */
#define TMPFS_LIMITS_VAR ",size=25%,nr_inodes=1m" #define TMPFS_LIMITS_VAR ",size=25%,nr_inodes=1m"
#define TMPFS_LIMITS_ROOTFS TMPFS_LIMITS_VAR #define TMPFS_LIMITS_ROOTFS TMPFS_LIMITS_VAR

View File

@ -125,10 +125,16 @@ int can_sleep_state(char **types) {
k = strlen(*type); k = strlen(*type);
FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state) FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state)
if (l == k && memcmp(word, *type, l) == 0) if (l == k && memcmp(word, *type, l) == 0) {
log_debug("Sleep mode \"%s\" is supported by the kernel.", *type);
return true; return true;
} }
}
if (DEBUG_LOGGING) {
_cleanup_free_ char *t = strv_join(types, "/");
log_debug("Sleep mode %s not supported by the kernel, sorry.", strnull(t));
}
return false; return false;
} }

View File

@ -23,7 +23,7 @@ static void check_p_d_u(const char *path, int code, const char *result) {
int r; int r;
r = cg_path_decode_unit(path, &unit); r = cg_path_decode_unit(path, &unit);
printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code); printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, strnull(result), code);
assert_se(r == code); assert_se(r == code);
assert_se(streq_ptr(unit, result)); assert_se(streq_ptr(unit, result));
} }
@ -45,7 +45,7 @@ static void check_p_g_u(const char *path, int code, const char *result) {
int r; int r;
r = cg_path_get_unit(path, &unit); r = cg_path_get_unit(path, &unit);
printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code); printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, strnull(result), code);
assert_se(r == code); assert_se(r == code);
assert_se(streq_ptr(unit, result)); assert_se(streq_ptr(unit, result));
} }
@ -69,7 +69,7 @@ static void check_p_g_u_u(const char *path, int code, const char *result) {
int r; int r;
r = cg_path_get_user_unit(path, &unit); r = cg_path_get_user_unit(path, &unit);
printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code); printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, strnull(result), code);
assert_se(r == code); assert_se(r == code);
assert_se(streq_ptr(unit, result)); assert_se(streq_ptr(unit, result));
} }

View File

@ -864,14 +864,17 @@ static void test_path_is_encrypted_one(const char *p, int expect) {
} }
static void test_path_is_encrypted(void) { static void test_path_is_encrypted(void) {
log_info("/* %s */", __func__); int booted = sd_booted(); /* If this is run in build environments such as koji, /dev might be a
* reguar fs. Don't assume too much if not running under systemd. */
log_info("/* %s (sd_booted=%d)*/", __func__, booted);
test_path_is_encrypted_one("/home", -1); test_path_is_encrypted_one("/home", -1);
test_path_is_encrypted_one("/var", -1); test_path_is_encrypted_one("/var", -1);
test_path_is_encrypted_one("/", -1); test_path_is_encrypted_one("/", -1);
test_path_is_encrypted_one("/proc", false); test_path_is_encrypted_one("/proc", false);
test_path_is_encrypted_one("/sys", false); test_path_is_encrypted_one("/sys", false);
test_path_is_encrypted_one("/dev", false); test_path_is_encrypted_one("/dev", booted > 0 ? false : -1);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

View File

@ -79,21 +79,15 @@ static Service *service_for_path(Manager *m, Path *path, const char *service_nam
} }
static void check_states(Manager *m, Path *path, Service *service, PathState path_state, ServiceState service_state) { static void check_states(Manager *m, Path *path, Service *service, PathState path_state, ServiceState service_state) {
usec_t ts;
usec_t timeout = 2 * USEC_PER_SEC;
assert_se(m); assert_se(m);
assert_se(service); assert_se(service);
ts = now(CLOCK_MONOTONIC); usec_t end = now(CLOCK_MONOTONIC) + 30 * USEC_PER_SEC;
while (path->result != PATH_SUCCESS || service->result != SERVICE_SUCCESS || while (path->result != PATH_SUCCESS || service->result != SERVICE_SUCCESS ||
path->state != path_state || service->state != service_state) { path->state != path_state || service->state != service_state) {
usec_t n;
int r;
r = sd_event_run(m->event, 100 * USEC_PER_MSEC); assert_se(sd_event_run(m->event, 100 * USEC_PER_MSEC) >= 0);
assert_se(r >= 0);
printf("%s: state = %s; result = %s \n", printf("%s: state = %s; result = %s \n",
UNIT(path)->id, UNIT(path)->id,
@ -104,8 +98,7 @@ static void check_states(Manager *m, Path *path, Service *service, PathState pat
service_state_to_string(service->state), service_state_to_string(service->state),
service_result_to_string(service->result)); service_result_to_string(service->result));
n = now(CLOCK_MONOTONIC); if (now(CLOCK_MONOTONIC) >= end) {
if (ts + timeout < n) {
log_error("Test timeout when testing %s", UNIT(path)->id); log_error("Test timeout when testing %s", UNIT(path)->id);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -7,6 +7,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "efivars.h"
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "log.h" #include "log.h"
@ -84,7 +85,9 @@ static void test_sleep(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
log_info("/= configuration =/"); printf("Secure boot: %sd\n", enable_disable(is_efi_secure_boot()));
log_info("/= individual sleep modes =/");
log_info("Standby configured: %s", yes_no(can_sleep_state(standby) > 0)); log_info("Standby configured: %s", yes_no(can_sleep_state(standby) > 0));
log_info("Suspend configured: %s", yes_no(can_sleep_state(mem) > 0)); log_info("Suspend configured: %s", yes_no(can_sleep_state(mem) > 0));
log_info("Hibernate configured: %s", yes_no(can_sleep_state(disk) > 0)); log_info("Hibernate configured: %s", yes_no(can_sleep_state(disk) > 0));
@ -94,7 +97,7 @@ static void test_sleep(void) {
log_info("Hibernate+Shutdown configured: %s", yes_no(can_sleep_disk(shutdown) > 0)); log_info("Hibernate+Shutdown configured: %s", yes_no(can_sleep_disk(shutdown) > 0));
log_info("Freeze configured: %s", yes_no(can_sleep_state(freeze) > 0)); log_info("Freeze configured: %s", yes_no(can_sleep_state(freeze) > 0));
log_info("/= running system =/"); log_info("/= high-level sleep verbs =/");
r = can_sleep("suspend"); r = can_sleep("suspend");
log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r)); log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("hibernate"); r = can_sleep("hibernate");

View File

@ -130,10 +130,12 @@ SendOption=
RequestOptions= RequestOptions=
UserClass= UserClass=
VendorClass= VendorClass=
AssignAcquiredDelegatedPrefixAddress=
AssignAcquiredDelegatedPrefixToken=
SendVendorOption= SendVendorOption=
RouteMetric= RouteMetric=
[DHCPv6PrefixDelegation]
SubnetId=
Assign=
Token=
[Route] [Route]
Destination= Destination=
Protocol= Protocol=
@ -203,7 +205,6 @@ NTP=
DHCP= DHCP=
Domains= Domains=
IPv6PrefixDelegation= IPv6PrefixDelegation=
IPv6PDSubnetId=
VLAN= VLAN=
DHCPServer= DHCPServer=
BindCarrier= BindCarrier=

View File

@ -0,0 +1,26 @@
[Match]
Name=dummy98
[Network]
IPv6AcceptRA=no
VRF=vrf99
Address=fdde:11:22::1/128
Address=fdde:11:33::1/64
Address=10.20.22.1/32
Address=10.20.33.1/24
[Address]
Address=fdde:11:44::1/128
AddPrefixRoute=no
[Address]
Address=fdde:11:55::1/64
AddPrefixRoute=no
[Address]
Address=10.20.44.1/32
AddPrefixRoute=no
[Address]
Address=10.20.55.1/24
AddPrefixRoute=no

View File

@ -0,0 +1,25 @@
[Match]
Name=test1
[Network]
IPv6AcceptRA=no
Address=fdde:12:22::1/128
Address=fdde:12:33::1/64
Address=10.21.22.1/32
Address=10.21.33.1/24
[Address]
Address=fdde:12:44::1/128
AddPrefixRoute=no
[Address]
Address=fdde:12:55::1/64
AddPrefixRoute=no
[Address]
Address=10.21.44.1/32
AddPrefixRoute=no
[Address]
Address=10.21.55.1/24
AddPrefixRoute=no

View File

@ -1717,6 +1717,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-qdisc-ingress-netem-compat.network', '25-qdisc-ingress-netem-compat.network',
'25-qdisc-pie.network', '25-qdisc-pie.network',
'25-qdisc-qfq.network', '25-qdisc-qfq.network',
'25-prefix-route-with-vrf.network',
'25-prefix-route-without-vrf.network',
'25-route-ipv6-src.network', '25-route-ipv6-src.network',
'25-route-static.network', '25-route-static.network',
'25-route-vrf.network', '25-route-vrf.network',
@ -1729,6 +1731,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-veth-peer.network', '25-veth-peer.network',
'25-veth.netdev', '25-veth.netdev',
'25-vrf.netdev', '25-vrf.netdev',
'25-vrf.network',
'26-link-local-addressing-ipv6.network', '26-link-local-addressing-ipv6.network',
'routing-policy-rule-dummy98.network', 'routing-policy-rule-dummy98.network',
'routing-policy-rule-test1.network'] 'routing-policy-rule-test1.network']
@ -1815,6 +1818,77 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
print(output) print(output)
self.assertNotRegex(output, '192.168.100.10/24') self.assertNotRegex(output, '192.168.100.10/24')
@expectedFailureIfModuleIsNotAvailable('vrf')
def test_prefix_route(self):
copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
'25-prefix-route-without-vrf.network', '11-dummy.netdev',
'25-vrf.netdev', '25-vrf.network')
for trial in range(2):
if trial == 0:
start_networkd()
else:
restart_networkd(3)
self.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
output = check_output('ip route show table 42 dev dummy98')
print('### ip route show table 42 dev dummy98')
print(output)
self.assertRegex(output, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
self.assertRegex(output, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
self.assertRegex(output, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
self.assertRegex(output, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
self.assertRegex(output, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
self.assertRegex(output, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
self.assertRegex(output, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
self.assertRegex(output, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
self.assertRegex(output, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
output = check_output('ip -6 route show table 42 dev dummy98')
print('### ip -6 route show table 42 dev dummy98')
print(output)
if trial == 0:
# Kernel's bug?
self.assertRegex(output, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
#self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
self.assertRegex(output, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
self.assertRegex(output, 'ff00::/8 metric 256 pref medium')
print()
output = check_output('ip route show dev test1')
print('### ip route show dev test1')
print(output)
self.assertRegex(output, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
output = check_output('ip route show table local dev test1')
print('### ip route show table local dev test1')
print(output)
self.assertRegex(output, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
self.assertRegex(output, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
self.assertRegex(output, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
self.assertRegex(output, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
self.assertRegex(output, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
self.assertRegex(output, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
self.assertRegex(output, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
self.assertRegex(output, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
output = check_output('ip -6 route show dev test1')
print('### ip -6 route show dev test1')
print(output)
self.assertRegex(output, 'fdde:12:22::1 proto kernel metric 256 pref medium')
self.assertRegex(output, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
output = check_output('ip -6 route show table local dev test1')
print('### ip -6 route show table local dev test1')
print(output)
self.assertRegex(output, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'ff00::/8 metric 256 pref medium')
def test_configure_without_carrier(self): def test_configure_without_carrier(self):
copy_unit_to_networkd_unit_path('11-dummy.netdev') copy_unit_to_networkd_unit_path('11-dummy.netdev')
start_networkd() start_networkd()

View File

@ -22,4 +22,4 @@ After=swap.target
What=tmpfs What=tmpfs
Where=/tmp Where=/tmp
Type=tmpfs Type=tmpfs
Options=mode=1777,strictatime,nosuid,nodev,size=10%,nr_inodes=400k Options=mode=1777,strictatime,nosuid,nodev,size=50%,nr_inodes=400k