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