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

systemd / systemd / 19484860156

18 Nov 2025 10:54PM UTC coverage: 72.449% (-0.05%) from 72.503%
19484860156

push

github

web-flow
Improve systemd-analyze man page and bash completion (#39778)

This updates example output in systemd-analyze's man page after the
tool's output was changed in a previous commit.

Additionally bash completion is added for `systemd-analyze filesystems`
and improved for `systemd-analyze calendar`.

308071 of 425226 relevant lines covered (72.45%)

1286949.26 hits per line

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

81.77
/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 "conf-parser.h"
9
#include "alloc-util.h"
10
#include "cgroup-util.h"
11
#include "errno-util.h"
12
#include "event-util.h"
13
#include "fd-util.h"
14
#include "format-util.h"
15
#include "hashmap.h"
16
#include "networkd-link.h"
17
#include "networkd-lldp-tx.h"
18
#include "networkd-manager.h"
19
#include "networkd-ndisc.h"
20
#include "networkd-network.h"
21
#include "networkd-sysctl.h"
22
#include "path-util.h"
23
#include "set.h"
24
#include "socket-util.h"
25
#include "string-table.h"
26
#include "string-util.h"
27
#include "sysctl-util.h"
28

29
#if ENABLE_SYSCTL_BPF
30

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

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

40
DEFINE_TRIVIAL_CLEANUP_FUNC(struct sysctl_monitor_bpf *, sysctl_monitor_bpf_free);
442✔
41

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

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

54
        if (we->errorcode != 0) {
11✔
55
                log_warning_errno(we->errorcode, "Sysctl monitor BPF returned error: %m");
×
56
                return 0;
×
57
        }
58

59
        path = path_join("/proc/sys", we->path);
11✔
60
        if (!path) {
11✔
61
                log_oom_warning();
×
62
                return 0;
63
        }
64

65
        /* If we never managed this handle, ignore it. */
66
        value = hashmap_get(*sysctl_shadow, path);
11✔
67
        if (!value)
11✔
68
                return 0;
69

70
        if (!strneq(value, we->newvalue, sizeof(we->newvalue)))
×
71
                log_struct(LOG_WARNING,
×
72
                           LOG_MESSAGE_ID(SD_MESSAGE_SYSCTL_CHANGED_STR),
73
                           LOG_ITEM("OBJECT_PID=" PID_FMT, we->pid),
74
                           LOG_ITEM("OBJECT_COMM=%s", we->comm),
75
                           LOG_ITEM("SYSCTL=%s", path),
76
                           LOG_ITEM("OLDVALUE=%s", we->current),
77
                           LOG_ITEM("NEWVALUE=%s", we->newvalue),
78
                           LOG_ITEM("OURVALUE=%s", value),
79
                           LOG_MESSAGE("Foreign process '%s[" PID_FMT "]' changed sysctl '%s' from '%s' to '%s', conflicting with our setting to '%s'.",
80
                                       we->comm, we->pid, path, we->current, we->newvalue, value));
81

82
        return 0;
83
}
84

85
static int on_ringbuf_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
8✔
86
        struct ring_buffer *rb = ASSERT_PTR(userdata);
8✔
87
        int r;
8✔
88

89
        r = sym_ring_buffer__poll(rb, /* timeout_msec= */ 0);
8✔
90
        if (r < 0 && errno != EINTR)
8✔
91
                log_error_errno(errno, "Error polling ring buffer: %m");
×
92

93
        return 0;
8✔
94
}
95

96
int manager_install_sysctl_monitor(Manager *manager) {
442✔
97
        _cleanup_(sysctl_monitor_bpf_freep) struct sysctl_monitor_bpf *obj = NULL;
442✔
98
        _cleanup_(bpf_link_freep) struct bpf_link *sysctl_link = NULL;
442✔
99
        _cleanup_(bpf_ring_buffer_freep) struct ring_buffer *sysctl_buffer = NULL;
×
100
        _cleanup_close_ int cgroup_fd = -EBADF, root_cgroup_fd = -EBADF;
884✔
101
        _cleanup_free_ char *cgroup = NULL;
442✔
102
        int idx = 0, r, fd;
442✔
103

104
        assert(manager);
442✔
105

106
        r = dlopen_bpf();
442✔
107
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
442✔
108
                return log_debug_errno(r, "sysctl monitor disabled, as BPF support is not available.");
×
109
        if (r < 0)
442✔
110
                return log_warning_errno(r, "Failed to load libbpf, not installing sysctl monitor: %m");
×
111

112
        r = cg_pid_get_path(0, &cgroup);
442✔
113
        if (r < 0)
442✔
114
                return log_warning_errno(r, "Failed to get cgroup path, ignoring: %m.");
×
115

116
        root_cgroup_fd = cg_path_open("/");
442✔
117
        if (root_cgroup_fd < 0)
442✔
118
                return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m");
×
119

120
        obj = sysctl_monitor_bpf__open_and_load();
442✔
121
        if (!obj)
442✔
122
                return log_full_errno(errno == EINVAL ? LOG_DEBUG : LOG_INFO, errno,
59✔
123
                                      "Unable to load sysctl monitor BPF program, ignoring: %m");
124

125
        cgroup_fd = cg_path_open(cgroup);
383✔
126
        if (cgroup_fd < 0)
383✔
127
                return log_warning_errno(cgroup_fd, "Failed to open cgroup: %m");
×
128

129
        if (sym_bpf_map_update_elem(sym_bpf_map__fd(obj->maps.cgroup_map), &idx, &cgroup_fd, BPF_ANY))
383✔
130
                return log_warning_errno(errno, "Failed to update cgroup map: %m");
×
131

132
        sysctl_link = sym_bpf_program__attach_cgroup(obj->progs.sysctl_monitor, root_cgroup_fd);
383✔
133
        r = bpf_get_error_translated(sysctl_link);
383✔
134
        if (r < 0)
383✔
135
                return log_warning_errno(r, "Unable to attach sysctl monitor BPF program to cgroup, ignoring: %m");
×
136

137
        fd = sym_bpf_map__fd(obj->maps.written_sysctls);
383✔
138
        if (fd < 0)
383✔
139
                return log_warning_errno(fd, "Failed to get fd of sysctl maps: %m");
×
140

141
        sysctl_buffer = sym_ring_buffer__new(fd, sysctl_event_handler, &manager->sysctl_shadow, NULL);
383✔
142
        if (!sysctl_buffer)
383✔
143
                return log_warning_errno(errno, "Failed to create ring buffer: %m");
×
144

145
        fd = sym_ring_buffer__epoll_fd(sysctl_buffer);
383✔
146
        if (fd < 0)
383✔
147
                return log_warning_errno(fd, "Failed to get poll fd of ring buffer: %m");
×
148

149
        r = sd_event_add_io(manager->event, &manager->sysctl_event_source,
383✔
150
                            fd, EPOLLIN, on_ringbuf_io, sysctl_buffer);
151
        if (r < 0)
383✔
152
                return log_warning_errno(r, "Failed to watch sysctl event ringbuffer: %m");
×
153

154
        manager->sysctl_link = TAKE_PTR(sysctl_link);
383✔
155
        manager->sysctl_skel = TAKE_PTR(obj);
383✔
156
        manager->sysctl_buffer = TAKE_PTR(sysctl_buffer);
383✔
157
        manager->cgroup_fd = TAKE_FD(cgroup_fd);
383✔
158

159
        return 0;
383✔
160
}
161

162
void manager_remove_sysctl_monitor(Manager *manager) {
467✔
163
        assert(manager);
467✔
164

165
        manager->sysctl_event_source = sd_event_source_disable_unref(manager->sysctl_event_source);
467✔
166
        manager->sysctl_buffer = bpf_ring_buffer_free(manager->sysctl_buffer);
467✔
167
        manager->sysctl_link = bpf_link_free(manager->sysctl_link);
467✔
168
        manager->sysctl_skel = sysctl_monitor_bpf_free(manager->sysctl_skel);
467✔
169
        manager->cgroup_fd = safe_close(manager->cgroup_fd);
467✔
170
        manager->sysctl_shadow = hashmap_free(manager->sysctl_shadow);
467✔
171
}
467✔
172

173
int link_clear_sysctl_shadows(Link *link) {
2,787✔
174
        _cleanup_free_ char *ipv4 = NULL, *ipv6 = NULL;
2,787✔
175
        char *key = NULL, *value = NULL;
2,787✔
176

177
        assert(link);
2,787✔
178
        assert(link->manager);
2,787✔
179

180
        ipv4 = path_join("/proc/sys/net/ipv4/conf", link->ifname);
2,787✔
181
        if (!ipv4)
2,787✔
182
                return log_oom();
×
183

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

188
        HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow)
9,748✔
189
                if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) {
6,961✔
190
                        assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value));
3,096✔
191
                        free(key);
3,096✔
192
                        free(value);
3,096✔
193
                }
194

195
        return 0;
2,787✔
196
}
197
#endif
198

199
static void manager_set_ip_forwarding(Manager *manager, int family) {
888✔
200
        int r, t;
888✔
201

202
        assert(manager);
888✔
203
        assert(IN_SET(family, AF_INET, AF_INET6));
888✔
204

205
        if (family == AF_INET6 && !socket_ipv6_is_supported())
888✔
206
                return;
207

208
        t = manager->ip_forwarding[family == AF_INET6];
888✔
209
        if (t < 0)
888✔
210
                return; /* keep */
211

212
        /* First, set the default value. */
213
        r = sysctl_write_ip_property_boolean(family, "default", "forwarding", t, manager_get_sysctl_shadow(manager));
4✔
214
        if (r < 0)
4✔
215
                log_warning_errno(r, "Failed to %s the default %s forwarding: %m",
×
216
                                  enable_disable(t), af_to_ipv4_ipv6(family));
217

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

225
void manager_set_sysctl(Manager *manager) {
442✔
226
        assert(manager);
442✔
227
        assert(!manager->test_mode);
442✔
228

229
        manager_set_ip_forwarding(manager, AF_INET);
442✔
230
        manager_set_ip_forwarding(manager, AF_INET6);
442✔
231
}
442✔
232

233
static bool link_is_configured_for_family(Link *link, int family) {
17,946✔
234
        assert(link);
17,946✔
235

236
        if (!link->network)
17,946✔
237
                return false;
238

239
        if (link->flags & IFF_LOOPBACK)
17,946✔
240
                return false;
241

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

248
        if (family == AF_INET6 && !socket_ipv6_is_supported())
17,942✔
249
                return false;
×
250

251
        return true;
252
}
253

254
static int link_update_ipv6_sysctl(Link *link) {
860✔
255
        assert(link);
860✔
256
        assert(link->manager);
860✔
257

258
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
259
                return 0;
260

261
        if (!link_ipv6_enabled(link))
860✔
262
                return 0;
263

264
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false, manager_get_sysctl_shadow(link->manager));
790✔
265
}
266

267
static int link_set_proxy_arp(Link *link) {
860✔
268
        assert(link);
860✔
269
        assert(link->manager);
860✔
270

271
        if (!link_is_configured_for_family(link, AF_INET))
860✔
272
                return 0;
273

274
        if (link->network->proxy_arp < 0)
860✔
275
                return 0;
276

277
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0, manager_get_sysctl_shadow(link->manager));
2✔
278
}
279

280
static int link_set_proxy_arp_pvlan(Link *link) {
860✔
281
        assert(link);
860✔
282
        assert(link->manager);
860✔
283

284
        if (!link_is_configured_for_family(link, AF_INET))
860✔
285
                return 0;
286

287
        if (link->network->proxy_arp_pvlan < 0)
860✔
288
                return 0;
289

290
        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✔
291
}
292

293
int link_get_ip_forwarding(Link *link, int family) {
2,297✔
294
        assert(link);
2,297✔
295
        assert(link->manager);
2,297✔
296
        assert(link->network);
2,297✔
297
        assert(IN_SET(family, AF_INET, AF_INET6));
2,297✔
298

299
        /* If it is explicitly specified, then honor the setting. */
300
        int t = link->network->ip_forwarding[family == AF_INET6];
2,297✔
301
        if (t >= 0)
2,297✔
302
                return t;
303

304
        /* If IPMasquerade= is enabled, also enable IP forwarding. */
305
        if (FLAGS_SET(link->network->ip_masquerade, AF_TO_ADDRESS_FAMILY(family)))
3,606✔
306
                return true;
307

308
        /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
309
        if (family == AF_INET6 && link_radv_enabled(link))
2,196✔
310
                return true;
311

312
        /* Otherwise, use the global setting. */
313
        return link->manager->ip_forwarding[family == AF_INET6];
2,163✔
314
}
315

316
static int link_set_ip_forwarding_impl(Link *link, int family) {
1,722✔
317
        int r, t;
1,722✔
318

319
        assert(link);
1,722✔
320
        assert(link->manager);
1,722✔
321
        assert(IN_SET(family, AF_INET, AF_INET6));
1,722✔
322

323
        if (!link_is_configured_for_family(link, family))
1,722✔
324
                return 0;
325

326
        t = link_get_ip_forwarding(link, family);
1,722✔
327
        if (t < 0)
1,722✔
328
                return 0; /* keep */
329

330
        r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t, manager_get_sysctl_shadow(link->manager));
123✔
331
        if (r < 0)
123✔
332
                return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
×
333
                                              enable_disable(t), af_to_ipv4_ipv6(family));
334

335
        return 0;
336
}
337

338
static int link_reapply_ip_forwarding(Link *link, int family) {
10✔
339
        int r, ret = 0;
10✔
340

341
        assert(link);
10✔
342
        assert(IN_SET(family, AF_INET, AF_INET6));
10✔
343

344
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
10✔
345
                return 0;
10✔
346

347
        (void) link_set_ip_forwarding_impl(link, family);
6✔
348

349
        r = link_lldp_tx_update_capabilities(link);
6✔
350
        if (r < 0)
6✔
351
                RET_GATHER(ret, log_link_warning_errno(link, r, "Could not update LLDP capabilities, ignoring: %m"));
×
352

353
        if (family == AF_INET6 && !link_ndisc_enabled(link)) {
6✔
354
                r = ndisc_stop(link);
3✔
355
                if (r < 0)
3✔
356
                        RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery, ignoring: %m"));
×
357

358
                ndisc_flush(link);
3✔
359
        }
360

361
        return ret;
362
}
363

364
static int link_set_ip_forwarding(Link *link, int family) {
1,720✔
365
        int r;
1,720✔
366

367
        assert(link);
1,720✔
368
        assert(link->manager);
1,720✔
369
        assert(link->network);
1,720✔
370
        assert(IN_SET(family, AF_INET, AF_INET6));
1,720✔
371

372
        if (!link_is_configured_for_family(link, family))
1,720✔
373
                return 0;
374

375
        /* When IPMasquerade= is enabled and the global setting is unset, enable _global_ IP forwarding, and
376
         * re-apply per-link setting for all links. */
377
        if (FLAGS_SET(link->network->ip_masquerade, AF_TO_ADDRESS_FAMILY(family)) &&
2,580✔
378
            link->manager->ip_forwarding[family == AF_INET6] < 0) {
30✔
379

380
                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✔
381

382
                link->manager->ip_forwarding[family == AF_INET6] = true;
4✔
383
                manager_set_ip_forwarding(link->manager, family);
4✔
384

385
                Link *other;
4✔
386
                HASHMAP_FOREACH(other, link->manager->links_by_index) {
18✔
387
                        r = link_reapply_ip_forwarding(other, family);
10✔
388
                        if (r < 0)
10✔
389
                                link_enter_failed(other);
×
390
                }
391

392
                return 0;
4✔
393
        }
394

395
        /* Otherwise, apply per-link setting for _this_ link. */
396
        return link_set_ip_forwarding_impl(link, family);
1,716✔
397
}
398

399
static int link_set_ipv4_rp_filter(Link *link) {
860✔
400
        assert(link);
860✔
401
        assert(link->manager);
860✔
402

403
        if (!link_is_configured_for_family(link, AF_INET))
860✔
404
                return 0;
405

406
        if (link->network->ipv4_rp_filter < 0)
860✔
407
                return 0;
408

409
        return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter, manager_get_sysctl_shadow(link->manager));
2✔
410
}
411

412
static int link_set_ipv4_force_igmp_version(Link *link) {
860✔
413
        assert(link);
860✔
414

415
        if (!link_is_configured_for_family(link, AF_INET))
860✔
416
                return 0;
417

418
        if (link->network->ipv4_force_igmp_version < 0)
860✔
419
                return 0;
420

421
        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✔
422
}
423

424
static int link_set_ipv6_privacy_extensions(Link *link) {
860✔
425
        IPv6PrivacyExtensions val;
860✔
426

427
        assert(link);
860✔
428
        assert(link->manager);
860✔
429

430
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
431
                return 0;
432

433
        val = link->network->ipv6_privacy_extensions;
860✔
434
        if (val < 0) /* If not specified, then use the global setting. */
860✔
435
                val = link->manager->ipv6_privacy_extensions;
835✔
436

437
        /* When "kernel", do not update the setting. */
438
        if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
860✔
439
                return 0;
440

441
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val, manager_get_sysctl_shadow(link->manager));
860✔
442
}
443

444
static int link_set_ipv6_accept_ra(Link *link) {
860✔
445
        assert(link);
860✔
446
        assert(link->manager);
860✔
447

448
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
449
                return 0;
450

451
        return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0", manager_get_sysctl_shadow(link->manager));
860✔
452
}
453

454
static int link_set_ipv6_dad_transmits(Link *link) {
860✔
455
        assert(link);
860✔
456
        assert(link->manager);
860✔
457

458
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
459
                return 0;
460

461
        if (link->network->ipv6_dad_transmits < 0)
860✔
462
                return 0;
463

464
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits, manager_get_sysctl_shadow(link->manager));
2✔
465
}
466

467
static int link_set_ipv6_hop_limit(Link *link) {
860✔
468
        assert(link);
860✔
469
        assert(link->manager);
860✔
470

471
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
472
                return 0;
473

474
        if (link->network->ipv6_hop_limit <= 0)
860✔
475
                return 0;
476

477
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit, manager_get_sysctl_shadow(link->manager));
2✔
478
}
479

480
static int link_set_ipv6_retransmission_time(Link *link) {
860✔
481
        usec_t retrans_time_ms;
860✔
482

483
        assert(link);
860✔
484
        assert(link->manager);
860✔
485

486
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
487
                return 0;
488

489
        if (!timestamp_is_set(link->network->ipv6_retransmission_time))
860✔
490
                return 0;
491

492
        retrans_time_ms = DIV_ROUND_UP(link->network->ipv6_retransmission_time, USEC_PER_MSEC);
2✔
493
         if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
2✔
494
                return 0;
495

496
        return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms, manager_get_sysctl_shadow(link->manager));
2✔
497
}
498

499
static int link_set_ipv6_proxy_ndp(Link *link) {
860✔
500
        bool v;
860✔
501

502
        assert(link);
860✔
503
        assert(link->manager);
860✔
504

505
        if (!link_is_configured_for_family(link, AF_INET6))
860✔
506
                return 0;
507

508
        if (link->network->ipv6_proxy_ndp >= 0)
860✔
509
                v = link->network->ipv6_proxy_ndp;
2✔
510
        else
511
                v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
858✔
512

513
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, manager_get_sysctl_shadow(link->manager));
860✔
514
}
515

516
int link_set_ipv6_mtu(Link *link, int log_level) {
1,604✔
517
        uint32_t mtu = 0;
1,604✔
518
        int r;
1,604✔
519

520
        assert(link);
1,604✔
521
        assert(link->manager);
1,604✔
522

523
        if (!link_is_configured_for_family(link, AF_INET6))
1,604✔
524
                return 0;
525

526
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1,600✔
527
                return 0;
528

529
        if (sd_event_source_get_enabled(link->ipv6_mtu_wait_synced_event_source, /* ret = */ NULL) > 0) {
1,600✔
530
                log_link_debug(link, "Waiting for IPv6 MTU is synced to link MTU, delaying to set IPv6 MTU.");
×
531
                return 0;
×
532
        }
533

534
        assert(link->network);
1,600✔
535

536
        if (link->network->ndisc_use_mtu)
1,600✔
537
                mtu = link->ndisc_mtu;
1,600✔
538
        if (mtu == 0)
1,600✔
539
                mtu = link->network->ipv6_mtu;
1,546✔
540
        if (mtu == 0)
1,546✔
541
                return 0;
542

543
        if (mtu > link->mtu) {
89✔
544
                log_link_full(link, log_level,
11✔
545
                              "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
546
                              mtu, link->mtu);
547
                mtu = link->mtu;
11✔
548
        }
549

550
        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
89✔
551
        if (r < 0)
89✔
552
                return log_link_warning_errno(link, r, "Failed to set IPv6 MTU to %"PRIu32": %m", mtu);
×
553

554
        return 0;
555
}
556

557
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata);
558

559
static int link_set_ipv6_mtu_async_impl(Link *link) {
46✔
560
        uint32_t current_mtu;
46✔
561
        int r;
46✔
562

563
        assert(link);
46✔
564

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

568
        if (++link->ipv6_mtu_wait_trial_count >= 10) {
46✔
569
                log_link_debug(link, "Timed out waiting for IPv6 MTU being synced to link MTU, proceeding anyway.");
×
570
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
571
                if (r < 0)
×
572
                        return r;
46✔
573

574
                return 1; /* done */
×
575
        }
576

577
        /* Check if IPv6 MTU is synced. */
578
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
46✔
579
        if (r < 0)
46✔
580
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
1✔
581

582
        if (current_mtu == link->mtu) {
45✔
583
                /* Already synced. Update IPv6 MTU now. */
584
                r = link_set_ipv6_mtu(link, LOG_INFO);
45✔
585
                if (r < 0)
45✔
586
                        return r;
587

588
                return 1; /* done */
45✔
589
        }
590

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

600
        /* Check again. */
601
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
×
602
        if (r < 0)
×
603
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
×
604

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

611
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
612
                if (r < 0)
×
613
                        return r;
614

615
                return 1; /* done */
×
616
        }
617

618
        log_link_debug(link, "IPv6 MTU is not synced to the link MTU after it is changed. Waiting for a while.");
×
619
        return 0; /* waiting */
620
}
621

622
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata) {
×
623
        (void) link_set_ipv6_mtu_async_impl(ASSERT_PTR(userdata));
×
624
        return 0;
×
625
}
626

627
int link_set_ipv6_mtu_async(Link *link) {
46✔
628
        assert(link);
46✔
629

630
        link->ipv6_mtu_wait_trial_count = 0;
46✔
631
        return link_set_ipv6_mtu_async_impl(link);
46✔
632
}
633

634
static int link_set_ipv4_accept_local(Link *link) {
860✔
635
        assert(link);
860✔
636
        assert(link->manager);
860✔
637

638
        if (!link_is_configured_for_family(link, AF_INET))
860✔
639
                return 0;
640

641
        if (link->network->ipv4_accept_local < 0)
860✔
642
                return 0;
643

644
        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✔
645
}
646

647
static int link_set_ipv4_route_localnet(Link *link) {
860✔
648
        assert(link);
860✔
649
        assert(link->manager);
860✔
650

651
        if (!link_is_configured_for_family(link, AF_INET))
860✔
652
                return 0;
653

654
        if (link->network->ipv4_route_localnet < 0)
860✔
655
                return 0;
656

657
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, manager_get_sysctl_shadow(link->manager));
×
658
}
659

660
static int link_set_ipv4_promote_secondaries(Link *link) {
860✔
661
        assert(link);
860✔
662
        assert(link->manager);
860✔
663

664
        if (!link_is_configured_for_family(link, AF_INET))
860✔
665
                return 0;
666

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

675
static int link_set_mpls_input(Link *link) {
860✔
676
        assert(link);
860✔
677
        assert(link->manager);
860✔
678

679
        if (!link_is_configured_for_family(link, AF_MPLS))
860✔
680
                return 0;
681

682
        if (link->network->mpls_input < 0)
860✔
683
                return 0;
684

685
        return sysctl_write_ip_property_boolean(AF_MPLS, link->ifname, "input", link->network->mpls_input > 0, manager_get_sysctl_shadow(link->manager));
1✔
686
}
687

688
int link_set_sysctl(Link *link) {
860✔
689
        int r;
860✔
690

691
        assert(link);
860✔
692

693
        /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
694
         * for this interface, then enable IPv6 */
695
        r = link_update_ipv6_sysctl(link);
860✔
696
        if (r < 0)
860✔
697
                log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
×
698

699
        r = link_set_proxy_arp(link);
860✔
700
        if (r < 0)
860✔
701
               log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
×
702

703
        r = link_set_proxy_arp_pvlan(link);
860✔
704
        if (r < 0)
860✔
705
                log_link_warning_errno(link, r, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
×
706

707
        (void) link_set_ip_forwarding(link, AF_INET);
860✔
708
        (void) link_set_ip_forwarding(link, AF_INET6);
860✔
709

710
        r = link_set_ipv6_privacy_extensions(link);
860✔
711
        if (r < 0)
860✔
712
                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
×
713

714
        r = link_set_ipv6_accept_ra(link);
860✔
715
        if (r < 0)
860✔
716
                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
×
717

718
        r = link_set_ipv6_dad_transmits(link);
860✔
719
        if (r < 0)
860✔
720
                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
×
721

722
        r = link_set_ipv6_hop_limit(link);
860✔
723
        if (r < 0)
860✔
724
                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
×
725

726
        r = link_set_ipv6_retransmission_time(link);
860✔
727
        if (r < 0)
860✔
728
                log_link_warning_errno(link, r, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
×
729

730
        r = link_set_ipv6_proxy_ndp(link);
860✔
731
        if (r < 0)
860✔
732
                log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
×
733

734
        (void) link_set_ipv6_mtu(link, LOG_INFO);
860✔
735

736
        r = link_set_ipv6ll_stable_secret(link);
860✔
737
        if (r < 0)
860✔
738
                log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link-local address: %m");
×
739

740
        r = link_set_ipv4_accept_local(link);
860✔
741
        if (r < 0)
860✔
742
                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
×
743

744
        r = link_set_ipv4_route_localnet(link);
860✔
745
        if (r < 0)
860✔
746
                log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
×
747

748
        r = link_set_ipv4_rp_filter(link);
860✔
749
        if (r < 0)
860✔
750
                log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
×
751

752
        r = link_set_ipv4_force_igmp_version(link);
860✔
753
        if (r < 0)
860✔
754
                log_link_warning_errno(link, r, "Cannot set IPv4 force igmp version, ignoring: %m");
×
755

756
        r = link_set_ipv4_promote_secondaries(link);
860✔
757
        if (r < 0)
860✔
758
                log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");
×
759

760
        r = link_set_mpls_input(link);
860✔
761
        if (r < 0)
860✔
762
                log_link_warning_errno(link, r, "Cannot set MPLS input, ignoring: %m");
×
763

764
        return 0;
860✔
765
}
766

767
static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
768
        [IPV6_PRIVACY_EXTENSIONS_NO]            = "no",
769
        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
770
        [IPV6_PRIVACY_EXTENSIONS_YES]           = "yes",
771
        [IPV6_PRIVACY_EXTENSIONS_KERNEL]        = "kernel",
772
};
773

774
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
76✔
775
                                        IPV6_PRIVACY_EXTENSIONS_YES);
776
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions);
22✔
777

778
static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
779
        [IP_REVERSE_PATH_FILTER_NO]     = "no",
780
        [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
781
        [IP_REVERSE_PATH_FILTER_LOOSE]  = "loose",
782
};
783

784
DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
2✔
785
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter);
2✔
786

787
int config_parse_ip_forward_deprecated(
×
788
                const char *unit,
789
                const char *filename,
790
                unsigned line,
791
                const char *section,
792
                unsigned section_line,
793
                const char *lvalue,
794
                int ltype,
795
                const char *rvalue,
796
                void *data,
797
                void *userdata) {
798

799
        assert(filename);
×
800

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

808
static const char* const ipv4_force_igmp_version_table[_IPV4_FORCE_IGMP_VERSION_MAX] = {
809
        [IPV4_FORCE_IGMP_VERSION_NO] = "no",
810
        [IPV4_FORCE_IGMP_VERSION_1]  = "v1",
811
        [IPV4_FORCE_IGMP_VERSION_2]  = "v2",
812
        [IPV4_FORCE_IGMP_VERSION_3]  = "v3",
813
};
814

815
DEFINE_STRING_TABLE_LOOKUP(ipv4_force_igmp_version, IPv4ForceIgmpVersion);
2✔
816
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