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

systemd / systemd / 20082643496

09 Dec 2025 07:56PM UTC coverage: 72.681% (+0.2%) from 72.443%
20082643496

push

github

yuwata
resolve: always read /etc/resolv.conf on reload systemd-resolved

When systemd-resolved is used in resolv.conf foreign mode, reloading the
systemd-resolved daemon does not read resolv.conf when not touched since
the last time resolved read the file. Since the DNS servers list is
flushed during a reload, resolved forgets about the servers
in /etc/resolv.conf

When reloading the daemon it is expected that all configuration is
reloaded regardless of the disk timestamps.

1 of 1 new or added line in 1 file covered. (100.0%)

386 existing lines in 42 files now uncovered.

309400 of 425694 relevant lines covered (72.68%)

1255615.42 hits per line

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

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

3
#include <linux/if_arp.h>
4

5
#include "sd-messages.h"
6

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

30
#if ENABLE_SYSCTL_BPF
31

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

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

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

43
static int sysctl_event_handler(void *ctx, void *data, size_t data_sz) {
11✔
44
        struct sysctl_write_event *we = ASSERT_PTR(data);
11✔
45
        Hashmap **sysctl_shadow = ASSERT_PTR(ctx);
11✔
46
        _cleanup_free_ char *path = NULL;
11✔
47
        char *value;
11✔
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)
11✔
52
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
×
53
                                         "Unexpected sysctl event, disabling sysctl monitoring: %d", we->version);
54

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

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

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

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

83
        return 0;
84
}
85

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

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

94
        return 0;
8✔
95
}
96

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

105
        assert(manager);
443✔
106

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

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

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

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

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

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

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

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

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

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

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

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

160
        return 0;
384✔
161
}
162

163
void manager_remove_sysctl_monitor(Manager *manager) {
468✔
164
        assert(manager);
468✔
165

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

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

178
        assert(link);
2,784✔
179
        assert(link->manager);
2,784✔
180

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

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

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

196
        return 0;
2,784✔
197
}
198
#endif
199

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

203
        assert(manager);
890✔
204
        assert(IN_SET(family, AF_INET, AF_INET6));
890✔
205

206
        if (family == AF_INET6 && !socket_ipv6_is_supported())
890✔
207
                return;
208

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

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

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

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

230
        manager_set_ip_forwarding(manager, AF_INET);
443✔
231
        manager_set_ip_forwarding(manager, AF_INET6);
443✔
232
}
443✔
233

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

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

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

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

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

252
        return true;
253
}
254

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

259
        if (!link_is_configured_for_family(link, AF_INET6))
854✔
260
                return 0;
261

262
        if (!link_ipv6_enabled(link))
854✔
263
                return 0;
264

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

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

272
        if (!link_is_configured_for_family(link, AF_INET))
854✔
273
                return 0;
274

275
        if (link->network->proxy_arp < 0)
854✔
276
                return 0;
277

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

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

285
        if (!link_is_configured_for_family(link, AF_INET))
854✔
286
                return 0;
287

288
        if (link->network->proxy_arp_pvlan < 0)
854✔
289
                return 0;
290

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

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

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

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

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

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

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

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

324
        if (!link_is_configured_for_family(link, family))
1,710✔
325
                return 0;
326

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

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

336
        return 0;
337
}
338

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

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

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

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

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

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

359
                ndisc_flush(link);
3✔
360
        }
361

362
        return ret;
363
}
364

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

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

373
        if (!link_is_configured_for_family(link, family))
1,708✔
374
                return 0;
375

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

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

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

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

393
                return 0;
4✔
394
        }
395

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

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

404
        if (!link_is_configured_for_family(link, AF_INET))
854✔
405
                return 0;
406

407
        if (link->network->ipv4_rp_filter < 0)
854✔
408
                return 0;
409

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

413
static int link_set_ipv4_force_igmp_version(Link *link) {
854✔
414
        assert(link);
854✔
415

416
        if (!link_is_configured_for_family(link, AF_INET))
854✔
417
                return 0;
418

419
        if (link->network->ipv4_force_igmp_version < 0)
854✔
420
                return 0;
421

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

425
static int link_set_ipv6_privacy_extensions(Link *link) {
854✔
426
        IPv6PrivacyExtensions val;
854✔
427

428
        assert(link);
854✔
429
        assert(link->manager);
854✔
430

431
        if (!link_is_configured_for_family(link, AF_INET6))
854✔
432
                return 0;
433

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

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

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

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

449
        if (!link_is_configured_for_family(link, AF_INET6))
854✔
450
                return 0;
451

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

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

459
        if (!link_is_configured_for_family(link, AF_INET6))
854✔
460
                return 0;
461

462
        if (link->network->ipv6_dad_transmits < 0)
854✔
463
                return 0;
464

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

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

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

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

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

481
static int link_set_ipv6_retransmission_time(Link *link) {
854✔
482
        usec_t retrans_time_ms;
854✔
483

484
        assert(link);
854✔
485
        assert(link->manager);
854✔
486

487
        if (!link_is_configured_for_family(link, AF_INET6))
854✔
488
                return 0;
489

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

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

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

500
static int link_set_ipv6_proxy_ndp(Link *link) {
854✔
501
        bool v;
854✔
502

503
        assert(link);
854✔
504
        assert(link->manager);
854✔
505

506
        if (!link_is_configured_for_family(link, AF_INET6))
854✔
507
                return 0;
508

509
        if (link->network->ipv6_proxy_ndp >= 0)
854✔
510
                v = link->network->ipv6_proxy_ndp;
2✔
511
        else
512
                v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
852✔
513

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

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

521
        assert(link);
1,596✔
522
        assert(link->manager);
1,596✔
523

524
        if (!link_is_configured_for_family(link, AF_INET6))
1,596✔
525
                return 0;
526

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

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

535
        assert(link->network);
1,592✔
536

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

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

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

555
        return 0;
556
}
557

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

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

564
        assert(link);
44✔
565

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

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

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

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

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

589
                return 1; /* done */
43✔
590
        }
591

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

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

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

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

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

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

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

628
int link_set_ipv6_mtu_async(Link *link) {
44✔
629
        assert(link);
44✔
630

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

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

639
        if (!link_is_configured_for_family(link, AF_INET))
854✔
640
                return 0;
641

642
        if (link->network->ipv4_accept_local < 0)
854✔
643
                return 0;
644

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

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

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

655
        if (link->network->ipv4_route_localnet < 0)
854✔
656
                return 0;
657

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

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

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

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

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

680
        if (!link_is_configured_for_family(link, AF_MPLS))
854✔
681
                return 0;
682

683
        if (link->network->mpls_input < 0)
854✔
684
                return 0;
685

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

689
int link_set_sysctl(Link *link) {
854✔
690
        int r;
854✔
691

692
        assert(link);
854✔
693

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

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

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

708
        (void) link_set_ip_forwarding(link, AF_INET);
854✔
709
        (void) link_set_ip_forwarding(link, AF_INET6);
854✔
710

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

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

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

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

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

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

735
        (void) link_set_ipv6_mtu(link, LOG_INFO);
854✔
736

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

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

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

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

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

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

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

765
        return 0;
854✔
766
}
767

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

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

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

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

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

800
        assert(filename);
×
801

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

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

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