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

systemd / systemd / 14815796853

02 May 2025 11:41AM UTC coverage: 72.24% (-0.003%) from 72.243%
14815796853

push

github

web-flow
Various changes to prepare for running IWYU on the repository (#37319)

These are various commits that were required to get things compiling
after running IWYU. I think all of them make sense on their own, hence
this split PR to merge them ahead of time.

81 of 96 new or added lines in 48 files covered. (84.38%)

209 existing lines in 39 files now uncovered.

297219 of 411432 relevant lines covered (72.24%)

693693.2 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 <linux/if.h>
4
#include <linux/if_arp.h>
5
#include <netinet/in.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
#include "bpf/sysctl_monitor/sysctl-monitor-skel.h"
30
#include "bpf/sysctl_monitor/sysctl-write-event.h"
31

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

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

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

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

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

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

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

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

79
        return 0;
80
}
81

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

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

90
        return 0;
1✔
91
}
92

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

101
        assert(manager);
417✔
102

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

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

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

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

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

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

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

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

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

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

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

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

156
        return 0;
361✔
157
}
158

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

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

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

174
        assert(link);
2,598✔
175
        assert(link->manager);
2,598✔
176

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

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

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

192
        return 0;
2,598✔
193
}
194
#endif
195

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

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

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

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

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

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

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

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

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

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

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

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

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

248
        return true;
249
}
250

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

255
        if (!link_is_configured_for_family(link, AF_INET6))
762✔
256
                return 0;
257

258
        if (!link_ipv6_enabled(link))
762✔
259
                return 0;
260

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

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

268
        if (!link_is_configured_for_family(link, AF_INET))
762✔
269
                return 0;
270

271
        if (link->network->proxy_arp < 0)
762✔
272
                return 0;
273

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

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

281
        if (!link_is_configured_for_family(link, AF_INET))
762✔
282
                return 0;
283

284
        if (link->network->proxy_arp_pvlan < 0)
762✔
285
                return 0;
286

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

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

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

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

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

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

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

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

320
        if (!link_is_configured_for_family(link, family))
1,524✔
321
                return 0;
322

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

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

332
        return 0;
333
}
334

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

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

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

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

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

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

355
                ndisc_flush(link);
1✔
356
        }
357

358
        return ret;
359
}
360

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

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

369
        if (!link_is_configured_for_family(link, family))
1,524✔
370
                return 0;
371

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

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

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

387
                return 0;
2✔
388
        }
389

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

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

398
        if (!link_is_configured_for_family(link, AF_INET))
762✔
399
                return 0;
400

401
        if (link->network->ipv4_rp_filter < 0)
762✔
402
                return 0;
403

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

407
static int link_set_ipv4_force_igmp_version(Link *link) {
762✔
408
        assert(link);
762✔
409

410
        if (!link_is_configured_for_family(link, AF_INET))
762✔
411
                return 0;
412

413
        if (link->network->ipv4_force_igmp_version < 0)
762✔
414
                return 0;
415

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

419
static int link_set_ipv6_privacy_extensions(Link *link) {
762✔
420
        IPv6PrivacyExtensions val;
762✔
421

422
        assert(link);
762✔
423
        assert(link->manager);
762✔
424

425
        if (!link_is_configured_for_family(link, AF_INET6))
762✔
426
                return 0;
427

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

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

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

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

443
        if (!link_is_configured_for_family(link, AF_INET6))
762✔
444
                return 0;
445

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

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

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

456
        if (link->network->ipv6_dad_transmits < 0)
762✔
457
                return 0;
458

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

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

466
        if (!link_is_configured_for_family(link, AF_INET6))
762✔
467
                return 0;
468

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

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

475
static int link_set_ipv6_retransmission_time(Link *link) {
762✔
476
        usec_t retrans_time_ms;
762✔
477

478
        assert(link);
762✔
479
        assert(link->manager);
762✔
480

481
        if (!link_is_configured_for_family(link, AF_INET6))
762✔
482
                return 0;
483

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

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

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

494
static int link_set_ipv6_proxy_ndp(Link *link) {
762✔
495
        bool v;
762✔
496

497
        assert(link);
762✔
498
        assert(link->manager);
762✔
499

500
        if (!link_is_configured_for_family(link, AF_INET6))
762✔
501
                return 0;
502

503
        if (link->network->ipv6_proxy_ndp >= 0)
762✔
504
                v = link->network->ipv6_proxy_ndp;
2✔
505
        else
506
                v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
760✔
507

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

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

515
        assert(link);
1,428✔
516
        assert(link->manager);
1,428✔
517

518
        if (!link_is_configured_for_family(link, AF_INET6))
1,428✔
519
                return 0;
520

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

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

529
        assert(link->network);
1,424✔
530

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

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

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

549
        return 0;
550
}
551

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

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

558
        assert(link);
45✔
559

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

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

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

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

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

583
                return 1; /* done */
44✔
584
        }
585

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

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

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

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

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

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

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

622
int link_set_ipv6_mtu_async(Link *link) {
45✔
623
        assert(link);
45✔
624

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

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

633
        if (!link_is_configured_for_family(link, AF_INET))
762✔
634
                return 0;
635

636
        if (link->network->ipv4_accept_local < 0)
762✔
637
                return 0;
638

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

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

646
        if (!link_is_configured_for_family(link, AF_INET))
762✔
647
                return 0;
648

649
        if (link->network->ipv4_route_localnet < 0)
762✔
650
                return 0;
651

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

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

659
        if (!link_is_configured_for_family(link, AF_INET))
762✔
660
                return 0;
661

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

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

674
        if (!link_is_configured_for_family(link, AF_MPLS))
762✔
675
                return 0;
676

677
        if (link->network->mpls_input < 0)
762✔
678
                return 0;
679

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

683
int link_set_sysctl(Link *link) {
762✔
684
        int r;
762✔
685

686
        assert(link);
762✔
687

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

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

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

702
        (void) link_set_ip_forwarding(link, AF_INET);
762✔
703
        (void) link_set_ip_forwarding(link, AF_INET6);
762✔
704

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

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

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

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

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

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

729
        (void) link_set_ipv6_mtu(link, LOG_INFO);
762✔
730

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

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

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

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

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

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

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

759
        return 0;
762✔
760
}
761

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

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

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

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

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

794
        assert(filename);
×
795

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

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

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