]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: introduce per-interface IP forwarding settings
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
f579559b 2
9aa5d8ba
YW
3#include <net/if.h>
4#include <netinet/in.h>
01234e1f 5#include <linux/netdevice.h>
a0b191b7 6#include <unistd.h>
69a93e7d 7
b5efdb8a 8#include "alloc-util.h"
f579559b
TG
9#include "conf-files.h"
10#include "conf-parser.h"
37de2509 11#include "dns-domain.h"
3ffd4af2 12#include "fd-util.h"
07630cea 13#include "hostname-util.h"
88295a05 14#include "in-addr-util.h"
7e19cc54 15#include "net-condition.h"
c918b70a 16#include "netdev/macvlan.h"
fb486c90 17#include "networkd-address-label.h"
093e3533 18#include "networkd-address.h"
9671ae9d 19#include "networkd-bridge-fdb.h"
ff9e0783 20#include "networkd-bridge-mdb.h"
22d37e5d 21#include "networkd-dhcp-common.h"
c517a49b 22#include "networkd-dhcp-server-static-lease.h"
14d9ab9d 23#include "networkd-ipv6-proxy-ndp.h"
23f53b99 24#include "networkd-manager.h"
3773eb54 25#include "networkd-ndisc.h"
1939ebeb 26#include "networkd-neighbor.h"
3ffd4af2 27#include "networkd-network.h"
75156ccb 28#include "networkd-nexthop.h"
b5ce4047 29#include "networkd-radv.h"
3b6a3bde 30#include "networkd-route.h"
ca183bf8 31#include "networkd-routing-policy-rule.h"
518cd6b5 32#include "networkd-sriov.h"
6bedfcbb 33#include "parse-util.h"
b0c82192 34#include "path-lookup.h"
3a67b8bb 35#include "qdisc.h"
4f1ac4a3 36#include "radv-internal.h"
8a516214 37#include "set.h"
cebe1257 38#include "socket-util.h"
8fcde012 39#include "stat-util.h"
8b43440b 40#include "string-table.h"
07630cea 41#include "string-util.h"
700f1186 42#include "strv.h"
3a67b8bb 43#include "tclass.h"
f579559b 44
c448459d 45/* Let's assume that anything above this number is a user misconfiguration. */
63b98386 46#define MAX_NTP_SERVERS 128U
c448459d 47
8f9bdeab 48static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret) {
cebe1257
YW
49 const char *kind_string;
50 NetDev *netdev;
51 int r;
52
96db6412
YW
53 /* For test-networkd-conf, the check must be earlier than the assertions. */
54 if (!name)
55 return 0;
56
cebe1257
YW
57 assert(network);
58 assert(network->manager);
59 assert(network->filename);
8f9bdeab 60 assert(ret);
cebe1257 61
cebe1257
YW
62 if (kind == _NETDEV_KIND_TUNNEL)
63 kind_string = "tunnel";
64 else {
65 kind_string = netdev_kind_to_string(kind);
66 if (!kind_string)
8f9bdeab
YW
67 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
68 "%s: Invalid NetDev kind of %s, ignoring assignment.",
69 network->filename, name);
cebe1257
YW
70 }
71
72 r = netdev_get(network->manager, name, &netdev);
73 if (r < 0)
8f9bdeab
YW
74 return log_warning_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
75 network->filename, name);
cebe1257
YW
76
77 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
78 IN_SET(netdev->kind,
bc945c2b 79 NETDEV_KIND_ERSPAN,
cebe1257
YW
80 NETDEV_KIND_GRE,
81 NETDEV_KIND_GRETAP,
82 NETDEV_KIND_IP6GRE,
83 NETDEV_KIND_IP6GRETAP,
9282f75b 84 NETDEV_KIND_IP6TNL,
bc945c2b
YW
85 NETDEV_KIND_IPIP,
86 NETDEV_KIND_SIT,
87 NETDEV_KIND_VTI,
88 NETDEV_KIND_VTI6)))
8f9bdeab
YW
89 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
90 "%s: NetDev %s is not a %s, ignoring assignment",
91 network->filename, name, kind_string);
cebe1257 92
8f9bdeab 93 *ret = netdev_ref(netdev);
cebe1257
YW
94 return 1;
95}
96
97static int network_resolve_stacked_netdevs(Network *network) {
98 void *name, *kind;
cebe1257
YW
99 int r;
100
101 assert(network);
102
90e74a66 103 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names) {
cebe1257
YW
104 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
105
8f9bdeab 106 if (network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev) <= 0)
cebe1257
YW
107 continue;
108
dcd46cc4
SS
109 r = hashmap_ensure_put(&network->stacked_netdevs, &string_hash_ops, netdev->ifname, netdev);
110 if (r == -ENOMEM)
cebe1257 111 return log_oom();
cebe1257 112 if (r < 0)
8f9bdeab
YW
113 log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
114 network->filename, (const char *) name);
cebe1257
YW
115
116 netdev = NULL;
117 }
118
119 return 0;
120}
121
96db6412 122int network_verify(Network *network) {
50783f91
YW
123 int r;
124
0321cea7 125 assert(network);
ea853de5 126 assert(network->manager);
0321cea7
YW
127 assert(network->filename);
128
5722fb89 129 if (net_match_is_empty(&network->match) && !network->conditions)
dade7349
ZJS
130 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
131 "%s: No valid settings found in the [Match] section, ignoring file. "
132 "To match all interfaces, add Name=* in the [Match] section.",
133 network->filename);
84ea567e 134
cebe1257 135 /* skip out early if configuration does not match the environment */
a0b191b7 136 if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
cebe1257 137 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
138 "%s: Conditions in the file do not match the system environment, skipping.",
139 network->filename);
cebe1257 140
57aef9d7
YW
141 if (network->keep_master) {
142 if (network->batadv_name)
143 log_warning("%s: BatmanAdvanced= set with KeepMaster= enabled, ignoring BatmanAdvanced=.",
144 network->filename);
145 if (network->bond_name)
146 log_warning("%s: Bond= set with KeepMaster= enabled, ignoring Bond=.",
147 network->filename);
148 if (network->bridge_name)
149 log_warning("%s: Bridge= set with KeepMaster= enabled, ignoring Bridge=.",
150 network->filename);
151 if (network->vrf_name)
152 log_warning("%s: VRF= set with KeepMaster= enabled, ignoring VRF=.",
153 network->filename);
154
155 network->batadv_name = mfree(network->batadv_name);
156 network->bond_name = mfree(network->bond_name);
157 network->bridge_name = mfree(network->bridge_name);
158 network->vrf_name = mfree(network->vrf_name);
159 }
160
c0267a59 161 (void) network_resolve_netdev_one(network, network->batadv_name, NETDEV_KIND_BATADV, &network->batadv);
cebe1257
YW
162 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
163 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
164 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
8f9bdeab
YW
165 r = network_resolve_stacked_netdevs(network);
166 if (r < 0)
167 return r;
cebe1257
YW
168
169 /* Free unnecessary entries. */
c0267a59 170 network->batadv_name = mfree(network->batadv_name);
cebe1257
YW
171 network->bond_name = mfree(network->bond_name);
172 network->bridge_name = mfree(network->bridge_name);
173 network->vrf_name = mfree(network->vrf_name);
174 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
175
0321cea7
YW
176 if (network->bond) {
177 /* Bonding slave does not support addressing. */
0321cea7 178 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
179 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
180 network->filename);
0321cea7
YW
181 network->link_local = ADDRESS_FAMILY_NO;
182 }
9cd9fc8f 183 if (!ordered_hashmap_isempty(network->addresses_by_section))
ab24039f
ZJS
184 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
185 network->filename);
2a54a044 186 if (!hashmap_isempty(network->routes_by_section))
ab24039f
ZJS
187 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
188 network->filename);
9cd9fc8f 189
ebd96906 190 network->addresses_by_section = ordered_hashmap_free(network->addresses_by_section);
74c301b9 191 network->routes_by_section = hashmap_free(network->routes_by_section);
0321cea7
YW
192 }
193
c918b70a
TY
194 if (network->link_local < 0) {
195 network->link_local = ADDRESS_FAMILY_IPV6;
196
57aef9d7 197 if (network->keep_master || network->bridge)
c918b70a
TY
198 network->link_local = ADDRESS_FAMILY_NO;
199 else {
200 NetDev *netdev;
201
202 HASHMAP_FOREACH(netdev, network->stacked_netdevs) {
203 MacVlan *m;
204
205 if (netdev->kind == NETDEV_KIND_MACVLAN)
206 m = MACVLAN(netdev);
207 else if (netdev->kind == NETDEV_KIND_MACVTAP)
208 m = MACVTAP(netdev);
209 else
210 continue;
211
212 if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU)
213 network->link_local = ADDRESS_FAMILY_NO;
214
215 /* There won't be a passthru MACVLAN/MACVTAP if there's already one in another mode */
216 break;
217 }
218 }
219 }
220
75d5abd2
YW
221 if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE)
222 SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false);
8f191801 223
9e1432d5
YW
224 if (in6_addr_is_set(&network->ipv6ll_stable_secret) &&
225 network->ipv6ll_address_gen_mode < 0)
226 network->ipv6ll_address_gen_mode = IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
227
14d9ab9d 228 network_adjust_ipv6_proxy_ndp(network);
3773eb54 229 network_adjust_ipv6_accept_ra(network);
22d37e5d 230 network_adjust_dhcp(network);
69e0f833 231 network_adjust_radv(network);
5546870e 232 network_adjust_bridge_vlan(network);
3773eb54 233
933c70a0 234 if (network->mtu > 0 && network->dhcp_use_mtu) {
0321cea7
YW
235 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
236 "Disabling UseMTU=.", network->filename);
237 network->dhcp_use_mtu = false;
238 }
239
7da377ef 240 if (network->dhcp_critical >= 0) {
ea853de5
YW
241 if (network->keep_configuration >= 0) {
242 if (network->manager->keep_configuration < 0)
243 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
244 "Ignoring CriticalConnection=.", network->filename);
245 } else if (network->dhcp_critical)
7da377ef
SS
246 /* CriticalConnection=yes also preserve foreign static configurations. */
247 network->keep_configuration = KEEP_CONFIGURATION_YES;
248 else
80060352 249 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef
SS
250 }
251
61135582
DS
252 if (!strv_isempty(network->bind_carrier)) {
253 if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND))
254 log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. "
255 "Setting ActivationPolicy=bound.", network->filename);
256 network->activation_policy = ACTIVATION_POLICY_BOUND;
257 } else if (network->activation_policy == ACTIVATION_POLICY_BOUND) {
258 log_warning("%s: ActivationPolicy=bound requires BindCarrier=. "
259 "Ignoring ActivationPolicy=bound.", network->filename);
260 network->activation_policy = ACTIVATION_POLICY_UP;
261 }
262
263 if (network->activation_policy == _ACTIVATION_POLICY_INVALID)
264 network->activation_policy = ACTIVATION_POLICY_UP;
265
266 if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
6706ce2f
YW
267 if (network->ignore_carrier_loss_set && network->ignore_carrier_loss_usec < USEC_INFINITY)
268 log_warning("%s: IgnoreCarrierLoss=no or finite timespan conflicts with ActivationPolicy=always-up. "
269 "Setting IgnoreCarrierLoss=yes.", network->filename);
270 network->ignore_carrier_loss_set = true;
271 network->ignore_carrier_loss_usec = USEC_INFINITY;
61135582
DS
272 }
273
27438545 274 if (!network->ignore_carrier_loss_set) /* Set implied default. */
6706ce2f 275 network->ignore_carrier_loss_usec = network->configure_without_carrier ? USEC_INFINITY : 0;
61135582 276
7c644a69
DS
277 if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) {
278 if (network->required_for_online < 0 ||
279 (network->required_for_online == true && network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN)) {
280 log_debug("%s: Setting RequiredForOnline=no because ActivationPolicy=%s.", network->filename,
281 activation_policy_to_string(network->activation_policy));
282 network->required_for_online = false;
283 } else if (network->required_for_online == true)
284 log_warning("%s: RequiredForOnline=yes and ActivationPolicy=%s, "
285 "this may cause a delay at boot.", network->filename,
286 activation_policy_to_string(network->activation_policy));
287 }
288
289 if (network->required_for_online < 0)
290 network->required_for_online = true;
291
7da377ef 292 if (network->keep_configuration < 0)
80060352 293 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef 294
87851e0f
YW
295 if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
296 log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
297 network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
298 }
299
50783f91
YW
300 r = network_drop_invalid_addresses(network);
301 if (r < 0)
61ec7bea 302 return r; /* network_drop_invalid_addresses() logs internally. */
13ffa39f 303 network_drop_invalid_routes(network);
015b2432
YW
304 r = network_drop_invalid_nexthops(network);
305 if (r < 0)
306 return r;
9671ae9d 307 network_drop_invalid_bridge_fdb_entries(network);
ff9e0783 308 network_drop_invalid_bridge_mdb_entries(network);
aa9626ee
YW
309 r = network_drop_invalid_neighbors(network);
310 if (r < 0)
311 return r;
13ffa39f
YW
312 network_drop_invalid_address_labels(network);
313 network_drop_invalid_prefixes(network);
314 network_drop_invalid_route_prefixes(network);
315 network_drop_invalid_routing_policy_rules(network);
3a67b8bb
YW
316 network_drop_invalid_qdisc(network);
317 network_drop_invalid_tclass(network);
41ce9d76 318 r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section);
e217e22a 319 if (r < 0)
61ec7bea 320 return r; /* sr_iov_drop_invalid_sections() logs internally. */
c517a49b 321 network_drop_invalid_static_leases(network);
518cd6b5 322
0321cea7
YW
323 return 0;
324}
325
7f06b3e1 326int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
838b2f7a 327 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 328 _cleanup_(network_unrefp) Network *network = NULL;
047a0dac 329 const char *dropin_dirname;
838b2f7a 330 char *d;
f579559b
TG
331 int r;
332
bf1bc670
TA
333 assert(manager);
334 assert(filename);
335
4e54a17d 336 r = null_or_empty_path(filename);
4e54a17d 337 if (r < 0)
61ec7bea 338 return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
4e54a17d 339 if (r > 0) {
ed88bcfb 340 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
341 return 0;
342 }
343
838b2f7a
YW
344 fname = strdup(filename);
345 if (!fname)
346 return log_oom();
347
348 name = strdup(basename(filename));
349 if (!name)
350 return log_oom();
351
352 d = strrchr(name, '.');
353 if (!d)
61ec7bea 354 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file name: %s", filename);
838b2f7a
YW
355
356 *d = '\0';
357
358 dropin_dirname = strjoina(name, ".network.d");
359
17f9c355 360 network = new(Network, 1);
f579559b
TG
361 if (!network)
362 return log_oom();
363
17f9c355 364 *network = (Network) {
838b2f7a
YW
365 .filename = TAKE_PTR(fname),
366 .name = TAKE_PTR(name),
17f9c355 367
715d398e 368 .manager = manager,
35ac3b76
YW
369 .n_ref = 1,
370
7c644a69 371 .required_for_online = -1,
3255bda6 372 .required_operstate_for_online = LINK_OPERSTATE_RANGE_INVALID,
61135582 373 .activation_policy = _ACTIVATION_POLICY_INVALID,
cee68339 374 .group = -1,
db5756f3
YW
375 .arp = -1,
376 .multicast = -1,
377 .allmulticast = -1,
937e305e 378 .promiscuous = -1,
db5756f3 379
ea853de5 380 .keep_configuration = manager->keep_configuration,
db5756f3 381
4e26a5ba 382 .dhcp_duid.type = _DUID_TYPE_INVALID,
7da377ef 383 .dhcp_critical = -1,
17f9c355 384 .dhcp_use_ntp = true,
d7b04506 385 .dhcp_routes_to_ntp = true,
299d578f 386 .dhcp_use_sip = true,
edb88a72 387 .dhcp_use_captive_portal = true,
17f9c355 388 .dhcp_use_dns = true,
70570306 389 .dhcp_routes_to_dns = true,
17f9c355
YW
390 .dhcp_use_hostname = true,
391 .dhcp_use_routes = true,
589397a2 392 .dhcp_use_gateway = -1,
17f9c355 393 .dhcp_send_hostname = true,
5f3b5f19 394 .dhcp_send_release = true,
17f9c355 395 .dhcp_route_metric = DHCP_ROUTE_METRIC,
cf289b14 396 .dhcp_use_rapid_commit = -1,
f90635f1 397 .dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
17f9c355 398 .dhcp_route_table = RT_TABLE_MAIN,
db5756f3 399 .dhcp_ip_service_type = -1,
e70eca9b 400 .dhcp_broadcast = -1,
fc35a9f8 401 .dhcp_ipv6_only_mode = -1,
17f9c355 402
1536b7b2 403 .dhcp6_use_address = true,
0f5ef9b6 404 .dhcp6_use_pd_prefix = true,
1536b7b2 405 .dhcp6_use_dns = true,
38ba3da0 406 .dhcp6_use_hostname = true,
1536b7b2 407 .dhcp6_use_ntp = true,
a75feb55 408 .dhcp6_use_captive_portal = true,
50ee1fec 409 .dhcp6_use_rapid_commit = true,
b90480c8 410 .dhcp6_send_hostname = true,
4e26a5ba 411 .dhcp6_duid.type = _DUID_TYPE_INVALID,
0e45721e 412 .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
b895aa5f 413 .dhcp6_send_release = true,
caa8ca42 414
a27588d4
YW
415 .dhcp_pd = -1,
416 .dhcp_pd_announce = true,
417 .dhcp_pd_assign = true,
418 .dhcp_pd_manage_temporary_address = true,
419 .dhcp_pd_subnet_id = -1,
420 .dhcp_pd_route_metric = DHCP6PD_ROUTE_METRIC,
9efa8a3c 421
21b6b87e 422 .dhcp_server_bind_to_interface = true,
2a71d57f
LP
423 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
424 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
425 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
17f9c355
YW
426 .dhcp_server_emit_router = true,
427 .dhcp_server_emit_timezone = true,
1fa0a4ef 428 .dhcp_server_rapid_commit = true,
17f9c355 429
4f1ac4a3 430 .router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
c9e2c2da 431 .router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
17f9c355
YW
432 .router_emit_dns = true,
433 .router_emit_domains = true,
434
435 .use_bpdu = -1,
436 .hairpin = -1,
97f27f8a 437 .isolated = -1,
17f9c355
YW
438 .fast_leave = -1,
439 .allow_port_to_be_root = -1,
440 .unicast_flood = -1,
7f15b714 441 .multicast_flood = -1,
d3aa8b49 442 .multicast_to_unicast = -1,
7f15b714
TJ
443 .neighbor_suppression = -1,
444 .learning = -1,
1087623b
SS
445 .bridge_proxy_arp = -1,
446 .bridge_proxy_arp_wifi = -1,
17f9c355 447 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 448 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355 449
228693af 450 .bridge_vlan_pvid = BRIDGE_VLAN_KEEP_PVID,
0b8d501c 451
17f9c355 452 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
c01b9b87 453 .lldp_multicast_mode = _SD_LLDP_MULTICAST_MODE_INVALID,
17f9c355 454
7ece6f58 455 .dns_default_route = -1,
17f9c355
YW
456 .llmnr = RESOLVE_SUPPORT_YES,
457 .mdns = RESOLVE_SUPPORT_NO,
458 .dnssec_mode = _DNSSEC_MODE_INVALID,
459 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
460
0321cea7 461 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 462 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 463 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 464
3976c430 465 .ip_forwarding = { -1, -1, },
94d76d07 466 .ipv4_accept_local = -1,
d75bf6cf 467 .ipv4_route_localnet = -1,
932ef6ec 468 .ipv6_privacy_extensions = _IPV6_PRIVACY_EXTENSIONS_INVALID,
17f9c355 469 .ipv6_dad_transmits = -1,
17f9c355 470 .ipv6_proxy_ndp = -1,
17f9c355 471 .proxy_arp = -1,
b4959550 472 .proxy_arp_pvlan = -1,
9c72e8f8 473 .ipv4_rp_filter = _IP_REVERSE_PATH_FILTER_INVALID,
db5756f3 474
7d93b92f 475 .ipv6_accept_ra = -1,
17f9c355 476 .ipv6_accept_ra_use_dns = true,
610c0db1 477 .ipv6_accept_ra_use_gateway = true,
9747955d 478 .ipv6_accept_ra_use_captive_portal = true,
610c0db1 479 .ipv6_accept_ra_use_route_prefix = true,
062c2eea
SS
480 .ipv6_accept_ra_use_autonomous_prefix = true,
481 .ipv6_accept_ra_use_onlink_prefix = true,
7d93b92f 482 .ipv6_accept_ra_use_mtu = true,
f141b2c0 483 .ipv6_accept_ra_use_hop_limit = true,
1452d497 484 .ipv6_accept_ra_use_reachable_time = true,
d4c8de21 485 .ipv6_accept_ra_use_retransmission_time = true,
91750028 486 .ipv6_accept_ra_use_icmp6_ratelimit = true,
17f9c355 487 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
6f812d28
YW
488 .ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
489 .ipv6_accept_ra_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
490 .ipv6_accept_ra_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
cabe5711 491 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
c423be28 492
52aa38f1 493 .can_termination = -1,
72e65e6f
YW
494
495 .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
496 .ipoib_umcast = -1,
17f9c355 497 };
f579559b 498
4f9ff96a 499 r = config_parse_many(
947f59ba 500 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root = */ NULL,
4f9ff96a
LP
501 "Match\0"
502 "Link\0"
518cd6b5 503 "SR-IOV\0"
4f9ff96a
LP
504 "Network\0"
505 "Address\0"
506 "Neighbor\0"
507 "IPv6AddressLabel\0"
508 "RoutingPolicyRule\0"
509 "Route\0"
510 "NextHop\0"
511 "DHCP\0" /* compat */
512 "DHCPv4\0"
513 "DHCPv6\0"
a27588d4
YW
514 "DHCPv6PrefixDelegation\0" /* compat */
515 "DHCPPrefixDelegation\0"
4f9ff96a 516 "DHCPServer\0"
c517a49b 517 "DHCPServerStaticLease\0"
4f9ff96a
LP
518 "IPv6AcceptRA\0"
519 "IPv6NDPProxyAddress\0"
520 "Bridge\0"
521 "BridgeFDB\0"
3db468ea 522 "BridgeMDB\0"
4f9ff96a 523 "BridgeVLAN\0"
27ff0490 524 "IPv6SendRA\0"
4f9ff96a
LP
525 "IPv6PrefixDelegation\0"
526 "IPv6Prefix\0"
527 "IPv6RoutePrefix\0"
1925f829 528 "IPv6PREF64Prefix\0"
4f9ff96a
LP
529 "LLDP\0"
530 "TrafficControlQueueingDiscipline\0"
531 "CAN\0"
532 "QDisc\0"
533 "BFIFO\0"
534 "CAKE\0"
535 "ControlledDelay\0"
536 "DeficitRoundRobinScheduler\0"
537 "DeficitRoundRobinSchedulerClass\0"
d474aa51 538 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
539 "FairQueueing\0"
540 "FairQueueingControlledDelay\0"
8f6b6d70 541 "FlowQueuePIE\0"
4f9ff96a
LP
542 "GenericRandomEarlyDetection\0"
543 "HeavyHitterFilter\0"
544 "HierarchyTokenBucket\0"
545 "HierarchyTokenBucketClass\0"
546 "NetworkEmulator\0"
b12aaee5
SS
547 "PFIFO\0"
548 "PFIFOFast\0"
549 "PFIFOHeadDrop\0"
4f9ff96a 550 "PIE\0"
b12aaee5 551 "QuickFairQueueing\0"
4d7ddaf9 552 "QuickFairQueueingClass\0"
4f9ff96a
LP
553 "StochasticFairBlue\0"
554 "StochasticFairnessQueueing\0"
555 "TokenBucketFilter\0"
556 "TrivialLinkEqualizer\0",
557 config_item_perf_lookup, network_network_gperf_lookup,
558 CONFIG_PARSE_WARN,
559 network,
ead3a3fc 560 &network->stats_by_path,
a2640646 561 &network->dropins);
102bc043 562 if (r < 0)
61ec7bea 563 return r; /* config_parse_many() logs internally. */
f579559b 564
fa7cd711
YW
565 r = network_add_ipv4ll_route(network);
566 if (r < 0)
9202b567 567 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
fa7cd711 568
5d5003ab
YW
569 r = network_add_default_route_on_device(network);
570 if (r < 0)
9202b567
YW
571 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
572 network->filename);
5d5003ab 573
9202b567 574 r = network_verify(network);
9202b567 575 if (r < 0)
61ec7bea 576 return r; /* network_verify() logs internally. */
7f06b3e1 577
9fa3e794 578 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
dbffab87 579 if (r < 0)
61ec7bea 580 return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
dbffab87 581
b5b9b0e7 582 TAKE_PTR(network);
f579559b
TG
583 return 0;
584}
585
7f06b3e1 586int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5 587 _cleanup_strv_free_ char **files = NULL;
f579559b
TG
588 int r;
589
590 assert(manager);
591
7f06b3e1 592 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 593
dc0d4078 594 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
595 if (r < 0)
596 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 597
036a8d50
YW
598 STRV_FOREACH(f, files)
599 (void) network_load_one(manager, networks, *f);
f579559b 600
f579559b
TG
601 return 0;
602}
603
7f06b3e1
YW
604int network_reload(Manager *manager) {
605 OrderedHashmap *new_networks = NULL;
606 Network *n, *old;
7f06b3e1
YW
607 int r;
608
609 assert(manager);
610
611 r = network_load(manager, &new_networks);
612 if (r < 0)
613 goto failure;
614
90e74a66 615 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1 616 r = network_get_by_name(manager, n->name, &old);
8524db50
YW
617 if (r < 0) {
618 log_debug("Found new .network file: %s", n->filename);
619 continue;
620 }
7f06b3e1 621
8524db50
YW
622 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
623 log_debug("Found updated .network file: %s", n->filename);
7f06b3e1 624 continue;
8524db50 625 }
7f06b3e1
YW
626
627 r = ordered_hashmap_replace(new_networks, old->name, old);
628 if (r < 0)
629 goto failure;
630
631 network_ref(old);
632 network_unref(n);
633 }
634
635 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
636 manager->networks = new_networks;
637
fb126bb1
YW
638 r = manager_build_dhcp_pd_subnet_ids(manager);
639 if (r < 0)
640 return r;
641
642 r = manager_build_nexthop_ids(manager);
643 if (r < 0)
644 return r;
645
646 return 0;
7f06b3e1
YW
647
648failure:
649 ordered_hashmap_free_with_destructor(new_networks, network_unref);
650
651 return r;
652}
653
a27588d4 654int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
1a4ca0e2
YW
655 Network *n;
656 int r;
657
658 assert(manager);
659
a27588d4 660 set_clear(manager->dhcp_pd_subnet_ids);
1a4ca0e2
YW
661
662 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
663 if (n->unmanaged)
664 continue;
665
a27588d4 666 if (!n->dhcp_pd)
1a4ca0e2
YW
667 continue;
668
a27588d4 669 if (n->dhcp_pd_subnet_id < 0)
1a4ca0e2
YW
670 continue;
671
a27588d4 672 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
1a4ca0e2
YW
673 if (r < 0)
674 return r;
675 }
676
677 return 0;
678}
679
35ac3b76 680static Network *network_free(Network *network) {
f579559b 681 if (!network)
35ac3b76 682 return NULL;
f579559b 683
54e0cfc4 684 free(network->name);
f579559b 685 free(network->filename);
54e0cfc4 686 free(network->description);
a2640646 687 strv_free(network->dropins);
8524db50 688 hashmap_free(network->stats_by_path);
f579559b 689
54e0cfc4 690 /* conditions */
5722fb89 691 net_match_clear(&network->match);
c4f58dea 692 condition_free_list(network->conditions);
f579559b 693
54e0cfc4
YW
694 /* link settings */
695 strv_free(network->bind_carrier);
696
697 /* NTP */
698 strv_free(network->ntp);
699
700 /* DNS */
701 for (unsigned i = 0; i < network->n_dns; i++)
702 in_addr_full_free(network->dns[i]);
703 free(network->dns);
704 ordered_set_free(network->search_domains);
705 ordered_set_free(network->route_domains);
706 set_free_free(network->dnssec_negative_trust_anchors);
707
708 /* DHCP server */
11c38d3e
YA
709 free(network->dhcp_server_relay_agent_circuit_id);
710 free(network->dhcp_server_relay_agent_remote_id);
6278e428
YW
711 free(network->dhcp_server_boot_server_name);
712 free(network->dhcp_server_boot_filename);
54e0cfc4
YW
713 free(network->dhcp_server_timezone);
714 free(network->dhcp_server_uplink_name);
715 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
716 free(network->dhcp_server_emit[t].addresses);
717 ordered_hashmap_free(network->dhcp_server_send_options);
718 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
11c38d3e 719
54e0cfc4 720 /* DHCP client */
edb85f0d 721 free(network->dhcp_vendor_class_identifier);
7b8d23a9 722 free(network->dhcp_mudurl);
27cb34f5 723 free(network->dhcp_hostname);
d419ef02 724 free(network->dhcp_label);
6b000af4 725 set_free(network->dhcp_deny_listed_ip);
98ebef62 726 set_free(network->dhcp_allow_listed_ip);
54e0cfc4 727 strv_free(network->dhcp_user_class);
5bc945be 728 set_free(network->dhcp_request_options);
54e0cfc4
YW
729 ordered_hashmap_free(network->dhcp_client_send_options);
730 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
4b3590c3 731 free(network->dhcp_netlabel);
fc289dd0 732 nft_set_context_clear(&network->dhcp_nft_set_context);
54e0cfc4
YW
733
734 /* DHCPv6 client */
3175a8c2 735 free(network->dhcp6_mudurl);
9968ca32 736 free(network->dhcp6_hostname);
f37f2a6b 737 strv_free(network->dhcp6_user_class);
ed0d1b2e 738 strv_free(network->dhcp6_vendor_class);
54e0cfc4
YW
739 set_free(network->dhcp6_request_options);
740 ordered_hashmap_free(network->dhcp6_client_send_options);
741 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
4b3590c3 742 free(network->dhcp6_netlabel);
fc289dd0 743 nft_set_context_clear(&network->dhcp6_nft_set_context);
c106cc36 744
54e0cfc4
YW
745 /* DHCP PD */
746 free(network->dhcp_pd_uplink_name);
747 set_free(network->dhcp_pd_tokens);
4b3590c3 748 free(network->dhcp_pd_netlabel);
fc289dd0 749 nft_set_context_clear(&network->dhcp_pd_nft_set_context);
cdd7812b 750
54e0cfc4 751 /* Router advertisement */
5e276772 752 ordered_set_free(network->router_search_domains);
cdd7812b 753 free(network->router_dns);
54e0cfc4
YW
754 free(network->router_uplink_name);
755
756 /* NDisc */
c995fa02
YW
757 set_free(network->ndisc_deny_listed_router);
758 set_free(network->ndisc_allow_listed_router);
759 set_free(network->ndisc_deny_listed_prefix);
760 set_free(network->ndisc_allow_listed_prefix);
761 set_free(network->ndisc_deny_listed_route_prefix);
762 set_free(network->ndisc_allow_listed_route_prefix);
54e0cfc4 763 set_free(network->ndisc_tokens);
4b3590c3 764 free(network->ndisc_netlabel);
fc289dd0 765 nft_set_context_clear(&network->ndisc_nft_set_context);
3bef724f 766
54e0cfc4
YW
767 /* LLDP */
768 free(network->lldp_mudurl);
769
770 /* netdev */
c0267a59 771 free(network->batadv_name);
cebe1257
YW
772 free(network->bridge_name);
773 free(network->bond_name);
774 free(network->vrf_name);
775 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 776 netdev_unref(network->bridge);
47e2dc31 777 netdev_unref(network->bond);
6cb955c6 778 netdev_unref(network->vrf);
fa6f1e54 779 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 780
54e0cfc4 781 /* static configs */
d349f502 782 set_free_free(network->ipv6_proxy_ndp_addresses);
ebd96906 783 ordered_hashmap_free(network->addresses_by_section);
74c301b9 784 hashmap_free(network->routes_by_section);
59ac53a6 785 ordered_hashmap_free(network->nexthops_by_section);
9671ae9d 786 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
ff9e0783 787 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
2a75f23b 788 ordered_hashmap_free(network->neighbors_by_section);
d6a2a0f9 789 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
ecb0e85e
YW
790 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
791 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
1925f829 792 hashmap_free_with_destructor(network->pref64_prefixes_by_section, pref64_prefix_free);
ca183bf8 793 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
c517a49b 794 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
518cd6b5 795 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
3a67b8bb
YW
796 hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free);
797 hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
6ae115c1 798
35ac3b76 799 return mfree(network);
f579559b
TG
800}
801
35ac3b76
YW
802DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
803
dbffab87
TG
804int network_get_by_name(Manager *manager, const char *name, Network **ret) {
805 Network *network;
806
807 assert(manager);
808 assert(name);
809 assert(ret);
810
715d398e 811 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
812 if (!network)
813 return -ENOENT;
814
815 *ret = network;
816
817 return 0;
818}
819
adfeee49 820bool network_has_static_ipv6_configurations(Network *network) {
439689c6 821 Address *address;
adfeee49 822 Route *route;
9671ae9d 823 BridgeFDB *fdb;
ff9e0783 824 BridgeMDB *mdb;
adfeee49 825 Neighbor *neighbor;
439689c6
SS
826
827 assert(network);
828
9cd9fc8f 829 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
830 if (address->family == AF_INET6)
831 return true;
adfeee49 832
2a54a044 833 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
834 if (route->family == AF_INET6)
835 return true;
836
9671ae9d 837 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
adfeee49
YW
838 if (fdb->family == AF_INET6)
839 return true;
840
ff9e0783 841 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
3db468ea
DM
842 if (mdb->family == AF_INET6)
843 return true;
844
aa9626ee 845 ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
adfeee49
YW
846 if (neighbor->family == AF_INET6)
847 return true;
848
d6a2a0f9 849 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
850 return true;
851
ecb0e85e 852 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 853 return true;
d30081c2
YW
854
855 if (!hashmap_isempty(network->route_prefixes_by_section))
856 return true;
439689c6 857
1925f829
SS
858 if (!hashmap_isempty(network->pref64_prefixes_by_section))
859 return true;
860
439689c6
SS
861 return false;
862}
863
63481576
YW
864int config_parse_stacked_netdev(
865 const char *unit,
02b59d57
TG
866 const char *filename,
867 unsigned line,
868 const char *section,
869 unsigned section_line,
870 const char *lvalue,
871 int ltype,
872 const char *rvalue,
873 void *data,
874 void *userdata) {
63481576 875
95dba435
YW
876 _cleanup_free_ char *name = NULL;
877 NetDevKind kind = ltype;
99534007 878 Hashmap **h = ASSERT_PTR(data);
02b59d57
TG
879 int r;
880
881 assert(filename);
882 assert(lvalue);
883 assert(rvalue);
95dba435 884 assert(IN_SET(kind,
b90d0f83 885 NETDEV_KIND_IPOIB,
bc945c2b
YW
886 NETDEV_KIND_IPVLAN,
887 NETDEV_KIND_IPVTAP,
bc945c2b
YW
888 NETDEV_KIND_MACSEC,
889 NETDEV_KIND_MACVLAN,
890 NETDEV_KIND_MACVTAP,
891 NETDEV_KIND_VLAN,
892 NETDEV_KIND_VXLAN,
893 NETDEV_KIND_XFRM,
894 _NETDEV_KIND_TUNNEL));
54abf461 895
cebe1257 896 if (!ifname_valid(rvalue)) {
d96edb2c 897 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 898 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
899 return 0;
900 }
901
cebe1257
YW
902 name = strdup(rvalue);
903 if (!name)
904 return log_oom();
3e570042 905
6de530f2
SS
906 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
907 if (r == -ENOMEM)
cebe1257 908 return log_oom();
83ec4592 909 if (r < 0)
d96edb2c 910 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
911 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
912 else if (r == 0)
913 log_syntax(unit, LOG_DEBUG, filename, line, r,
914 "NetDev '%s' specified twice, ignoring.", name);
915 else
0c7bd7ec 916 TAKE_PTR(name);
47e2dc31 917
fe6b2d55
TG
918 return 0;
919}
7951dea2 920
3df9bec5
LP
921int config_parse_domains(
922 const char *unit,
923 const char *filename,
924 unsigned line,
925 const char *section,
926 unsigned section_line,
927 const char *lvalue,
928 int ltype,
929 const char *rvalue,
930 void *data,
931 void *userdata) {
932
99534007 933 Network *n = ASSERT_PTR(userdata);
6192b846
TG
934 int r;
935
5aafd5b1 936 assert(filename);
3df9bec5
LP
937 assert(lvalue);
938 assert(rvalue);
6192b846 939
3df9bec5 940 if (isempty(rvalue)) {
5e276772
YW
941 n->search_domains = ordered_set_free(n->search_domains);
942 n->route_domains = ordered_set_free(n->route_domains);
3df9bec5
LP
943 return 0;
944 }
67272d15 945
d96edb2c 946 for (const char *p = rvalue;;) {
3df9bec5
LP
947 _cleanup_free_ char *w = NULL, *normalized = NULL;
948 const char *domain;
949 bool is_route;
950
951 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
952 if (r == -ENOMEM)
953 return log_oom();
3df9bec5 954 if (r < 0) {
d96edb2c 955 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 956 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 957 return 0;
3df9bec5
LP
958 }
959 if (r == 0)
d96edb2c 960 return 0;
3df9bec5
LP
961
962 is_route = w[0] == '~';
963 domain = is_route ? w + 1 : w;
964
965 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
966 /* If the root domain appears as is, or the special token "*" is found, we'll
967 * consider this as routing domain, unconditionally. */
3df9bec5 968 is_route = true;
ab24039f
ZJS
969 domain = "."; /* make sure we don't allow empty strings, thus write the root
970 * domain as "." */
3df9bec5 971 } else {
7470cc4c 972 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 973 if (r < 0) {
d96edb2c 974 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 975 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
976 continue;
977 }
978
979 domain = normalized;
980
981 if (is_localhost(domain)) {
d96edb2c 982 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
983 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
984 domain);
37de2509 985 continue;
3df9bec5 986 }
37de2509 987 }
40274ed6 988
5e2a51d5 989 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
cf453507
YW
990 r = ordered_set_put_strdup(set, domain);
991 if (r == -EEXIST)
992 continue;
09451975
LP
993 if (r < 0)
994 return log_oom();
40274ed6 995 }
6192b846
TG
996}
997
8eb9058d
LP
998int config_parse_timezone(
999 const char *unit,
1000 const char *filename,
1001 unsigned line,
1002 const char *section,
1003 unsigned section_line,
1004 const char *lvalue,
1005 int ltype,
1006 const char *rvalue,
1007 void *data,
1008 void *userdata) {
1009
99534007 1010 char **tz = ASSERT_PTR(data);
8eb9058d
LP
1011 int r;
1012
1013 assert(filename);
1014 assert(lvalue);
1015 assert(rvalue);
1016
b40b8b06
YW
1017 if (isempty(rvalue)) {
1018 *tz = mfree(*tz);
1019 return 0;
1020 }
8eb9058d 1021
b40b8b06
YW
1022 r = verify_timezone(rvalue, LOG_WARNING);
1023 if (r < 0) {
1024 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1025 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1026 return 0;
1027 }
1028
b40b8b06 1029 return free_and_strdup_warn(tz, rvalue);
8eb9058d 1030}
1a04db0f 1031
53253824
SS
1032int config_parse_dns(
1033 const char *unit,
1034 const char *filename,
1035 unsigned line,
1036 const char *section,
1037 unsigned section_line,
1038 const char *lvalue,
1039 int ltype,
1040 const char *rvalue,
1041 void *data,
1042 void *userdata) {
1043
99534007 1044 Network *n = ASSERT_PTR(userdata);
53253824
SS
1045 int r;
1046
1047 assert(filename);
1048 assert(lvalue);
1049 assert(rvalue);
1050
d96edb2c 1051 if (isempty(rvalue)) {
e77bd3fd
YW
1052 for (unsigned i = 0; i < n->n_dns; i++)
1053 in_addr_full_free(n->dns[i]);
d96edb2c
YW
1054 n->dns = mfree(n->dns);
1055 n->n_dns = 0;
1056 return 0;
1057 }
1058
1059 for (const char *p = rvalue;;) {
e77bd3fd 1060 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 1061 _cleanup_free_ char *w = NULL;
e77bd3fd 1062 struct in_addr_full **m;
53253824 1063
d96edb2c 1064 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
1065 if (r == -ENOMEM)
1066 return log_oom();
1067 if (r < 0) {
d96edb2c 1068 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1069 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 1070 return 0;
53253824 1071 }
5512a963 1072 if (r == 0)
d96edb2c 1073 return 0;
53253824 1074
e77bd3fd 1075 r = in_addr_full_new_from_string(w, &dns);
53253824 1076 if (r < 0) {
d96edb2c 1077 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1078 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1079 continue;
1080 }
1081
e77bd3fd
YW
1082 if (IN_SET(dns->port, 53, 853))
1083 dns->port = 0;
1084
1085 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 1086 if (!m)
53253824
SS
1087 return log_oom();
1088
e77bd3fd 1089 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 1090 n->dns = m;
53253824 1091 }
53253824
SS
1092}
1093
8a516214
LP
1094int config_parse_dnssec_negative_trust_anchors(
1095 const char *unit,
1096 const char *filename,
1097 unsigned line,
1098 const char *section,
1099 unsigned section_line,
1100 const char *lvalue,
1101 int ltype,
1102 const char *rvalue,
1103 void *data,
1104 void *userdata) {
1105
99534007 1106 Set **nta = ASSERT_PTR(data);
8a516214
LP
1107 int r;
1108
5aafd5b1 1109 assert(filename);
8a516214
LP
1110 assert(lvalue);
1111 assert(rvalue);
1112
1113 if (isempty(rvalue)) {
5aafd5b1 1114 *nta = set_free_free(*nta);
8a516214
LP
1115 return 0;
1116 }
1117
d96edb2c 1118 for (const char *p = rvalue;;) {
8a516214
LP
1119 _cleanup_free_ char *w = NULL;
1120
1121 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1122 if (r == -ENOMEM)
1123 return log_oom();
8a516214 1124 if (r < 0) {
d96edb2c 1125 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1126 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1127 return 0;
8a516214
LP
1128 }
1129 if (r == 0)
d96edb2c 1130 return 0;
8a516214
LP
1131
1132 r = dns_name_is_valid(w);
1133 if (r <= 0) {
d96edb2c 1134 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1135 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1136 continue;
1137 }
1138
5aafd5b1 1139 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1140 if (r < 0)
1141 return log_oom();
8a516214 1142 }
8a516214 1143}
b2a81c0b 1144
26575990
LP
1145int config_parse_ntp(
1146 const char *unit,
1147 const char *filename,
1148 unsigned line,
1149 const char *section,
1150 unsigned section_line,
1151 const char *lvalue,
1152 int ltype,
1153 const char *rvalue,
1154 void *data,
1155 void *userdata) {
1156
99534007 1157 char ***l = ASSERT_PTR(data);
26575990
LP
1158 int r;
1159
5aafd5b1 1160 assert(filename);
26575990
LP
1161 assert(lvalue);
1162 assert(rvalue);
1163
1164 if (isempty(rvalue)) {
1165 *l = strv_free(*l);
1166 return 0;
1167 }
1168
d96edb2c 1169 for (const char *p = rvalue;;) {
26575990
LP
1170 _cleanup_free_ char *w = NULL;
1171
d96edb2c 1172 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1173 if (r == -ENOMEM)
1174 return log_oom();
1175 if (r < 0) {
d96edb2c 1176 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1177 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1178 return 0;
26575990
LP
1179 }
1180 if (r == 0)
d96edb2c 1181 return 0;
26575990
LP
1182
1183 r = dns_name_is_valid_or_address(w);
1184 if (r <= 0) {
d96edb2c 1185 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1186 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1187 continue;
af1c0de0
SS
1188 }
1189
c448459d
ZJS
1190 if (strv_length(*l) > MAX_NTP_SERVERS) {
1191 log_syntax(unit, LOG_WARNING, filename, line, 0,
1192 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1193 MAX_NTP_SERVERS, w);
d96edb2c 1194 return 0;
c448459d
ZJS
1195 }
1196
1197 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1198 if (r < 0)
1199 return log_oom();
af1c0de0 1200 }
af1c0de0
SS
1201}
1202
4ac77d63
YW
1203int config_parse_required_for_online(
1204 const char *unit,
1205 const char *filename,
1206 unsigned line,
1207 const char *section,
1208 unsigned section_line,
1209 const char *lvalue,
1210 int ltype,
1211 const char *rvalue,
1212 void *data,
1213 void *userdata) {
1214
99534007 1215 Network *network = ASSERT_PTR(userdata);
4ac77d63
YW
1216 int r;
1217
5aafd5b1
YW
1218 assert(filename);
1219 assert(lvalue);
1220 assert(rvalue);
5aafd5b1 1221
4ac77d63 1222 if (isempty(rvalue)) {
7c644a69 1223 network->required_for_online = -1;
3255bda6 1224 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_INVALID;
4ac77d63
YW
1225 return 0;
1226 }
1227
ba04f957 1228 r = parse_operational_state_range(rvalue, &network->required_operstate_for_online);
75cd4a5d 1229 if (r < 0) {
4ac77d63
YW
1230 r = parse_boolean(rvalue);
1231 if (r < 0) {
d96edb2c 1232 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1233 "Failed to parse %s= setting, ignoring assignment: %s",
1234 lvalue, rvalue);
1235 return 0;
1236 }
1237
ba04f957
YW
1238 network->required_for_online = r;
1239 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1240 return 0;
4ac77d63
YW
1241 }
1242
ba04f957 1243 network->required_for_online = true;
4ac77d63
YW
1244 return 0;
1245}
7da377ef 1246
f0c09831
YW
1247int config_parse_link_group(
1248 const char *unit,
1249 const char *filename,
1250 unsigned line,
1251 const char *section,
1252 unsigned section_line,
1253 const char *lvalue,
1254 int ltype,
1255 const char *rvalue,
1256 void *data,
1257 void *userdata) {
1258
99534007 1259 Network *network = ASSERT_PTR(userdata);
f0c09831 1260 int r;
10af8bb2 1261 int32_t group;
f0c09831
YW
1262
1263 assert(filename);
1264 assert(lvalue);
1265 assert(rvalue);
f0c09831
YW
1266
1267 if (isempty(rvalue)) {
10af8bb2 1268 network->group = -1;
f0c09831
YW
1269 return 0;
1270 }
1271
10af8bb2 1272 r = safe_atoi32(rvalue, &group);
f0c09831
YW
1273 if (r < 0) {
1274 log_syntax(unit, LOG_WARNING, filename, line, r,
1275 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1276 return 0;
1277 }
1278
10af8bb2
SB
1279 if (group < 0) {
1280 log_syntax(unit, LOG_WARNING, filename, line, r,
1281 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1282 return 0;
1283 }
1284
1285 network->group = group;
f0c09831
YW
1286 return 0;
1287}
1288
6706ce2f
YW
1289int config_parse_ignore_carrier_loss(
1290 const char *unit,
1291 const char *filename,
1292 unsigned line,
1293 const char *section,
1294 unsigned section_line,
1295 const char *lvalue,
1296 int ltype,
1297 const char *rvalue,
1298 void *data,
1299 void *userdata) {
1300
99534007 1301 Network *network = ASSERT_PTR(userdata);
6706ce2f
YW
1302 usec_t usec;
1303 int r;
1304
1305 assert(filename);
1306 assert(lvalue);
1307 assert(rvalue);
6706ce2f
YW
1308
1309 if (isempty(rvalue)) {
1310 network->ignore_carrier_loss_set = false;
1311 return 0;
1312 }
1313
1314 r = parse_boolean(rvalue);
1315 if (r >= 0) {
1316 network->ignore_carrier_loss_set = true;
1317 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1318 return 0;
1319 }
1320
1321 r = parse_sec(rvalue, &usec);
1322 if (r < 0) {
1323 log_syntax(unit, LOG_WARNING, filename, line, r,
1324 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1325 return 0;
1326 }
1327
1328 network->ignore_carrier_loss_set = true;
1329 network->ignore_carrier_loss_usec = usec;
1330 return 0;
1331}
1332
8430841b
L
1333DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1334 "Failed to parse RequiredFamilyForOnline= setting");
1335
7da377ef
SS
1336DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1337 "Failed to parse KeepConfiguration= setting");
1338
1339static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1340 [KEEP_CONFIGURATION_NO] = "no",
1341 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1342 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1343 [KEEP_CONFIGURATION_STATIC] = "static",
1344 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1345};
1346
1347DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9 1348
61135582
DS
1349static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1350 [ACTIVATION_POLICY_UP] = "up",
1351 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1352 [ACTIVATION_POLICY_MANUAL] = "manual",
1353 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1354 [ACTIVATION_POLICY_DOWN] = "down",
1355 [ACTIVATION_POLICY_BOUND] = "bound",
1356};
1357
1358DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1359DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");