• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 20629511025

31 Dec 2025 02:58PM UTC coverage: 72.676% (+0.2%) from 72.439%
20629511025

push

github

web-flow
Support Bash completions for short option group in journalctl (#40214)

Currently, the Bash completions for journalctl tries to match the
previous word _**exactly**_, which leads to the following issue:
`journalctl -u dock` correctly auto completes to `journalctl -u
docker.service`, but `journalctl -eu` provides no completions at all,
which is a shame since I never use the `-u` option alone (almost always
`-eu` or `-efu`, I wish the `-e` option was the default but I digress).

The proposed solution is to assume words that start with only a single
dash and consist of only letters are short option groups and handle them
as if the previous word was the short option using the last character,
e.g. `-efu` -> `-u`.

309992 of 426542 relevant lines covered (72.68%)

1153788.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.27
/src/network/networkd-sysctl.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <linux/if_arp.h>
4

5
#include "sd-messages.h"
6

7
#include "af-list.h"
8
#include "bpf-dlopen.h"
9
#include "conf-parser.h"
10
#include "alloc-util.h"
11
#include "cgroup-util.h"
12
#include "errno-util.h"
13
#include "event-util.h"
14
#include "fd-util.h"
15
#include "format-util.h"
16
#include "hashmap.h"
17
#include "networkd-link.h"
18
#include "networkd-lldp-tx.h"
19
#include "networkd-manager.h"
20
#include "networkd-ndisc.h"
21
#include "networkd-network.h"
22
#include "networkd-sysctl.h"
23
#include "path-util.h"
24
#include "set.h"
25
#include "socket-util.h"
26
#include "string-table.h"
27
#include "string-util.h"
28
#include "sysctl-util.h"
29

30
#if ENABLE_SYSCTL_BPF
31

32
#include "bpf-link.h"
33
#include "bpf/sysctl-monitor/sysctl-monitor-skel.h"
34
#include "bpf/sysctl-monitor/sysctl-write-event.h"
35

36
static struct sysctl_monitor_bpf* sysctl_monitor_bpf_free(struct sysctl_monitor_bpf *obj) {
471✔
37
        sysctl_monitor_bpf__destroy(obj);
471✔
38
        return NULL;
471✔
39
}
40

41
DEFINE_TRIVIAL_CLEANUP_FUNC(struct sysctl_monitor_bpf *, sysctl_monitor_bpf_free);
446✔
42

43
static int sysctl_event_handler(void *ctx, void *data, size_t data_sz) {
17✔
44
        struct sysctl_write_event *we = ASSERT_PTR(data);
17✔
45
        Hashmap **sysctl_shadow = ASSERT_PTR(ctx);
17✔
46
        _cleanup_free_ char *path = NULL;
17✔
47
        char *value;
17✔
48

49
        /* Returning a negative value interrupts the ring buffer polling,
50
         * so do it only in case of a fatal error like a version mismatch. */
51
        if (we->version != 1)
17✔
52
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
×
53
                                         "Unexpected sysctl event, disabling sysctl monitoring: %d", we->version);
54

55
        if (we->errorcode != 0) {
17✔
56
                /* The log message is checked in test-network/systemd-networkd-tests.py. Please update the
57
                 * test when the log message is changed. */
58
                log_warning_errno(we->errorcode, "Sysctl monitor BPF returned error: %m");
×
59
                return 0;
×
60
        }
61

62
        path = path_join("/proc/sys", we->path);
17✔
63
        if (!path) {
17✔
64
                log_oom_warning();
×
65
                return 0;
66
        }
67

68
        /* If we never managed this handle, ignore it. */
69
        value = hashmap_get(*sysctl_shadow, path);
17✔
70
        if (!value)
17✔
71
                return 0;
72

73
        if (!strneq(value, we->newvalue, sizeof(we->newvalue)))
4✔
74
                /* The log message is checked in test-network/systemd-networkd-tests.py. Please update the
75
                 * test when the log message is changed. */
76
                log_struct(LOG_WARNING,
4✔
77
                           LOG_MESSAGE_ID(SD_MESSAGE_SYSCTL_CHANGED_STR),
78
                           LOG_ITEM("OBJECT_PID=" PID_FMT, we->pid),
79
                           LOG_ITEM("OBJECT_COMM=%s", we->comm),
80
                           LOG_ITEM("SYSCTL=%s", path),
81
                           LOG_ITEM("OLDVALUE=%s", we->current),
82
                           LOG_ITEM("NEWVALUE=%s", we->newvalue),
83
                           LOG_ITEM("OURVALUE=%s", value),
84
                           LOG_MESSAGE("Foreign process '%s[" PID_FMT "]' changed sysctl '%s' from '%s' to '%s', conflicting with our setting to '%s'.",
85
                                       we->comm, we->pid, path, we->current, we->newvalue, value));
86

87
        return 0;
88
}
89

90
static int on_ringbuf_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
14✔
91
        struct ring_buffer *rb = ASSERT_PTR(userdata);
14✔
92
        int r;
14✔
93

94
        r = sym_ring_buffer__poll(rb, /* timeout_msec= */ 0);
14✔
95
        if (r < 0 && errno != EINTR)
14✔
96
                log_error_errno(errno, "Error polling ring buffer: %m");
×
97

98
        return 0;
14✔
99
}
100

101
int manager_install_sysctl_monitor(Manager *manager) {
446✔
102
        _cleanup_(sysctl_monitor_bpf_freep) struct sysctl_monitor_bpf *obj = NULL;
446✔
103
        _cleanup_(bpf_link_freep) struct bpf_link *sysctl_link = NULL;
446✔
104
        _cleanup_(bpf_ring_buffer_freep) struct ring_buffer *sysctl_buffer = NULL;
×
105
        _cleanup_close_ int cgroup_fd = -EBADF, root_cgroup_fd = -EBADF;
892✔
106
        _cleanup_free_ char *cgroup = NULL;
446✔
107
        int idx = 0, r, fd;
446✔
108

109
        assert(manager);
446✔
110

111
        r = dlopen_bpf();
446✔
112
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
446✔
113
                return log_debug_errno(r, "sysctl monitor disabled, as BPF support is not available.");
×
114
        if (r < 0)
446✔
115
                return log_warning_errno(r, "Failed to load libbpf, not installing sysctl monitor: %m");
×
116

117
        r = cg_pid_get_path(0, &cgroup);
446✔
118
        if (r < 0)
446✔
119
                return log_warning_errno(r, "Failed to get cgroup path, ignoring: %m.");
×
120

121
        root_cgroup_fd = cg_path_open("/");
446✔
122
        if (root_cgroup_fd < 0)
446✔
123
                return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m");
×
124

125
        obj = sysctl_monitor_bpf__open_and_load();
446✔
126
        if (!obj)
446✔
127
                return log_full_errno(errno == EINVAL ? LOG_DEBUG : LOG_INFO, errno,
59✔
128
                                      "Unable to load sysctl monitor BPF program, ignoring: %m");
129

130
        cgroup_fd = cg_path_open(cgroup);
387✔
131
        if (cgroup_fd < 0)
387✔
132
                return log_warning_errno(cgroup_fd, "Failed to open cgroup: %m");
×
133

134
        if (sym_bpf_map_update_elem(sym_bpf_map__fd(obj->maps.cgroup_map), &idx, &cgroup_fd, BPF_ANY))
387✔
135
                return log_warning_errno(errno, "Failed to update cgroup map: %m");
×
136

137
        sysctl_link = sym_bpf_program__attach_cgroup(obj->progs.sysctl_monitor, root_cgroup_fd);
387✔
138
        r = bpf_get_error_translated(sysctl_link);
387✔
139
        if (r < 0)
387✔
140
                return log_warning_errno(r, "Unable to attach sysctl monitor BPF program to cgroup, ignoring: %m");
×
141

142
        fd = sym_bpf_map__fd(obj->maps.written_sysctls);
387✔
143
        if (fd < 0)
387✔
144
                return log_warning_errno(fd, "Failed to get fd of sysctl maps: %m");
×
145

146
        sysctl_buffer = sym_ring_buffer__new(fd, sysctl_event_handler, &manager->sysctl_shadow, NULL);
387✔
147
        if (!sysctl_buffer)
387✔
148
                return log_warning_errno(errno, "Failed to create ring buffer: %m");
×
149

150
        fd = sym_ring_buffer__epoll_fd(sysctl_buffer);
387✔
151
        if (fd < 0)
387✔
152
                return log_warning_errno(fd, "Failed to get poll fd of ring buffer: %m");
×
153

154
        r = sd_event_add_io(manager->event, &manager->sysctl_event_source,
387✔
155
                            fd, EPOLLIN, on_ringbuf_io, sysctl_buffer);
156
        if (r < 0)
387✔
157
                return log_warning_errno(r, "Failed to watch sysctl event ringbuffer: %m");
×
158

159
        manager->sysctl_link = TAKE_PTR(sysctl_link);
387✔
160
        manager->sysctl_skel = TAKE_PTR(obj);
387✔
161
        manager->sysctl_buffer = TAKE_PTR(sysctl_buffer);
387✔
162
        manager->cgroup_fd = TAKE_FD(cgroup_fd);
387✔
163

164
        return 0;
387✔
165
}
166

167
void manager_remove_sysctl_monitor(Manager *manager) {
471✔
168
        assert(manager);
471✔
169

170
        manager->sysctl_event_source = sd_event_source_disable_unref(manager->sysctl_event_source);
471✔
171
        manager->sysctl_buffer = bpf_ring_buffer_free(manager->sysctl_buffer);
471✔
172
        manager->sysctl_link = bpf_link_free(manager->sysctl_link);
471✔
173
        manager->sysctl_skel = sysctl_monitor_bpf_free(manager->sysctl_skel);
471✔
174
        manager->cgroup_fd = safe_close(manager->cgroup_fd);
471✔
175
        manager->sysctl_shadow = hashmap_free(manager->sysctl_shadow);
471✔
176
}
471✔
177

178
int link_clear_sysctl_shadows(Link *link) {
2,808✔
179
        _cleanup_free_ char *ipv4 = NULL, *ipv6 = NULL;
2,808✔
180
        char *key = NULL, *value = NULL;
2,808✔
181

182
        assert(link);
2,808✔
183
        assert(link->manager);
2,808✔
184

185
        ipv4 = path_join("/proc/sys/net/ipv4/conf", link->ifname);
2,808✔
186
        if (!ipv4)
2,808✔
187
                return log_oom();
×
188

189
        ipv6 = path_join("/proc/sys/net/ipv6/conf", link->ifname);
2,808✔
190
        if (!ipv6)
2,808✔
191
                return log_oom();
×
192

193
        HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow)
9,666✔
194
                if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) {
6,858✔
195
                        assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value));
3,078✔
196
                        free(key);
3,078✔
197
                        free(value);
3,078✔
198
                }
199

200
        return 0;
2,808✔
201
}
202
#endif
203

204
static void manager_set_ip_forwarding(Manager *manager, int family) {
896✔
205
        int r, t;
896✔
206

207
        assert(manager);
896✔
208
        assert(IN_SET(family, AF_INET, AF_INET6));
896✔
209

210
        if (family == AF_INET6 && !socket_ipv6_is_supported())
896✔
211
                return;
212

213
        t = manager->ip_forwarding[family == AF_INET6];
896✔
214
        if (t < 0)
896✔
215
                return; /* keep */
216

217
        /* First, set the default value. */
218
        r = sysctl_write_ip_property_boolean(family, "default", "forwarding", t, manager_get_sysctl_shadow(manager));
4✔
219
        if (r < 0)
4✔
220
                log_warning_errno(r, "Failed to %s the default %s forwarding: %m",
×
221
                                  enable_disable(t), af_to_ipv4_ipv6(family));
222

223
        /* Then, set the value to all interfaces. */
224
        r = sysctl_write_ip_property_boolean(family, "all", "forwarding", t, manager_get_sysctl_shadow(manager));
4✔
225
        if (r < 0)
4✔
226
                log_warning_errno(r, "Failed to %s %s forwarding for all interfaces: %m",
×
227
                                  enable_disable(t), af_to_ipv4_ipv6(family));
228
}
229

230
void manager_set_sysctl(Manager *manager) {
446✔
231
        assert(manager);
446✔
232
        assert(!manager->test_mode);
446✔
233

234
        manager_set_ip_forwarding(manager, AF_INET);
446✔
235
        manager_set_ip_forwarding(manager, AF_INET6);
446✔
236
}
446✔
237

238
static bool link_is_configured_for_family(Link *link, int family) {
17,847✔
239
        assert(link);
17,847✔
240

241
        if (!link->network)
17,847✔
242
                return false;
243

244
        if (link->flags & IFF_LOOPBACK)
17,847✔
245
                return false;
246

247
        /* CAN devices do not support IP layer. Most of the functions below are never called for CAN devices,
248
         * but link_set_ipv6_mtu() may be called after setting interface MTU, and warn about the failure. For
249
         * safety, let's unconditionally check if the interface is not a CAN device. */
250
        if (IN_SET(family, AF_INET, AF_INET6, AF_MPLS) && link->iftype == ARPHRD_CAN)
17,847✔
251
                return false;
252

253
        if (family == AF_INET6 && !socket_ipv6_is_supported())
17,843✔
254
                return false;
×
255

256
        return true;
257
}
258

259
static int link_update_ipv6_sysctl(Link *link) {
855✔
260
        assert(link);
855✔
261
        assert(link->manager);
855✔
262

263
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
264
                return 0;
265

266
        if (!link_ipv6_enabled(link))
855✔
267
                return 0;
268

269
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false, manager_get_sysctl_shadow(link->manager));
791✔
270
}
271

272
static int link_set_proxy_arp(Link *link) {
855✔
273
        assert(link);
855✔
274
        assert(link->manager);
855✔
275

276
        if (!link_is_configured_for_family(link, AF_INET))
855✔
277
                return 0;
278

279
        if (link->network->proxy_arp < 0)
855✔
280
                return 0;
281

282
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0, manager_get_sysctl_shadow(link->manager));
2✔
283
}
284

285
static int link_set_proxy_arp_pvlan(Link *link) {
855✔
286
        assert(link);
855✔
287
        assert(link->manager);
855✔
288

289
        if (!link_is_configured_for_family(link, AF_INET))
855✔
290
                return 0;
291

292
        if (link->network->proxy_arp_pvlan < 0)
855✔
293
                return 0;
294

295
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp_pvlan", link->network->proxy_arp_pvlan > 0, manager_get_sysctl_shadow(link->manager));
2✔
296
}
297

298
int link_get_ip_forwarding(Link *link, int family) {
2,299✔
299
        assert(link);
2,299✔
300
        assert(link->manager);
2,299✔
301
        assert(link->network);
2,299✔
302
        assert(IN_SET(family, AF_INET, AF_INET6));
2,299✔
303

304
        /* If it is explicitly specified, then honor the setting. */
305
        int t = link->network->ip_forwarding[family == AF_INET6];
2,299✔
306
        if (t >= 0)
2,299✔
307
                return t;
308

309
        /* If IPMasquerade= is enabled, also enable IP forwarding. */
310
        if (FLAGS_SET(link->network->ip_masquerade, AF_TO_ADDRESS_FAMILY(family)))
3,616✔
311
                return true;
312

313
        /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
314
        if (family == AF_INET6 && link_radv_enabled(link))
2,198✔
315
                return true;
316

317
        /* Otherwise, use the global setting. */
318
        return link->manager->ip_forwarding[family == AF_INET6];
2,165✔
319
}
320

321
static int link_set_ip_forwarding_impl(Link *link, int family) {
1,712✔
322
        int r, t;
1,712✔
323

324
        assert(link);
1,712✔
325
        assert(link->manager);
1,712✔
326
        assert(IN_SET(family, AF_INET, AF_INET6));
1,712✔
327

328
        if (!link_is_configured_for_family(link, family))
1,712✔
329
                return 0;
330

331
        t = link_get_ip_forwarding(link, family);
1,712✔
332
        if (t < 0)
1,712✔
333
                return 0; /* keep */
334

335
        r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t, manager_get_sysctl_shadow(link->manager));
123✔
336
        if (r < 0)
123✔
337
                return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
×
338
                                              enable_disable(t), af_to_ipv4_ipv6(family));
339

340
        return 0;
341
}
342

343
static int link_reapply_ip_forwarding(Link *link, int family) {
10✔
344
        int r, ret = 0;
10✔
345

346
        assert(link);
10✔
347
        assert(IN_SET(family, AF_INET, AF_INET6));
10✔
348

349
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
10✔
350
                return 0;
10✔
351

352
        (void) link_set_ip_forwarding_impl(link, family);
6✔
353

354
        r = link_lldp_tx_update_capabilities(link);
6✔
355
        if (r < 0)
6✔
356
                RET_GATHER(ret, log_link_warning_errno(link, r, "Could not update LLDP capabilities, ignoring: %m"));
×
357

358
        if (family == AF_INET6 && !link_ndisc_enabled(link)) {
6✔
359
                r = ndisc_stop(link);
3✔
360
                if (r < 0)
3✔
361
                        RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery, ignoring: %m"));
×
362

363
                ndisc_flush(link);
3✔
364
        }
365

366
        return ret;
367
}
368

369
static int link_set_ip_forwarding(Link *link, int family) {
1,710✔
370
        int r;
1,710✔
371

372
        assert(link);
1,710✔
373
        assert(link->manager);
1,710✔
374
        assert(link->network);
1,710✔
375
        assert(IN_SET(family, AF_INET, AF_INET6));
1,710✔
376

377
        if (!link_is_configured_for_family(link, family))
1,710✔
378
                return 0;
379

380
        /* When IPMasquerade= is enabled and the global setting is unset, enable _global_ IP forwarding, and
381
         * re-apply per-link setting for all links. */
382
        if (FLAGS_SET(link->network->ip_masquerade, AF_TO_ADDRESS_FAMILY(family)) &&
2,565✔
383
            link->manager->ip_forwarding[family == AF_INET6] < 0) {
30✔
384

385
                log_link_notice(link, "IPMasquerade= is enabled on the interface, enabling the global IPv6Forwarding= setting, which may affect NDisc and DHCPv6 client on other interfaces.");
4✔
386

387
                link->manager->ip_forwarding[family == AF_INET6] = true;
4✔
388
                manager_set_ip_forwarding(link->manager, family);
4✔
389

390
                Link *other;
4✔
391
                HASHMAP_FOREACH(other, link->manager->links_by_index) {
18✔
392
                        r = link_reapply_ip_forwarding(other, family);
10✔
393
                        if (r < 0)
10✔
394
                                link_enter_failed(other);
×
395
                }
396

397
                return 0;
4✔
398
        }
399

400
        /* Otherwise, apply per-link setting for _this_ link. */
401
        return link_set_ip_forwarding_impl(link, family);
1,706✔
402
}
403

404
static int link_set_ipv4_rp_filter(Link *link) {
855✔
405
        assert(link);
855✔
406
        assert(link->manager);
855✔
407

408
        if (!link_is_configured_for_family(link, AF_INET))
855✔
409
                return 0;
410

411
        if (link->network->ipv4_rp_filter < 0)
855✔
412
                return 0;
413

414
        return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter, manager_get_sysctl_shadow(link->manager));
2✔
415
}
416

417
static int link_set_ipv4_force_igmp_version(Link *link) {
855✔
418
        assert(link);
855✔
419

420
        if (!link_is_configured_for_family(link, AF_INET))
855✔
421
                return 0;
422

423
        if (link->network->ipv4_force_igmp_version < 0)
855✔
424
                return 0;
425

426
        return sysctl_write_ip_property_int(AF_INET, link->ifname, "force_igmp_version", link->network->ipv4_force_igmp_version, manager_get_sysctl_shadow(link->manager));
2✔
427
}
428

429
static int link_set_ipv6_privacy_extensions(Link *link) {
855✔
430
        IPv6PrivacyExtensions val;
855✔
431

432
        assert(link);
855✔
433
        assert(link->manager);
855✔
434

435
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
436
                return 0;
437

438
        val = link->network->ipv6_privacy_extensions;
855✔
439
        if (val < 0) /* If not specified, then use the global setting. */
855✔
440
                val = link->manager->ipv6_privacy_extensions;
830✔
441

442
        /* When "kernel", do not update the setting. */
443
        if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
855✔
444
                return 0;
445

446
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val, manager_get_sysctl_shadow(link->manager));
855✔
447
}
448

449
static int link_set_ipv6_accept_ra(Link *link) {
855✔
450
        assert(link);
855✔
451
        assert(link->manager);
855✔
452

453
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
454
                return 0;
455

456
        return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0", manager_get_sysctl_shadow(link->manager));
855✔
457
}
458

459
static int link_set_ipv6_dad_transmits(Link *link) {
855✔
460
        assert(link);
855✔
461
        assert(link->manager);
855✔
462

463
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
464
                return 0;
465

466
        if (link->network->ipv6_dad_transmits < 0)
855✔
467
                return 0;
468

469
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits, manager_get_sysctl_shadow(link->manager));
2✔
470
}
471

472
static int link_set_ipv6_hop_limit(Link *link) {
855✔
473
        assert(link);
855✔
474
        assert(link->manager);
855✔
475

476
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
477
                return 0;
478

479
        if (link->network->ipv6_hop_limit <= 0)
855✔
480
                return 0;
481

482
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit, manager_get_sysctl_shadow(link->manager));
2✔
483
}
484

485
static int link_set_ipv6_retransmission_time(Link *link) {
855✔
486
        usec_t retrans_time_ms;
855✔
487

488
        assert(link);
855✔
489
        assert(link->manager);
855✔
490

491
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
492
                return 0;
493

494
        if (!timestamp_is_set(link->network->ipv6_retransmission_time))
855✔
495
                return 0;
496

497
        retrans_time_ms = DIV_ROUND_UP(link->network->ipv6_retransmission_time, USEC_PER_MSEC);
2✔
498
         if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
2✔
499
                return 0;
500

501
        return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms, manager_get_sysctl_shadow(link->manager));
2✔
502
}
503

504
static int link_set_ipv6_proxy_ndp(Link *link) {
855✔
505
        bool v;
855✔
506

507
        assert(link);
855✔
508
        assert(link->manager);
855✔
509

510
        if (!link_is_configured_for_family(link, AF_INET6))
855✔
511
                return 0;
512

513
        if (link->network->ipv6_proxy_ndp >= 0)
855✔
514
                v = link->network->ipv6_proxy_ndp;
2✔
515
        else
516
                v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
853✔
517

518
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, manager_get_sysctl_shadow(link->manager));
855✔
519
}
520

521
int link_set_ipv6_mtu(Link *link, int log_level) {
1,600✔
522
        uint32_t mtu = 0;
1,600✔
523
        int r;
1,600✔
524

525
        assert(link);
1,600✔
526
        assert(link->manager);
1,600✔
527

528
        if (!link_is_configured_for_family(link, AF_INET6))
1,600✔
529
                return 0;
530

531
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1,596✔
532
                return 0;
533

534
        if (sd_event_source_get_enabled(link->ipv6_mtu_wait_synced_event_source, /* ret= */ NULL) > 0) {
1,596✔
535
                log_link_debug(link, "Waiting for IPv6 MTU is synced to link MTU, delaying to set IPv6 MTU.");
×
536
                return 0;
×
537
        }
538

539
        assert(link->network);
1,596✔
540

541
        if (link->network->ndisc_use_mtu)
1,596✔
542
                mtu = link->ndisc_mtu;
1,596✔
543
        if (mtu == 0)
1,596✔
544
                mtu = link->network->ipv6_mtu;
1,540✔
545
        if (mtu == 0)
1,540✔
546
                return 0;
547

548
        if (mtu > link->mtu) {
94✔
549
                log_link_full(link, log_level,
12✔
550
                              "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
551
                              mtu, link->mtu);
552
                mtu = link->mtu;
12✔
553
        }
554

555
        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
94✔
556
        if (r < 0)
94✔
557
                return log_link_warning_errno(link, r, "Failed to set IPv6 MTU to %"PRIu32": %m", mtu);
×
558

559
        return 0;
560
}
561

562
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata);
563

564
static int link_set_ipv6_mtu_async_impl(Link *link) {
45✔
565
        uint32_t current_mtu;
45✔
566
        int r;
45✔
567

568
        assert(link);
45✔
569

570
        /* When the link MTU is updated, it seems that the kernel IPv6 MTU of the interface is asynchronously
571
         * reset to the link MTU. Hence, we need to check if it is already reset, and wait for a while if not. */
572

573
        if (++link->ipv6_mtu_wait_trial_count >= 10) {
45✔
574
                log_link_debug(link, "Timed out waiting for IPv6 MTU being synced to link MTU, proceeding anyway.");
×
575
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
576
                if (r < 0)
×
577
                        return r;
45✔
578

579
                return 1; /* done */
×
580
        }
581

582
        /* Check if IPv6 MTU is synced. */
583
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
45✔
584
        if (r < 0)
45✔
585
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
1✔
586

587
        if (current_mtu == link->mtu) {
44✔
588
                /* Already synced. Update IPv6 MTU now. */
589
                r = link_set_ipv6_mtu(link, LOG_INFO);
44✔
590
                if (r < 0)
44✔
591
                        return r;
592

593
                return 1; /* done */
44✔
594
        }
595

596
        /* If not, set up a timer event source. */
597
        r = event_reset_time_relative(
×
598
                        link->manager->event, &link->ipv6_mtu_wait_synced_event_source,
×
599
                        CLOCK_BOOTTIME, 100 * USEC_PER_MSEC, 0,
600
                        ipv6_mtu_wait_synced_handler, link,
601
                        /* priority= */ 0, "ipv6-mtu-wait-synced", /* force_reset= */ true);
602
        if (r < 0)
×
603
                return log_link_warning_errno(link, r, "Failed to configure timer event source for waiting for IPv6 MTU being synced: %m");
×
604

605
        /* Check again. */
606
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
×
607
        if (r < 0)
×
608
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
×
609

610
        if (current_mtu == link->mtu) {
×
611
                /* Synced while setting up the timer event source. Disable it and update IPv6 MTU now. */
612
                r = sd_event_source_set_enabled(link->ipv6_mtu_wait_synced_event_source, SD_EVENT_OFF);
×
613
                if (r < 0)
×
614
                        log_link_debug_errno(link, r, "Failed to disable timer event source for IPv6 MTU, ignoring: %m");
×
615

616
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
617
                if (r < 0)
×
618
                        return r;
619

620
                return 1; /* done */
×
621
        }
622

623
        log_link_debug(link, "IPv6 MTU is not synced to the link MTU after it is changed. Waiting for a while.");
×
624
        return 0; /* waiting */
625
}
626

627
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata) {
×
628
        (void) link_set_ipv6_mtu_async_impl(ASSERT_PTR(userdata));
×
629
        return 0;
×
630
}
631

632
int link_set_ipv6_mtu_async(Link *link) {
45✔
633
        assert(link);
45✔
634

635
        link->ipv6_mtu_wait_trial_count = 0;
45✔
636
        return link_set_ipv6_mtu_async_impl(link);
45✔
637
}
638

639
static int link_set_ipv4_accept_local(Link *link) {
855✔
640
        assert(link);
855✔
641
        assert(link->manager);
855✔
642

643
        if (!link_is_configured_for_family(link, AF_INET))
855✔
644
                return 0;
645

646
        if (link->network->ipv4_accept_local < 0)
855✔
647
                return 0;
648

649
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0, manager_get_sysctl_shadow(link->manager));
2✔
650
}
651

652
static int link_set_ipv4_route_localnet(Link *link) {
855✔
653
        assert(link);
855✔
654
        assert(link->manager);
855✔
655

656
        if (!link_is_configured_for_family(link, AF_INET))
855✔
657
                return 0;
658

659
        if (link->network->ipv4_route_localnet < 0)
855✔
660
                return 0;
661

662
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, manager_get_sysctl_shadow(link->manager));
×
663
}
664

665
static int link_set_ipv4_promote_secondaries(Link *link) {
855✔
666
        assert(link);
855✔
667
        assert(link->manager);
855✔
668

669
        if (!link_is_configured_for_family(link, AF_INET))
855✔
670
                return 0;
671

672
        /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
673
         * changes between leases. The kernel will remove all secondary IP addresses of an interface
674
         * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
675
         * secondary IP and when the primary one expires it relies on the kernel to promote the
676
         * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
677
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true, manager_get_sysctl_shadow(link->manager));
855✔
678
}
679

680
static int link_set_mpls_input(Link *link) {
855✔
681
        assert(link);
855✔
682
        assert(link->manager);
855✔
683

684
        if (!link_is_configured_for_family(link, AF_MPLS))
855✔
685
                return 0;
686

687
        if (link->network->mpls_input < 0)
855✔
688
                return 0;
689

690
        return sysctl_write_ip_property_boolean(AF_MPLS, link->ifname, "input", link->network->mpls_input > 0, manager_get_sysctl_shadow(link->manager));
1✔
691
}
692

693
int link_set_sysctl(Link *link) {
855✔
694
        int r;
855✔
695

696
        assert(link);
855✔
697

698
        /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
699
         * for this interface, then enable IPv6 */
700
        r = link_update_ipv6_sysctl(link);
855✔
701
        if (r < 0)
855✔
702
                log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
×
703

704
        r = link_set_proxy_arp(link);
855✔
705
        if (r < 0)
855✔
706
               log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
×
707

708
        r = link_set_proxy_arp_pvlan(link);
855✔
709
        if (r < 0)
855✔
710
                log_link_warning_errno(link, r, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
×
711

712
        (void) link_set_ip_forwarding(link, AF_INET);
855✔
713
        (void) link_set_ip_forwarding(link, AF_INET6);
855✔
714

715
        r = link_set_ipv6_privacy_extensions(link);
855✔
716
        if (r < 0)
855✔
717
                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
×
718

719
        r = link_set_ipv6_accept_ra(link);
855✔
720
        if (r < 0)
855✔
721
                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
×
722

723
        r = link_set_ipv6_dad_transmits(link);
855✔
724
        if (r < 0)
855✔
725
                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
×
726

727
        r = link_set_ipv6_hop_limit(link);
855✔
728
        if (r < 0)
855✔
729
                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
×
730

731
        r = link_set_ipv6_retransmission_time(link);
855✔
732
        if (r < 0)
855✔
733
                log_link_warning_errno(link, r, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
×
734

735
        r = link_set_ipv6_proxy_ndp(link);
855✔
736
        if (r < 0)
855✔
737
                log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
×
738

739
        (void) link_set_ipv6_mtu(link, LOG_INFO);
855✔
740

741
        r = link_set_ipv6ll_stable_secret(link);
855✔
742
        if (r < 0)
855✔
743
                log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link-local address: %m");
×
744

745
        r = link_set_ipv4_accept_local(link);
855✔
746
        if (r < 0)
855✔
747
                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
×
748

749
        r = link_set_ipv4_route_localnet(link);
855✔
750
        if (r < 0)
855✔
751
                log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
×
752

753
        r = link_set_ipv4_rp_filter(link);
855✔
754
        if (r < 0)
855✔
755
                log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
×
756

757
        r = link_set_ipv4_force_igmp_version(link);
855✔
758
        if (r < 0)
855✔
759
                log_link_warning_errno(link, r, "Cannot set IPv4 force igmp version, ignoring: %m");
×
760

761
        r = link_set_ipv4_promote_secondaries(link);
855✔
762
        if (r < 0)
855✔
763
                log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");
×
764

765
        r = link_set_mpls_input(link);
855✔
766
        if (r < 0)
855✔
767
                log_link_warning_errno(link, r, "Cannot set MPLS input, ignoring: %m");
×
768

769
        return 0;
855✔
770
}
771

772
static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
773
        [IPV6_PRIVACY_EXTENSIONS_NO]            = "no",
774
        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
775
        [IPV6_PRIVACY_EXTENSIONS_YES]           = "yes",
776
        [IPV6_PRIVACY_EXTENSIONS_KERNEL]        = "kernel",
777
};
778

779
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
76✔
780
                                        IPV6_PRIVACY_EXTENSIONS_YES);
781
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions);
22✔
782

783
static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
784
        [IP_REVERSE_PATH_FILTER_NO]     = "no",
785
        [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
786
        [IP_REVERSE_PATH_FILTER_LOOSE]  = "loose",
787
};
788

789
DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
2✔
790
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter);
2✔
791

792
int config_parse_ip_forward_deprecated(
×
793
                const char *unit,
794
                const char *filename,
795
                unsigned line,
796
                const char *section,
797
                unsigned section_line,
798
                const char *lvalue,
799
                int ltype,
800
                const char *rvalue,
801
                void *data,
802
                void *userdata) {
803

804
        assert(filename);
×
805

806
        log_syntax(unit, LOG_WARNING, filename, line, 0,
×
807
                   "IPForward= setting is deprecated. "
808
                   "Please use IPv4Forwarding= and/or IPv6Forwarding= in networkd.conf for global setting, "
809
                   "and the same settings in .network files for per-interface setting.");
810
        return 0;
×
811
}
812

813
static const char* const ipv4_force_igmp_version_table[_IPV4_FORCE_IGMP_VERSION_MAX] = {
814
        [IPV4_FORCE_IGMP_VERSION_NO] = "no",
815
        [IPV4_FORCE_IGMP_VERSION_1]  = "v1",
816
        [IPV4_FORCE_IGMP_VERSION_2]  = "v2",
817
        [IPV4_FORCE_IGMP_VERSION_3]  = "v3",
818
};
819

820
DEFINE_STRING_TABLE_LOOKUP(ipv4_force_igmp_version, IPv4ForceIgmpVersion);
2✔
821
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv4_force_igmp_version, ipv4_force_igmp_version, IPv4ForceIgmpVersion);
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc