1
0
mirror of https://github.com/systemd/systemd synced 2026-04-21 22:44:51 +02:00

Compare commits

..

12 Commits

Author SHA1 Message Date
Luca Boccassi
82a03e8a85
Merge pull request #22389 from poettering/resolved-sysinit
units: move resolved to sysinit.target (from basic.target)
2022-02-24 23:00:27 +00:00
Luca Boccassi
6b3211c15e
Merge pull request #22611 from yuwata/network-activation-policy-stacked-netdevs
network: make activation policy also work for stacked netdevs
2022-02-24 22:57:35 +00:00
Luca Boccassi
224f21e64f
Merge pull request #22615 from yuwata/network-dhcp-server-support-pxe-boot-systems
network: dhcp server: support pxe boot systems
2022-02-24 22:52:56 +00:00
Daan De Meyer
baec7d782b meson: Drop required libfdisk version to 2.32
We initially pinned this to 2.33 in
e71f5585b9b0580428f9530d0a485265c9c25165 because libfdisk 2.32 in
CentOS 8 didn't have
2f35c1ead6
backported.

If we check now, we can see it has been backported
(https://git.centos.org/rpms/util-linux/blob/c8s/f/SOURCES/0048-libfdisk-count-gaps-to-possible-size-when-resize.patch)
which means we can drop the required version to 2.32 instead of 2.33.
2022-02-24 20:06:55 +00:00
Yu Watanabe
369ac19243 network: add NextServer= and Filename= setting to [DHCPServer] section
Closes #4403.
2022-02-25 02:45:47 +09:00
Yu Watanabe
d5e5cd5c34 sd-dhcp-server: add support to send next server and filename option for PXE boot systems 2022-02-25 02:32:58 +09:00
Lennart Poettering
047c2c14c5 units: drop After=systemd-resolved.service from systemd-nspawn@.service
resolved is now started as part of early boot hence we need no explicit
ordering anymore.
2022-02-24 10:37:11 +01:00
Lennart Poettering
29a8fbf49a units: move resolved to sysinit.target (from basic.target)
79a67f3ca4d32c37b5e754501852a85eae908a6a pulled systemd-resolved.service
in from basic.target instead of multi-user.target, i.e. the idea is to
make it an early boot service, instead of a regular service.

However, early boot services are supposed to be in sysinit.target, not
basic.target (the latter is just one that combines the early boot
services in sysinit.target, the sockets in sockets.targt, the mounts in
local-fs.target and so on into one big target).

Also, the comit actually didn't add a synchronization point, i.e. not
Before=, so that the whole thing was racy.

Let's fix all that.

Follow-up for 79a67f3ca4d32c37b5e754501852a85eae908a6a
2022-02-24 10:36:47 +01:00
Yu Watanabe
ee9918ae46 test-network: add test case for activation policy for stacked netdevs
For issue #22593.
2022-02-24 16:25:05 +09:00
Yu Watanabe
459c35d4c5 test-network: check existence before calling networkctl or ip command 2022-02-24 16:25:05 +09:00
Yu Watanabe
3c39b9cf37 test-network: remove unused configs 2022-02-24 08:37:30 +09:00
Yu Watanabe
047b9991a4 network: create stacked netdevs after the underlying link is activated
Otherwise, the activation policy for the netdevs are ignored.

Fixes #22593.
2022-02-24 08:37:26 +09:00
19 changed files with 119 additions and 39 deletions

2
README
View File

@ -177,7 +177,7 @@ REQUIREMENTS:
libaudit (optional)
libacl (optional)
libbpf >= 0.2.0 (optional)
libfdisk >= 2.33 (from util-linux) (optional)
libfdisk >= 2.32 (from util-linux) (optional)
libselinux (optional)
liblzma (optional)
liblz4 >= 1.3.0 / 130 (optional)

View File

@ -2626,6 +2626,23 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
<filename>/etc/localtime</filename> symlink.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>NextServer=</varname></term>
<listitem>
<para>Takes an IPv4 address. Configures the next server used by e.g. PXE boot systems.
Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Filename=</varname></term>
<listitem>
<para>Takes a path or url to a file loaded by e.g. a PXE boot loader. Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>SendOption=</varname></term>
<listitem>

View File

@ -1052,7 +1052,7 @@ libmount = dependency('mount',
want_libfdisk = get_option('fdisk')
if want_libfdisk != 'false' and not skip_deps
libfdisk = dependency('fdisk',
version : '>= 2.33',
version : '>= 2.32',
required : want_libfdisk == 'true')
have = libfdisk.found()
else

View File

@ -65,6 +65,8 @@ struct sd_dhcp_server {
char *timezone;
DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
struct in_addr next_server;
char *filename;
OrderedSet *extra_options;
OrderedSet *vendor_options;

View File

@ -21,6 +21,7 @@
#include "siphash24.h"
#include "string-util.h"
#include "unaligned.h"
#include "utf8.h"
#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
@ -162,6 +163,7 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
sd_event_unref(server->event);
free(server->filename);
free(server->timezone);
for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
@ -270,6 +272,26 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
return server->event;
}
int sd_dhcp_server_set_next_server(sd_dhcp_server *server, const struct in_addr *next_server) {
assert_return(server, -EINVAL);
if (next_server)
server->next_server = *next_server;
else
server->next_server = (struct in_addr) {};
return 0;
}
int sd_dhcp_server_set_filename(sd_dhcp_server *server, const char *filename) {
assert_return(server, -EINVAL);
if (filename && !ascii_is_valid(filename))
return -EINVAL;
return free_and_strdup(&server->filename, filename);
}
int sd_dhcp_server_stop(sd_dhcp_server *server) {
bool running;
@ -539,6 +561,7 @@ static int server_send_offer_or_ack(
return r;
packet->dhcp.yiaddr = address;
packet->dhcp.siaddr = server->next_server.s_addr;
lease_time = htobe32(req->lifetime);
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
@ -562,6 +585,22 @@ static int server_send_offer_or_ack(
return r;
}
if (server->filename) {
/* The pxelinux magic option is marked as deprecated, but let's append it for older
* implementations. */
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
SD_DHCP_OPTION_PXELINUX_MAGIC, 4,
(const uint8_t[]) { 0xf1, 0x00, 0x74, 0x7e });
if (r < 0)
return r;
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
SD_DHCP_OPTION_CONFIGURATION_FILE,
strlen(server->filename), server->filename);
if (r < 0)
return r;
}
if (type == DHCP_ACK) {
static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
[SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER,

View File

@ -643,6 +643,11 @@ static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
if (link->set_link_messages > 0)
return false;
/* If stacked netdevs are created before the underlying interface being activated, then
* the activation policy for the netdevs are ignored. See issue #22593. */
if (!link->activated)
return false;
}
if (NETDEV_VTABLE(netdev)->is_ready_to_create)

View File

@ -416,6 +416,14 @@ static int dhcp4_server_configure(Link *link) {
return log_link_error_errno(link, r, "Failed to set default lease time for DHCPv4 server instance: %m");
}
r = sd_dhcp_server_set_next_server(link->dhcp_server, &link->network->dhcp_server_next_server);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to set next server for DHCPv4 server instance: %m");
r = sd_dhcp_server_set_filename(link->dhcp_server, link->network->dhcp_server_filename);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to set filename for DHCPv4 server instance: %m");
for (sd_dhcp_lease_server_type_t type = 0; type < _SD_DHCP_LEASE_SERVER_TYPE_MAX; type ++) {
if (!link->network->dhcp_server_emit[type].emit)

View File

@ -305,6 +305,8 @@ DHCPServer.PoolSize, config_parse_uint32,
DHCPServer.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_server_send_vendor_options)
DHCPServer.SendOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_server_send_options)
DHCPServer.BindToInterface, config_parse_bool, 0, offsetof(Network, dhcp_server_bind_to_interface)
DHCPServer.NextServer, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_next_server)
DHCPServer.Filename, config_parse_string, 0, offsetof(Network, dhcp_server_filename)
DHCPServerStaticLease.Address, config_parse_dhcp_static_lease_address, 0, 0
DHCPServerStaticLease.MACAddress, config_parse_dhcp_static_lease_hwaddr, 0, 0
Bridge.Cost, config_parse_uint32, 0, offsetof(Network, cost)

View File

@ -700,6 +700,7 @@ static Network *network_free(Network *network) {
free(network->dhcp_server_relay_agent_circuit_id);
free(network->dhcp_server_relay_agent_remote_id);
free(network->dhcp_server_filename);
free(network->description);
free(network->dhcp_vendor_class_identifier);

View File

@ -200,6 +200,8 @@ struct Network {
uint32_t dhcp_server_pool_size;
OrderedHashmap *dhcp_server_send_options;
OrderedHashmap *dhcp_server_send_vendor_options;
struct in_addr dhcp_server_next_server;
char *dhcp_server_filename;
/* link local addressing support */
AddressFamily link_local;

View File

@ -97,6 +97,10 @@ enum {
SD_DHCP_OPTION_SIP_SERVER = 120,
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
SD_DHCP_OPTION_MUD_URL = 161,
SD_DHCP_OPTION_PXELINUX_MAGIC = 208, /* deprecated */
SD_DHCP_OPTION_CONFIGURATION_FILE = 209,
SD_DHCP_OPTION_PATH_PREFIX = 210,
SD_DHCP_OPTION_REBOOT_TIME = 211,
SD_DHCP_OPTION_6RD = 212,
SD_DHCP_OPTION_PRIVATE_BASE = 224,
/* Windows 10 option to send when Anonymize=true */

View File

@ -58,6 +58,8 @@ int sd_dhcp_server_stop(sd_dhcp_server *server);
int sd_dhcp_server_configure_pool(sd_dhcp_server *server, const struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size);
int sd_dhcp_server_set_next_server(sd_dhcp_server *server, const struct in_addr *next_server);
int sd_dhcp_server_set_filename(sd_dhcp_server *server, const char *filename);
int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled);
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
int sd_dhcp_server_set_router(sd_dhcp_server *server, const struct in_addr *address);

View File

@ -409,6 +409,8 @@ RelayAgentCircuitId=
RelayAgentRemoteId=
ServerAddress=
UplinkInterface=
NextServer=
Filename=
[DHCPServerStaticLease]
MACAddress=
Address=

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=test1
Name=vlan99
[Network]
Address=192.168.10.30/24

View File

@ -1,8 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[NetDev]
Name=vlan6
Kind=vlan
MTUBytes=1500
[VLAN]
Id=6

View File

@ -1,7 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=vlan6
[Network]
IPv6AcceptRA=false
Address=100.100.100.2/24

View File

@ -609,11 +609,13 @@ class Utilities():
needle = f'{link}: Bringing link {state}'
flag = state.upper()
for iteration in range(timeout+1):
if iteration != 0:
time.sleep(1)
if not link_exists(link):
continue
output = check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id)
if needle in output and flag in check_output(f'ip link show {link}'):
return True
if iteration < timeout:
time.sleep(1)
if fail_assert:
self.fail(f'Timed out waiting for {link} activated.')
return False
@ -638,13 +640,14 @@ class Utilities():
setup_state = r'\S+'
for secs in range(setup_timeout + 1):
if secs != 0:
time.sleep(1)
if not link_exists(link):
continue
output = check_output(*networkctl_cmd, '-n', '0', 'status', link, env=env)
print(output)
if re.search(rf'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output):
return True
# don't bother sleeping if time is up
if secs < setup_timeout:
time.sleep(1)
if fail_assert:
self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
return False
@ -2053,6 +2056,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'test1',
'veth-peer',
'veth99',
'vlan99',
'vrf99',
]
@ -2060,6 +2064,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'11-dummy.netdev',
'12-dummy.netdev',
'12-dummy.network',
'21-vlan.netdev',
'21-vlan-test1.network',
'23-active-slave.network',
'24-keep-configuration-static.network',
'24-search-domain.network',
@ -3115,10 +3121,12 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
self.wait_operstate('test1', 'routable')
def _test_activation_policy(self, test):
def _test_activation_policy(self, test, interface):
conffile = '25-activation-policy.network'
if test:
conffile = f'{conffile}.d/{test}.conf'
if interface == 'vlan99':
copy_unit_to_networkd_unit_path('21-vlan.netdev', '21-vlan-test1.network')
copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile, dropins=False)
start_networkd()
@ -3128,36 +3136,38 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
next_up = not expect_up
if test.endswith('down'):
self.wait_activated('test1')
self.wait_activated(interface)
for iteration in range(4):
with self.subTest(iteration=iteration, expect_up=expect_up):
operstate = 'routable' if expect_up else 'off'
setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None)
self.wait_operstate('test1', operstate, setup_state=setup_state, setup_timeout=20)
self.wait_operstate(interface, operstate, setup_state=setup_state, setup_timeout=20)
if expect_up:
self.assertIn('UP', check_output('ip link show test1'))
self.assertIn('192.168.10.30/24', check_output('ip address show test1'))
self.assertIn('default via 192.168.10.1', check_output('ip route show dev test1'))
self.assertIn('UP', check_output(f'ip link show {interface}'))
self.assertIn('192.168.10.30/24', check_output(f'ip address show {interface}'))
self.assertIn('default via 192.168.10.1', check_output(f'ip route show dev {interface}'))
else:
self.assertIn('DOWN', check_output('ip link show test1'))
self.assertIn('DOWN', check_output(f'ip link show {interface}'))
if next_up:
check_output('ip link set dev test1 up')
check_output(f'ip link set dev {interface} up')
else:
check_output('ip link set dev test1 down')
check_output(f'ip link set dev {interface} down')
expect_up = initial_up if always else next_up
next_up = not next_up
if always:
time.sleep(1)
def test_activation_policy(self):
for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
with self.subTest(test=test):
self.setUp()
self._test_activation_policy(test)
self.tearDown()
for interface in ['test1', 'vlan99']:
with self.subTest(interface=interface):
for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
with self.subTest(test=test):
self.setUp()
self._test_activation_policy(test, interface)
self.tearDown()
def _test_activation_policy_required_for_online(self, policy, required):
conffile = '25-activation-policy.network'

View File

@ -13,7 +13,7 @@ Documentation=man:systemd-nspawn(1)
Wants=modprobe@tun.service modprobe@loop.service modprobe@dm-mod.service
PartOf=machines.target
Before=machines.target
After=network.target systemd-resolved.service modprobe@tun.service modprobe@loop.service modprobe@dm-mod.service
After=network.target modprobe@tun.service modprobe@loop.service modprobe@dm-mod.service
RequiresMountsFor=/var/lib/machines/%i
[Service]

View File

@ -16,7 +16,7 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-resolver
DefaultDependencies=no
After=systemd-sysusers.service
Before=network.target nss-lookup.target shutdown.target
Before=sysinit.target network.target nss-lookup.target shutdown.target
Conflicts=shutdown.target
Wants=nss-lookup.target
@ -54,5 +54,5 @@ User=systemd-resolve
{{SERVICE_WATCHDOG}}
[Install]
WantedBy=basic.target
WantedBy=sysinit.target
Alias=dbus-org.freedesktop.resolve1.service