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

systemd / systemd / 29544664670

16 Jul 2026 04:17PM UTC coverage: 73.034% (+0.05%) from 72.983%
29544664670

push

github

yuwata
boot: fix MEMMAP_DEVICE_PATH EndingAddress field calculation

Let's do what EDK2 does.

Fixes: #43038

346521 of 474466 relevant lines covered (73.03%)

1340443.02 hits per line

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

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

3
#include <linux/if_arp.h>
4

5
#include "sd-messages.h"
6

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

30
#if ENABLE_SYSCTL_BPF
31

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

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

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

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

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

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

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

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

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

87
        return 0;
88
}
89

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

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

98
        return 0;
31✔
99
}
100

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

109
        assert(manager);
467✔
110

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

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

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

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

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

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

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

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

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

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

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

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

164
        return 0;
467✔
165
}
166

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

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

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

182
        assert(link);
1,873✔
183
        assert(link->manager);
1,873✔
184

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

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

193
        HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow)
8,881✔
194
                if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) {
7,008✔
195
                        assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value));
3,155✔
196
                        free(key);
3,155✔
197
                        free(value);
3,155✔
198
                }
199

200
        return 0;
1,873✔
201
}
202
#endif
203

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

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

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

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

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

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

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

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

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

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

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

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

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

256
        return true;
257
}
258

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

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

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

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

272
static int link_set_proxy_arp(Link *link) {
876✔
273
        bool v;
876✔
274

275
        assert(link);
876✔
276
        assert(link->manager);
876✔
277

278
        if (!link_is_configured_for_family(link, AF_INET))
876✔
279
                return 0;
280

281
        if (link->network->proxy_arp >= 0)
876✔
282
                v = link->network->proxy_arp;
3✔
283
        else if (network_has_neighbor_proxy_address(link->network, AF_INET))
873✔
284
                /* If IPv4ProxyARP= is not explicitly set, but per-address IPv4ProxyARPAddress=
285
                 * entries are configured, implicitly enable the proxy_arp sysctl. This matches
286
                 * the behavior of IPv6ProxyNDPAddress= which implies IPv6ProxyNDP=yes. */
287
                v = true;
288
        else
289
                return 0;
290

291
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", v, manager_get_sysctl_shadow(link->manager));
4✔
292
}
293

294
static int link_set_proxy_arp_pvlan(Link *link) {
876✔
295
        assert(link);
876✔
296
        assert(link->manager);
876✔
297

298
        if (!link_is_configured_for_family(link, AF_INET))
876✔
299
                return 0;
300

301
        if (link->network->proxy_arp_pvlan < 0)
876✔
302
                return 0;
303

304
        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✔
305
}
306

307
int link_get_ip_forwarding(Link *link, int family) {
2,303✔
308
        assert(link);
2,303✔
309
        assert(link->manager);
2,303✔
310
        assert(link->network);
2,303✔
311
        assert(IN_SET(family, AF_INET, AF_INET6));
2,303✔
312

313
        /* If it is explicitly specified, then honor the setting. */
314
        int t = link->network->ip_forwarding[family == AF_INET6];
2,303✔
315
        if (t >= 0)
2,303✔
316
                return t;
317

318
        /* If IPMasquerade= is enabled, also enable IP forwarding. */
319
        if (FLAGS_SET(link->network->ip_masquerade, AF_TO_ADDRESS_FAMILY(family)))
3,605✔
320
                return true;
321

322
        /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
323
        if (family == AF_INET6 && link_radv_enabled(link))
2,198✔
324
                return true;
325

326
        /* Otherwise, use the global setting. */
327
        return link->manager->ip_forwarding[family == AF_INET6];
2,164✔
328
}
329

330
static int link_set_ip_forwarding_impl(Link *link, int family) {
1,754✔
331
        int r, t;
1,754✔
332

333
        assert(link);
1,754✔
334
        assert(link->manager);
1,754✔
335
        assert(IN_SET(family, AF_INET, AF_INET6));
1,754✔
336

337
        if (!link_is_configured_for_family(link, family))
1,754✔
338
                return 0;
339

340
        t = link_get_ip_forwarding(link, family);
1,754✔
341
        if (t < 0)
1,754✔
342
                return 0; /* keep */
343

344
        r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t, manager_get_sysctl_shadow(link->manager));
125✔
345
        if (r < 0)
125✔
346
                return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
×
347
                                              enable_disable(t), af_to_ipv4_ipv6(family));
348

349
        return 0;
350
}
351

352
static int link_reapply_ip_forwarding(Link *link, int family) {
22✔
353
        int r, ret = 0;
22✔
354

355
        assert(link);
22✔
356
        assert(IN_SET(family, AF_INET, AF_INET6));
22✔
357

358
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
22✔
359
                return 0;
22✔
360

361
        (void) link_set_ip_forwarding_impl(link, family);
12✔
362

363
        r = link_lldp_tx_update_capabilities(link);
12✔
364
        if (r < 0)
12✔
365
                RET_GATHER(ret, log_link_warning_errno(link, r, "Could not update LLDP capabilities, ignoring: %m"));
×
366

367
        if (family == AF_INET6 && !link_ndisc_enabled(link)) {
12✔
368
                r = ndisc_stop(link);
6✔
369
                if (r < 0)
6✔
370
                        RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery, ignoring: %m"));
×
371

372
                ndisc_flush(link);
6✔
373
        }
374

375
        return ret;
376
}
377

378
static int link_set_ip_forwarding(Link *link, int family) {
1,752✔
379
        int r;
1,752✔
380

381
        assert(link);
1,752✔
382
        assert(link->manager);
1,752✔
383
        assert(link->network);
1,752✔
384
        assert(IN_SET(family, AF_INET, AF_INET6));
1,752✔
385

386
        if (!link_is_configured_for_family(link, family))
1,752✔
387
                return 0;
388

389
        /* When IPMasquerade= is enabled and the global setting is unset, enable _global_ IP forwarding, and
390
         * re-apply per-link setting for all links. */
391
        if (FLAGS_SET(link->network->ip_masquerade, AF_TO_ADDRESS_FAMILY(family)) &&
2,628✔
392
            link->manager->ip_forwarding[family == AF_INET6] < 0) {
36✔
393

394
                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.");
10✔
395

396
                link->manager->ip_forwarding[family == AF_INET6] = true;
10✔
397
                manager_set_ip_forwarding(link->manager, family);
10✔
398

399
                Link *other;
10✔
400
                HASHMAP_FOREACH(other, link->manager->links_by_index) {
42✔
401
                        r = link_reapply_ip_forwarding(other, family);
22✔
402
                        if (r < 0)
22✔
403
                                link_enter_failed(other);
×
404
                }
405

406
                return 0;
10✔
407
        }
408

409
        /* Otherwise, apply per-link setting for _this_ link. */
410
        return link_set_ip_forwarding_impl(link, family);
1,742✔
411
}
412

413
static int link_set_ipv4_rp_filter(Link *link) {
876✔
414
        assert(link);
876✔
415
        assert(link->manager);
876✔
416

417
        if (!link_is_configured_for_family(link, AF_INET))
876✔
418
                return 0;
419

420
        if (link->network->ipv4_rp_filter < 0)
876✔
421
                return 0;
422

423
        return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter, manager_get_sysctl_shadow(link->manager));
2✔
424
}
425

426
static int link_set_ipv4_force_igmp_version(Link *link) {
876✔
427
        assert(link);
876✔
428

429
        if (!link_is_configured_for_family(link, AF_INET))
876✔
430
                return 0;
431

432
        if (link->network->ipv4_force_igmp_version < 0)
876✔
433
                return 0;
434

435
        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✔
436
}
437

438
static int link_set_ipv6_privacy_extensions(Link *link) {
876✔
439
        IPv6PrivacyExtensions val;
876✔
440

441
        assert(link);
876✔
442
        assert(link->manager);
876✔
443

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

447
        val = link->network->ipv6_privacy_extensions;
876✔
448
        if (val < 0) /* If not specified, then use the global setting. */
876✔
449
                val = link->manager->ipv6_privacy_extensions;
851✔
450

451
        /* When "kernel", do not update the setting. */
452
        if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
876✔
453
                return 0;
454

455
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val, manager_get_sysctl_shadow(link->manager));
876✔
456
}
457

458
static int link_set_ipv6_accept_ra(Link *link) {
876✔
459
        assert(link);
876✔
460
        assert(link->manager);
876✔
461

462
        if (!link_is_configured_for_family(link, AF_INET6))
876✔
463
                return 0;
464

465
        return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0", manager_get_sysctl_shadow(link->manager));
876✔
466
}
467

468
static int link_set_ipv6_dad_transmits(Link *link) {
876✔
469
        assert(link);
876✔
470
        assert(link->manager);
876✔
471

472
        if (!link_is_configured_for_family(link, AF_INET6))
876✔
473
                return 0;
474

475
        if (link->network->ipv6_dad_transmits < 0)
876✔
476
                return 0;
477

478
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits, manager_get_sysctl_shadow(link->manager));
2✔
479
}
480

481
static int link_set_ipv6_hop_limit(Link *link) {
876✔
482
        assert(link);
876✔
483
        assert(link->manager);
876✔
484

485
        if (!link_is_configured_for_family(link, AF_INET6))
876✔
486
                return 0;
487

488
        if (link->network->ipv6_hop_limit <= 0)
876✔
489
                return 0;
490

491
        return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit, manager_get_sysctl_shadow(link->manager));
2✔
492
}
493

494
static int link_set_ipv6_retransmission_time(Link *link) {
876✔
495
        usec_t retrans_time_ms;
876✔
496

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

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

503
        if (!timestamp_is_set(link->network->ipv6_retransmission_time))
876✔
504
                return 0;
505

506
        retrans_time_ms = DIV_ROUND_UP(link->network->ipv6_retransmission_time, USEC_PER_MSEC);
2✔
507
         if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
2✔
508
                return 0;
509

510
        return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms, manager_get_sysctl_shadow(link->manager));
2✔
511
}
512

513
static int link_set_ipv6_proxy_ndp(Link *link) {
876✔
514
        bool v;
876✔
515

516
        assert(link);
876✔
517
        assert(link->manager);
876✔
518

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

522
        if (link->network->ipv6_proxy_ndp >= 0)
876✔
523
                v = link->network->ipv6_proxy_ndp;
2✔
524
        else
525
                v = network_has_neighbor_proxy_address(link->network, AF_INET6);
874✔
526

527
        return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, manager_get_sysctl_shadow(link->manager));
876✔
528
}
529

530
int link_set_ipv6_mtu(Link *link, int log_level) {
1,636✔
531
        uint32_t mtu = 0;
1,636✔
532
        int r;
1,636✔
533

534
        assert(link);
1,636✔
535
        assert(link->manager);
1,636✔
536

537
        if (!link_is_configured_for_family(link, AF_INET6))
1,636✔
538
                return 0;
539

540
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1,632✔
541
                return 0;
542

543
        if (sd_event_source_get_enabled(link->ipv6_mtu_wait_synced_event_source, /* ret= */ NULL) > 0) {
1,632✔
544
                log_link_debug(link, "Waiting for IPv6 MTU is synced to link MTU, delaying to set IPv6 MTU.");
×
545
                return 0;
546
        }
547

548
        assert(link->network);
1,632✔
549

550
        if (link->network->ndisc_use_mtu)
1,632✔
551
                mtu = link->ndisc_mtu;
1,632✔
552
        if (mtu == 0)
1,632✔
553
                mtu = link->network->ipv6_mtu;
1,573✔
554
        if (mtu == 0)
1,573✔
555
                return 0;
556

557
        if (mtu > link->mtu) {
91✔
558
                log_link_full(link, log_level,
11✔
559
                              "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
560
                              mtu, link->mtu);
561
                mtu = link->mtu;
11✔
562
        }
563

564
        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
91✔
565
        if (r < 0)
91✔
566
                return log_link_warning_errno(link, r, "Failed to set IPv6 MTU to %"PRIu32": %m", mtu);
×
567

568
        return 0;
569
}
570

571
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata);
572

573
static int link_set_ipv6_mtu_async_impl(Link *link) {
49✔
574
        uint32_t current_mtu;
49✔
575
        int r;
49✔
576

577
        assert(link);
49✔
578

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

582
        if (++link->ipv6_mtu_wait_trial_count >= 10) {
49✔
583
                log_link_debug(link, "Timed out waiting for IPv6 MTU being synced to link MTU, proceeding anyway.");
×
584
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
585
                if (r < 0)
×
586
                        return r;
49✔
587

588
                return 1; /* done */
×
589
        }
590

591
        /* Check if IPv6 MTU is synced. */
592
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
49✔
593
        if (r < 0)
49✔
594
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
1✔
595

596
        if (current_mtu == link->mtu) {
48✔
597
                /* Already synced. Update IPv6 MTU now. */
598
                r = link_set_ipv6_mtu(link, LOG_INFO);
47✔
599
                if (r < 0)
47✔
600
                        return r;
601

602
                return 1; /* done */
47✔
603
        }
604

605
        /* If not, set up a timer event source. */
606
        r = event_reset_time_relative(
2✔
607
                        link->manager->event, &link->ipv6_mtu_wait_synced_event_source,
1✔
608
                        CLOCK_BOOTTIME, 100 * USEC_PER_MSEC, 0,
609
                        ipv6_mtu_wait_synced_handler, link,
610
                        /* priority= */ 0, "ipv6-mtu-wait-synced", /* force_reset= */ true);
611
        if (r < 0)
1✔
612
                return log_link_warning_errno(link, r, "Failed to configure timer event source for waiting for IPv6 MTU being synced: %m");
×
613

614
        /* Check again. */
615
        r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", &current_mtu);
1✔
616
        if (r < 0)
1✔
617
                return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
×
618

619
        if (current_mtu == link->mtu) {
1✔
620
                /* Synced while setting up the timer event source. Disable it and update IPv6 MTU now. */
621
                r = sd_event_source_set_enabled(link->ipv6_mtu_wait_synced_event_source, SD_EVENT_OFF);
×
622
                if (r < 0)
×
623
                        log_link_debug_errno(link, r, "Failed to disable timer event source for IPv6 MTU, ignoring: %m");
×
624

625
                r = link_set_ipv6_mtu(link, LOG_INFO);
×
626
                if (r < 0)
×
627
                        return r;
628

629
                return 1; /* done */
×
630
        }
631

632
        log_link_debug(link, "IPv6 MTU is not synced to the link MTU after it is changed. Waiting for a while.");
1✔
633
        return 0; /* waiting */
634
}
635

636
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1✔
637
        (void) link_set_ipv6_mtu_async_impl(ASSERT_PTR(userdata));
1✔
638
        return 0;
1✔
639
}
640

641
int link_set_ipv6_mtu_async(Link *link) {
48✔
642
        assert(link);
48✔
643

644
        link->ipv6_mtu_wait_trial_count = 0;
48✔
645
        return link_set_ipv6_mtu_async_impl(link);
48✔
646
}
647

648
static int link_set_ipv4_accept_local(Link *link) {
876✔
649
        assert(link);
876✔
650
        assert(link->manager);
876✔
651

652
        if (!link_is_configured_for_family(link, AF_INET))
876✔
653
                return 0;
654

655
        if (link->network->ipv4_accept_local < 0)
876✔
656
                return 0;
657

658
        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✔
659
}
660

661
static int link_set_ipv4_route_localnet(Link *link) {
876✔
662
        assert(link);
876✔
663
        assert(link->manager);
876✔
664

665
        if (!link_is_configured_for_family(link, AF_INET))
876✔
666
                return 0;
667

668
        if (link->network->ipv4_route_localnet < 0)
876✔
669
                return 0;
670

671
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, manager_get_sysctl_shadow(link->manager));
×
672
}
673

674
static int link_set_ipv4_src_valid_mark(Link *link) {
876✔
675
        assert(link);
876✔
676
        assert(link->manager);
876✔
677
        assert(link->network);
876✔
678

679
        if (!link_is_configured_for_family(link, AF_INET))
876✔
680
                return 0;
681

682
        if (link->network->ipv4_src_valid_mark < 0)
876✔
683
                return 0;
684

685
        return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "src_valid_mark", link->network->ipv4_src_valid_mark > 0, manager_get_sysctl_shadow(link->manager));
2✔
686
}
687

688
static int link_set_ipv4_promote_secondaries(Link *link) {
876✔
689
        assert(link);
876✔
690
        assert(link->manager);
876✔
691

692
        if (!link_is_configured_for_family(link, AF_INET))
876✔
693
                return 0;
694

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

703
static int link_set_mpls_input(Link *link) {
876✔
704
        assert(link);
876✔
705
        assert(link->manager);
876✔
706

707
        if (!link_is_configured_for_family(link, AF_MPLS))
876✔
708
                return 0;
709

710
        if (link->network->mpls_input < 0)
876✔
711
                return 0;
712

713
        return sysctl_write_ip_property_boolean(AF_MPLS, link->ifname, "input", link->network->mpls_input > 0, manager_get_sysctl_shadow(link->manager));
1✔
714
}
715

716
int link_set_sysctl(Link *link) {
876✔
717
        int r;
876✔
718

719
        assert(link);
876✔
720

721
        /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
722
         * for this interface, then enable IPv6 */
723
        r = link_update_ipv6_sysctl(link);
876✔
724
        if (r < 0)
876✔
725
                log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
×
726

727
        r = link_set_proxy_arp(link);
876✔
728
        if (r < 0)
876✔
729
               log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
×
730

731
        r = link_set_proxy_arp_pvlan(link);
876✔
732
        if (r < 0)
876✔
733
                log_link_warning_errno(link, r, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
×
734

735
        (void) link_set_ip_forwarding(link, AF_INET);
876✔
736
        (void) link_set_ip_forwarding(link, AF_INET6);
876✔
737

738
        r = link_set_ipv6_privacy_extensions(link);
876✔
739
        if (r < 0)
876✔
740
                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
×
741

742
        r = link_set_ipv6_accept_ra(link);
876✔
743
        if (r < 0)
876✔
744
                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
×
745

746
        r = link_set_ipv6_dad_transmits(link);
876✔
747
        if (r < 0)
876✔
748
                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
×
749

750
        r = link_set_ipv6_hop_limit(link);
876✔
751
        if (r < 0)
876✔
752
                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
×
753

754
        r = link_set_ipv6_retransmission_time(link);
876✔
755
        if (r < 0)
876✔
756
                log_link_warning_errno(link, r, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
×
757

758
        r = link_set_ipv6_proxy_ndp(link);
876✔
759
        if (r < 0)
876✔
760
                log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
×
761

762
        (void) link_set_ipv6_mtu(link, LOG_INFO);
876✔
763

764
        r = link_set_ipv6ll_stable_secret(link);
876✔
765
        if (r < 0)
876✔
766
                log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link-local address: %m");
×
767

768
        r = link_set_ipv4_accept_local(link);
876✔
769
        if (r < 0)
876✔
770
                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
×
771

772
        r = link_set_ipv4_route_localnet(link);
876✔
773
        if (r < 0)
876✔
774
                log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
×
775

776
        r = link_set_ipv4_src_valid_mark(link);
876✔
777
        if (r < 0)
876✔
778
                log_link_warning_errno(link, r, "Cannot set IPv4 src_valid_mark flag for interface, ignoring: %m");
×
779

780
        r = link_set_ipv4_rp_filter(link);
876✔
781
        if (r < 0)
876✔
782
                log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
×
783

784
        r = link_set_ipv4_force_igmp_version(link);
876✔
785
        if (r < 0)
876✔
786
                log_link_warning_errno(link, r, "Cannot set IPv4 force igmp version, ignoring: %m");
×
787

788
        r = link_set_ipv4_promote_secondaries(link);
876✔
789
        if (r < 0)
876✔
790
                log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");
×
791

792
        r = link_set_mpls_input(link);
876✔
793
        if (r < 0)
876✔
794
                log_link_warning_errno(link, r, "Cannot set MPLS input, ignoring: %m");
×
795

796
        return 0;
876✔
797
}
798

799
static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
800
        [IPV6_PRIVACY_EXTENSIONS_NO]            = "no",
801
        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
802
        [IPV6_PRIVACY_EXTENSIONS_YES]           = "yes",
803
        [IPV6_PRIVACY_EXTENSIONS_KERNEL]        = "kernel",
804
};
805

806
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
76✔
807
                                        IPV6_PRIVACY_EXTENSIONS_YES);
808
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions);
22✔
809

810
static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
811
        [IP_REVERSE_PATH_FILTER_NO]     = "no",
812
        [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
813
        [IP_REVERSE_PATH_FILTER_LOOSE]  = "loose",
814
};
815

816
DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
2✔
817
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter);
2✔
818

819
int config_parse_ip_forward_deprecated(
×
820
                const char *unit,
821
                const char *filename,
822
                unsigned line,
823
                const char *section,
824
                unsigned section_line,
825
                const char *lvalue,
826
                int ltype,
827
                const char *rvalue,
828
                void *data,
829
                void *userdata) {
830

831
        assert(filename);
×
832

833
        log_syntax(unit, LOG_WARNING, filename, line, 0,
×
834
                   "IPForward= setting is deprecated. "
835
                   "Please use IPv4Forwarding= and/or IPv6Forwarding= in networkd.conf for global setting, "
836
                   "and the same settings in .network files for per-interface setting.");
837
        return 0;
×
838
}
839

840
static const char* const ipv4_force_igmp_version_table[_IPV4_FORCE_IGMP_VERSION_MAX] = {
841
        [IPV4_FORCE_IGMP_VERSION_NO] = "no",
842
        [IPV4_FORCE_IGMP_VERSION_1]  = "v1",
843
        [IPV4_FORCE_IGMP_VERSION_2]  = "v2",
844
        [IPV4_FORCE_IGMP_VERSION_3]  = "v3",
845
};
846

847
DEFINE_STRING_TABLE_LOOKUP(ipv4_force_igmp_version, IPv4ForceIgmpVersion);
2✔
848
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 TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc