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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

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

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

3
#include <netinet/in.h>
4
#include <linux/if.h>
5
#include <linux/if_arp.h>
6

7
#include "sd-messages.h"
8

9
#include "af-list.h"
10
#include "cgroup-util.h"
11
#include "event-util.h"
12
#include "fd-util.h"
13
#include "format-util.h"
14
#include "missing_network.h"
15
#include "networkd-link.h"
16
#include "networkd-lldp-tx.h"
17
#include "networkd-manager.h"
18
#include "networkd-ndisc.h"
19
#include "networkd-network.h"
20
#include "networkd-sysctl.h"
21
#include "path-util.h"
22
#include "socket-util.h"
23
#include "string-table.h"
24
#include "sysctl-util.h"
25

26
#if HAVE_VMLINUX_H
27

28
#include "bpf-link.h"
29

30
#include "bpf/sysctl_monitor/sysctl-monitor-skel.h"
31
#include "bpf/sysctl_monitor/sysctl-write-event.h"
32

33
static struct sysctl_monitor_bpf* sysctl_monitor_bpf_free(struct sysctl_monitor_bpf *obj) {
441✔
34
        sysctl_monitor_bpf__destroy(obj);
441✔
35
        return NULL;
441✔
36
}
37

38
DEFINE_TRIVIAL_CLEANUP_FUNC(struct sysctl_monitor_bpf *, sysctl_monitor_bpf_free);
417✔
39

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

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

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

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

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

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

80
        return 0;
81
}
82

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

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

91
        return 0;
1✔
92
}
93

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

102
        assert(manager);
417✔
103

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

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

114
        root_cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, "/");
417✔
115
        if (root_cgroup_fd < 0)
417✔
116
                return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m");
×
117

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

123
        cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, cgroup);
361✔
124
        if (cgroup_fd < 0)
361✔
125
                return log_warning_errno(cgroup_fd, "Failed to open cgroup: %m");
×
126

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

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

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

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

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

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

152
        manager->sysctl_link = TAKE_PTR(sysctl_link);
361✔
153
        manager->sysctl_skel = TAKE_PTR(obj);
361✔
154
        manager->sysctl_buffer = TAKE_PTR(sysctl_buffer);
361✔
155
        manager->cgroup_fd = TAKE_FD(cgroup_fd);
361✔
156

157
        return 0;
361✔
158
}
159

160
void manager_remove_sysctl_monitor(Manager *manager) {
441✔
161
        assert(manager);
441✔
162

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

171
int link_clear_sysctl_shadows(Link *link) {
2,601✔
172
        _cleanup_free_ char *ipv4 = NULL, *ipv6 = NULL;
2,601✔
173
        char *key = NULL, *value = NULL;
2,601✔
174

175
        assert(link);
2,601✔
176
        assert(link->manager);
2,601✔
177

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

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

186
        HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow)
8,313✔
187
                if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) {
5,712✔
188
                        assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value));
2,746✔
189
                        free(key);
2,746✔
190
                        free(value);
2,746✔
191
                }
192

193
        return 0;
2,601✔
194
}
195
#endif
196

197
static void manager_set_ip_forwarding(Manager *manager, int family) {
836✔
198
        int r, t;
836✔
199

200
        assert(manager);
836✔
201
        assert(IN_SET(family, AF_INET, AF_INET6));
836✔
202

203
        if (family == AF_INET6 && !socket_ipv6_is_supported())
836✔
204
                return;
205

206
        t = manager->ip_forwarding[family == AF_INET6];
836✔
207
        if (t < 0)
836✔
208
                return; /* keep */
209

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

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

223
void manager_set_sysctl(Manager *manager) {
417✔
224
        assert(manager);
417✔
225
        assert(!manager->test_mode);
417✔
226

227
        manager_set_ip_forwarding(manager, AF_INET);
417✔
228
        manager_set_ip_forwarding(manager, AF_INET6);
417✔
229
}
417✔
230

231
static bool link_is_configured_for_family(Link *link, int family) {
15,960✔
232
        assert(link);
15,960✔
233

234
        if (!link->network)
15,960✔
235
                return false;
236

237
        if (link->flags & IFF_LOOPBACK)
15,960✔
238
                return false;
239

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

246
        if (family == AF_INET6 && !socket_ipv6_is_supported())
15,956✔
247
                return false;
×
248

249
        return true;
250
}
251

252
static int link_update_ipv6_sysctl(Link *link) {
765✔
253
        assert(link);
765✔
254
        assert(link->manager);
765✔
255

256
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
257
                return 0;
258

259
        if (!link_ipv6_enabled(link))
765✔
260
                return 0;
261

262
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false, manager_get_sysctl_shadow(link->manager));
700✔
263
}
264

265
static int link_set_proxy_arp(Link *link) {
765✔
266
        assert(link);
765✔
267
        assert(link->manager);
765✔
268

269
        if (!link_is_configured_for_family(link, AF_INET))
765✔
270
                return 0;
271

272
        if (link->network->proxy_arp < 0)
765✔
273
                return 0;
274

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

278
static int link_set_proxy_arp_pvlan(Link *link) {
765✔
279
        assert(link);
765✔
280
        assert(link->manager);
765✔
281

282
        if (!link_is_configured_for_family(link, AF_INET))
765✔
283
                return 0;
284

285
        if (link->network->proxy_arp_pvlan < 0)
765✔
286
                return 0;
287

288
        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✔
289
}
290

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

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

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

306
        /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
307
        if (family == AF_INET6 && link_radv_enabled(link))
1,920✔
308
                return true;
309

310
        /* Otherwise, use the global setting. */
311
        return link->manager->ip_forwarding[family == AF_INET6];
1,890✔
312
}
313

314
static int link_set_ip_forwarding_impl(Link *link, int family) {
1,530✔
315
        int r, t;
1,530✔
316

317
        assert(link);
1,530✔
318
        assert(link->manager);
1,530✔
319
        assert(IN_SET(family, AF_INET, AF_INET6));
1,530✔
320

321
        if (!link_is_configured_for_family(link, family))
1,530✔
322
                return 0;
323

324
        t = link_get_ip_forwarding(link, family);
1,530✔
325
        if (t < 0)
1,530✔
326
                return 0; /* keep */
327

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

333
        return 0;
334
}
335

336
static int link_reapply_ip_forwarding(Link *link, int family) {
4✔
337
        int r, ret = 0;
4✔
338

339
        assert(link);
4✔
340
        assert(IN_SET(family, AF_INET, AF_INET6));
4✔
341

342
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
4✔
343
                return 0;
4✔
344

345
        (void) link_set_ip_forwarding_impl(link, family);
2✔
346

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

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

356
                ndisc_flush(link);
1✔
357
        }
358

359
        return ret;
360
}
361

362
static int link_set_ip_forwarding(Link *link, int family) {
1,530✔
363
        int r;
1,530✔
364

365
        assert(link);
1,530✔
366
        assert(link->manager);
1,530✔
367
        assert(link->network);
1,530✔
368
        assert(IN_SET(family, AF_INET, AF_INET6));
1,530✔
369

370
        if (!link_is_configured_for_family(link, family))
1,530✔
371
                return 0;
372

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

378
                link->manager->ip_forwarding[family == AF_INET6] = true;
2✔
379
                manager_set_ip_forwarding(link->manager, family);
2✔
380

381
                Link *other;
2✔
382
                HASHMAP_FOREACH(other, link->manager->links_by_index) {
8✔
383
                        r = link_reapply_ip_forwarding(other, family);
4✔
384
                        if (r < 0)
4✔
385
                                link_enter_failed(other);
×
386
                }
387

388
                return 0;
2✔
389
        }
390

391
        /* Otherwise, apply per-link setting for _this_ link. */
392
        return link_set_ip_forwarding_impl(link, family);
1,528✔
393
}
394

395
static int link_set_ipv4_rp_filter(Link *link) {
765✔
396
        assert(link);
765✔
397
        assert(link->manager);
765✔
398

399
        if (!link_is_configured_for_family(link, AF_INET))
765✔
400
                return 0;
401

402
        if (link->network->ipv4_rp_filter < 0)
765✔
403
                return 0;
404

405
        return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter, manager_get_sysctl_shadow(link->manager));
2✔
406
}
407

408
static int link_set_ipv4_force_igmp_version(Link *link) {
765✔
409
        assert(link);
765✔
410

411
        if (!link_is_configured_for_family(link, AF_INET))
765✔
412
                return 0;
413

414
        if (link->network->ipv4_force_igmp_version < 0)
765✔
415
                return 0;
416

417
        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✔
418
}
419

420
static int link_set_ipv6_privacy_extensions(Link *link) {
765✔
421
        IPv6PrivacyExtensions val;
765✔
422

423
        assert(link);
765✔
424
        assert(link->manager);
765✔
425

426
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
427
                return 0;
428

429
        val = link->network->ipv6_privacy_extensions;
765✔
430
        if (val < 0) /* If not specified, then use the global setting. */
765✔
431
                val = link->manager->ipv6_privacy_extensions;
740✔
432

433
        /* When "kernel", do not update the setting. */
434
        if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
765✔
435
                return 0;
436

437
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val, manager_get_sysctl_shadow(link->manager));
765✔
438
}
439

440
static int link_set_ipv6_accept_ra(Link *link) {
765✔
441
        assert(link);
765✔
442
        assert(link->manager);
765✔
443

444
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
445
                return 0;
446

447
        return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0", manager_get_sysctl_shadow(link->manager));
765✔
448
}
449

450
static int link_set_ipv6_dad_transmits(Link *link) {
765✔
451
        assert(link);
765✔
452
        assert(link->manager);
765✔
453

454
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
455
                return 0;
456

457
        if (link->network->ipv6_dad_transmits < 0)
765✔
458
                return 0;
459

460
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits, manager_get_sysctl_shadow(link->manager));
2✔
461
}
462

463
static int link_set_ipv6_hop_limit(Link *link) {
765✔
464
        assert(link);
765✔
465
        assert(link->manager);
765✔
466

467
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
468
                return 0;
469

470
        if (link->network->ipv6_hop_limit <= 0)
765✔
471
                return 0;
472

473
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit, manager_get_sysctl_shadow(link->manager));
2✔
474
}
475

476
static int link_set_ipv6_retransmission_time(Link *link) {
765✔
477
        usec_t retrans_time_ms;
765✔
478

479
        assert(link);
765✔
480
        assert(link->manager);
765✔
481

482
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
483
                return 0;
484

485
        if (!timestamp_is_set(link->network->ipv6_retransmission_time))
765✔
486
                return 0;
487

488
        retrans_time_ms = DIV_ROUND_UP(link->network->ipv6_retransmission_time, USEC_PER_MSEC);
2✔
489
         if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
2✔
490
                return 0;
491

492
        return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms, manager_get_sysctl_shadow(link->manager));
2✔
493
}
494

495
static int link_set_ipv6_proxy_ndp(Link *link) {
765✔
496
        bool v;
765✔
497

498
        assert(link);
765✔
499
        assert(link->manager);
765✔
500

501
        if (!link_is_configured_for_family(link, AF_INET6))
765✔
502
                return 0;
503

504
        if (link->network->ipv6_proxy_ndp >= 0)
765✔
505
                v = link->network->ipv6_proxy_ndp;
2✔
506
        else
507
                v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
763✔
508

509
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, manager_get_sysctl_shadow(link->manager));
1,527✔
510
}
511

512
int link_set_ipv6_mtu(Link *link, int log_level) {
1,425✔
513
        uint32_t mtu = 0;
1,425✔
514
        int r;
1,425✔
515

516
        assert(link);
1,425✔
517
        assert(link->manager);
1,425✔
518

519
        if (!link_is_configured_for_family(link, AF_INET6))
1,425✔
520
                return 0;
521

522
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1,421✔
523
                return 0;
524

525
        if (sd_event_source_get_enabled(link->ipv6_mtu_wait_synced_event_source, /* ret = */ NULL) > 0) {
1,421✔
526
                log_link_debug(link, "Waiting for IPv6 MTU is synced to link MTU, delaying to set IPv6 MTU.");
×
527
                return 0;
×
528
        }
529

530
        assert(link->network);
1,421✔
531

532
        if (link->network->ndisc_use_mtu)
1,421✔
533
                mtu = link->ndisc_mtu;
1,421✔
534
        if (mtu == 0)
1,421✔
535
                mtu = link->network->ipv6_mtu;
1,376✔
536
        if (mtu == 0)
1,376✔
537
                return 0;
538

539
        if (mtu > link->mtu) {
80✔
540
                log_link_full(link, log_level,
11✔
541
                              "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
542
                              mtu, link->mtu);
543
                mtu = link->mtu;
11✔
544
        }
545

546
        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
80✔
547
        if (r < 0)
80✔
548
                return log_link_warning_errno(link, r, "Failed to set IPv6 MTU to %"PRIu32": %m", mtu);
×
549

550
        return 0;
551
}
552

553
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata);
554

555
static int link_set_ipv6_mtu_async_impl(Link *link) {
44✔
556
        uint32_t current_mtu;
44✔
557
        int r;
44✔
558

559
        assert(link);
44✔
560

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

564
        if (++link->ipv6_mtu_wait_trial_count >= 10) {
44✔
565
                log_link_debug(link, "Timed out waiting for IPv6 MTU being synced to link MTU, proceeding anyway.");
×
566
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
567
                if (r < 0)
×
568
                        return r;
44✔
569

570
                return 1; /* done */
×
571
        }
572

573
        /* Check if IPv6 MTU is synced. */
574
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
44✔
575
        if (r < 0)
44✔
576
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
1✔
577

578
        if (current_mtu == link->mtu) {
43✔
579
                /* Already synced. Update IPv6 MTU now. */
580
                r = link_set_ipv6_mtu(link, LOG_INFO);
43✔
581
                if (r < 0)
43✔
582
                        return r;
583

584
                return 1; /* done */
43✔
585
        }
586

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

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

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

607
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
608
                if (r < 0)
×
609
                        return r;
610

611
                return 1; /* done */
×
612
        }
613

614
        log_link_debug(link, "IPv6 MTU is not synced to the link MTU after it is changed. Waiting for a while.");
×
615
        return 0; /* waiting */
616
}
617

618
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata) {
×
619
        (void) link_set_ipv6_mtu_async_impl(ASSERT_PTR(userdata));
×
620
        return 0;
×
621
}
622

623
int link_set_ipv6_mtu_async(Link *link) {
44✔
624
        assert(link);
44✔
625

626
        link->ipv6_mtu_wait_trial_count = 0;
44✔
627
        return link_set_ipv6_mtu_async_impl(link);
44✔
628
}
629

630
static int link_set_ipv4_accept_local(Link *link) {
765✔
631
        assert(link);
765✔
632
        assert(link->manager);
765✔
633

634
        if (!link_is_configured_for_family(link, AF_INET))
765✔
635
                return 0;
636

637
        if (link->network->ipv4_accept_local < 0)
765✔
638
                return 0;
639

640
        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✔
641
}
642

643
static int link_set_ipv4_route_localnet(Link *link) {
765✔
644
        assert(link);
765✔
645
        assert(link->manager);
765✔
646

647
        if (!link_is_configured_for_family(link, AF_INET))
765✔
648
                return 0;
649

650
        if (link->network->ipv4_route_localnet < 0)
765✔
651
                return 0;
652

653
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, manager_get_sysctl_shadow(link->manager));
×
654
}
655

656
static int link_set_ipv4_promote_secondaries(Link *link) {
765✔
657
        assert(link);
765✔
658
        assert(link->manager);
765✔
659

660
        if (!link_is_configured_for_family(link, AF_INET))
765✔
661
                return 0;
662

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

671
static int link_set_mpls_input(Link *link) {
765✔
672
        assert(link);
765✔
673
        assert(link->manager);
765✔
674

675
        if (!link_is_configured_for_family(link, AF_MPLS))
765✔
676
                return 0;
677

678
        if (link->network->mpls_input < 0)
765✔
679
                return 0;
680

681
        return sysctl_write_ip_property_boolean(AF_MPLS, link->ifname, "input", link->network->mpls_input > 0, manager_get_sysctl_shadow(link->manager));
1✔
682
}
683

684
int link_set_sysctl(Link *link) {
765✔
685
        int r;
765✔
686

687
        assert(link);
765✔
688

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

695
        r = link_set_proxy_arp(link);
765✔
696
        if (r < 0)
765✔
697
               log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
×
698

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

703
        (void) link_set_ip_forwarding(link, AF_INET);
765✔
704
        (void) link_set_ip_forwarding(link, AF_INET6);
765✔
705

706
        r = link_set_ipv6_privacy_extensions(link);
765✔
707
        if (r < 0)
765✔
708
                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
×
709

710
        r = link_set_ipv6_accept_ra(link);
765✔
711
        if (r < 0)
765✔
712
                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
×
713

714
        r = link_set_ipv6_dad_transmits(link);
765✔
715
        if (r < 0)
765✔
716
                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
×
717

718
        r = link_set_ipv6_hop_limit(link);
765✔
719
        if (r < 0)
765✔
720
                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
×
721

722
        r = link_set_ipv6_retransmission_time(link);
765✔
723
        if (r < 0)
765✔
724
                log_link_warning_errno(link, r, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
×
725

726
        r = link_set_ipv6_proxy_ndp(link);
765✔
727
        if (r < 0)
765✔
728
                log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
×
729

730
        (void) link_set_ipv6_mtu(link, LOG_INFO);
765✔
731

732
        r = link_set_ipv6ll_stable_secret(link);
765✔
733
        if (r < 0)
765✔
734
                log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link-local address: %m");
×
735

736
        r = link_set_ipv4_accept_local(link);
765✔
737
        if (r < 0)
765✔
738
                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
×
739

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

744
        r = link_set_ipv4_rp_filter(link);
765✔
745
        if (r < 0)
765✔
746
                log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
×
747

748
        r = link_set_ipv4_force_igmp_version(link);
765✔
749
        if (r < 0)
765✔
750
                log_link_warning_errno(link, r, "Cannot set IPv4 force igmp version, ignoring: %m");
×
751

752
        r = link_set_ipv4_promote_secondaries(link);
765✔
753
        if (r < 0)
765✔
754
                log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");
×
755

756
        r = link_set_mpls_input(link);
765✔
757
        if (r < 0)
765✔
758
                log_link_warning_errno(link, r, "Cannot set MPLS input, ignoring: %m");
×
759

760
        return 0;
765✔
761
}
762

763
static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
764
        [IPV6_PRIVACY_EXTENSIONS_NO]            = "no",
765
        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
766
        [IPV6_PRIVACY_EXTENSIONS_YES]           = "yes",
767
        [IPV6_PRIVACY_EXTENSIONS_KERNEL]        = "kernel",
768
};
769

770
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
76✔
771
                                        IPV6_PRIVACY_EXTENSIONS_YES);
772
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions);
22✔
773

774
static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
775
        [IP_REVERSE_PATH_FILTER_NO]     = "no",
776
        [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
777
        [IP_REVERSE_PATH_FILTER_LOOSE]  = "loose",
778
};
779

780
DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
2✔
781
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter);
2✔
782

783
int config_parse_ip_forward_deprecated(
×
784
                const char* unit,
785
                const char *filename,
786
                unsigned line,
787
                const char *section,
788
                unsigned section_line,
789
                const char *lvalue,
790
                int ltype,
791
                const char *rvalue,
792
                void *data,
793
                void *userdata) {
794

795
        assert(filename);
×
796

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

804
static const char* const ipv4_force_igmp_version_table[_IPV4_FORCE_IGMP_VERSION_MAX] = {
805
        [IPV4_FORCE_IGMP_VERSION_NO] = "no",
806
        [IPV4_FORCE_IGMP_VERSION_1]  = "v1",
807
        [IPV4_FORCE_IGMP_VERSION_2]  = "v2",
808
        [IPV4_FORCE_IGMP_VERSION_3]  = "v3",
809
};
810

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