]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: ndisc: do not read DNSSL option when UseDomains=no
[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"
7e19cc54 23#include "networkd-dhcp-server.h"
14d9ab9d 24#include "networkd-ipv6-proxy-ndp.h"
23f53b99 25#include "networkd-manager.h"
3773eb54 26#include "networkd-ndisc.h"
1939ebeb 27#include "networkd-neighbor.h"
3ffd4af2 28#include "networkd-network.h"
75156ccb 29#include "networkd-nexthop.h"
b5ce4047 30#include "networkd-radv.h"
3b6a3bde 31#include "networkd-route.h"
ca183bf8 32#include "networkd-routing-policy-rule.h"
518cd6b5 33#include "networkd-sriov.h"
6bedfcbb 34#include "parse-util.h"
b0c82192 35#include "path-lookup.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"
34658df2 43#include "tc.h"
07630cea 44#include "util.h"
f579559b 45
c448459d
ZJS
46/* Let's assume that anything above this number is a user misconfiguration. */
47#define MAX_NTP_SERVERS 128
48
8f9bdeab 49static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret) {
cebe1257
YW
50 const char *kind_string;
51 NetDev *netdev;
52 int r;
53
96db6412
YW
54 /* For test-networkd-conf, the check must be earlier than the assertions. */
55 if (!name)
56 return 0;
57
cebe1257
YW
58 assert(network);
59 assert(network->manager);
60 assert(network->filename);
8f9bdeab 61 assert(ret);
cebe1257 62
cebe1257
YW
63 if (kind == _NETDEV_KIND_TUNNEL)
64 kind_string = "tunnel";
65 else {
66 kind_string = netdev_kind_to_string(kind);
67 if (!kind_string)
8f9bdeab
YW
68 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
69 "%s: Invalid NetDev kind of %s, ignoring assignment.",
70 network->filename, name);
cebe1257
YW
71 }
72
73 r = netdev_get(network->manager, name, &netdev);
74 if (r < 0)
8f9bdeab
YW
75 return log_warning_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
76 network->filename, name);
cebe1257
YW
77
78 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
79 IN_SET(netdev->kind,
80 NETDEV_KIND_IPIP,
81 NETDEV_KIND_SIT,
82 NETDEV_KIND_GRE,
83 NETDEV_KIND_GRETAP,
84 NETDEV_KIND_IP6GRE,
85 NETDEV_KIND_IP6GRETAP,
86 NETDEV_KIND_VTI,
87 NETDEV_KIND_VTI6,
9282f75b
YW
88 NETDEV_KIND_IP6TNL,
89 NETDEV_KIND_ERSPAN)))
8f9bdeab
YW
90 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
91 "%s: NetDev %s is not a %s, ignoring assignment",
92 network->filename, name, kind_string);
cebe1257 93
8f9bdeab 94 *ret = netdev_ref(netdev);
cebe1257
YW
95 return 1;
96}
97
98static int network_resolve_stacked_netdevs(Network *network) {
99 void *name, *kind;
cebe1257
YW
100 int r;
101
102 assert(network);
103
90e74a66 104 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names) {
cebe1257
YW
105 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
106
8f9bdeab 107 if (network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev) <= 0)
cebe1257
YW
108 continue;
109
dcd46cc4
SS
110 r = hashmap_ensure_put(&network->stacked_netdevs, &string_hash_ops, netdev->ifname, netdev);
111 if (r == -ENOMEM)
cebe1257 112 return log_oom();
cebe1257 113 if (r < 0)
8f9bdeab
YW
114 log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
115 network->filename, (const char *) name);
cebe1257
YW
116
117 netdev = NULL;
118 }
119
120 return 0;
121}
122
96db6412 123int network_verify(Network *network) {
50783f91
YW
124 int r;
125
0321cea7
YW
126 assert(network);
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 }
0321cea7 183 if (network->dhcp_server) {
ab24039f
ZJS
184 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
185 network->filename);
0321cea7
YW
186 network->dhcp_server = false;
187 }
9cd9fc8f 188 if (!ordered_hashmap_isempty(network->addresses_by_section))
ab24039f
ZJS
189 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
190 network->filename);
2a54a044 191 if (!hashmap_isempty(network->routes_by_section))
ab24039f
ZJS
192 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
193 network->filename);
9cd9fc8f
YW
194
195 network->addresses_by_section = ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 196 network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
0321cea7
YW
197 }
198
c918b70a
TY
199 if (network->link_local < 0) {
200 network->link_local = ADDRESS_FAMILY_IPV6;
201
57aef9d7 202 if (network->keep_master || network->bridge)
c918b70a
TY
203 network->link_local = ADDRESS_FAMILY_NO;
204 else {
205 NetDev *netdev;
206
207 HASHMAP_FOREACH(netdev, network->stacked_netdevs) {
208 MacVlan *m;
209
210 if (netdev->kind == NETDEV_KIND_MACVLAN)
211 m = MACVLAN(netdev);
212 else if (netdev->kind == NETDEV_KIND_MACVTAP)
213 m = MACVTAP(netdev);
214 else
215 continue;
216
217 if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU)
218 network->link_local = ADDRESS_FAMILY_NO;
219
220 /* There won't be a passthru MACVLAN/MACVTAP if there's already one in another mode */
221 break;
222 }
223 }
224 }
225
75d5abd2
YW
226 if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE)
227 SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false);
8f191801 228
9e1432d5
YW
229 if (in6_addr_is_set(&network->ipv6ll_stable_secret) &&
230 network->ipv6ll_address_gen_mode < 0)
231 network->ipv6ll_address_gen_mode = IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
232
48ed2766
FW
233 /* IPMasquerade implies IPForward */
234 network->ip_forward |= network->ip_masquerade;
0321cea7 235
14d9ab9d 236 network_adjust_ipv6_proxy_ndp(network);
3773eb54 237 network_adjust_ipv6_accept_ra(network);
22d37e5d 238 network_adjust_dhcp(network);
69e0f833 239 network_adjust_radv(network);
5546870e 240 network_adjust_bridge_vlan(network);
3773eb54 241
933c70a0 242 if (network->mtu > 0 && network->dhcp_use_mtu) {
0321cea7
YW
243 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
244 "Disabling UseMTU=.", network->filename);
245 network->dhcp_use_mtu = false;
246 }
247
7da377ef
SS
248 if (network->dhcp_critical >= 0) {
249 if (network->keep_configuration >= 0)
250 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
251 "Ignoring CriticalConnection=.", network->filename);
252 else if (network->dhcp_critical)
253 /* CriticalConnection=yes also preserve foreign static configurations. */
254 network->keep_configuration = KEEP_CONFIGURATION_YES;
255 else
80060352 256 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef
SS
257 }
258
61135582
DS
259 if (!strv_isempty(network->bind_carrier)) {
260 if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND))
261 log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. "
262 "Setting ActivationPolicy=bound.", network->filename);
263 network->activation_policy = ACTIVATION_POLICY_BOUND;
264 } else if (network->activation_policy == ACTIVATION_POLICY_BOUND) {
265 log_warning("%s: ActivationPolicy=bound requires BindCarrier=. "
266 "Ignoring ActivationPolicy=bound.", network->filename);
267 network->activation_policy = ACTIVATION_POLICY_UP;
268 }
269
270 if (network->activation_policy == _ACTIVATION_POLICY_INVALID)
271 network->activation_policy = ACTIVATION_POLICY_UP;
272
273 if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
274 if (network->ignore_carrier_loss == false)
275 log_warning("%s: IgnoreCarrierLoss=false conflicts with ActivationPolicy=always-up. "
276 "Setting IgnoreCarrierLoss=true.", network->filename);
277 network->ignore_carrier_loss = true;
278 }
279
280 if (network->ignore_carrier_loss < 0)
281 network->ignore_carrier_loss = network->configure_without_carrier;
282
7c644a69
DS
283 if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) {
284 if (network->required_for_online < 0 ||
285 (network->required_for_online == true && network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN)) {
286 log_debug("%s: Setting RequiredForOnline=no because ActivationPolicy=%s.", network->filename,
287 activation_policy_to_string(network->activation_policy));
288 network->required_for_online = false;
289 } else if (network->required_for_online == true)
290 log_warning("%s: RequiredForOnline=yes and ActivationPolicy=%s, "
291 "this may cause a delay at boot.", network->filename,
292 activation_policy_to_string(network->activation_policy));
293 }
294
295 if (network->required_for_online < 0)
296 network->required_for_online = true;
297
7da377ef 298 if (network->keep_configuration < 0)
80060352 299 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef 300
87851e0f
YW
301 if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
302 log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
303 network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
304 }
305
50783f91
YW
306 r = network_drop_invalid_addresses(network);
307 if (r < 0)
308 return r;
13ffa39f
YW
309 network_drop_invalid_routes(network);
310 network_drop_invalid_nexthops(network);
9671ae9d 311 network_drop_invalid_bridge_fdb_entries(network);
ff9e0783 312 network_drop_invalid_bridge_mdb_entries(network);
13ffa39f
YW
313 network_drop_invalid_neighbors(network);
314 network_drop_invalid_address_labels(network);
315 network_drop_invalid_prefixes(network);
316 network_drop_invalid_route_prefixes(network);
317 network_drop_invalid_routing_policy_rules(network);
318 network_drop_invalid_traffic_control(network);
319 network_drop_invalid_sr_iov(network);
c517a49b 320 network_drop_invalid_static_leases(network);
518cd6b5 321
0017ba31
YW
322 network_adjust_dhcp_server(network);
323
0321cea7
YW
324 return 0;
325}
326
7f06b3e1 327int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
838b2f7a 328 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 329 _cleanup_(network_unrefp) Network *network = NULL;
047a0dac 330 const char *dropin_dirname;
838b2f7a 331 char *d;
f579559b
TG
332 int r;
333
bf1bc670
TA
334 assert(manager);
335 assert(filename);
336
4e54a17d
YW
337 r = null_or_empty_path(filename);
338 if (r == -ENOENT)
339 return 0;
340 if (r < 0)
341 return r;
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)
357 return -EINVAL;
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,
db5756f3
YW
377 .arp = -1,
378 .multicast = -1,
379 .allmulticast = -1,
937e305e 380 .promiscuous = -1,
db5756f3 381
db5756f3
YW
382 .ignore_carrier_loss = -1,
383 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
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,
17f9c355 390 .dhcp_use_dns = true,
70570306 391 .dhcp_routes_to_dns = true,
17f9c355
YW
392 .dhcp_use_hostname = true,
393 .dhcp_use_routes = true,
589397a2 394 .dhcp_use_gateway = -1,
17f9c355 395 .dhcp_send_hostname = true,
5f3b5f19 396 .dhcp_send_release = true,
17f9c355 397 .dhcp_route_metric = DHCP_ROUTE_METRIC,
f90635f1 398 .dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
17f9c355 399 .dhcp_route_table = RT_TABLE_MAIN,
db5756f3 400 .dhcp_ip_service_type = -1,
e70eca9b 401 .dhcp_broadcast = -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,
4e26a5ba 408 .dhcp6_duid.type = _DUID_TYPE_INVALID,
0e45721e 409 .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
caa8ca42 410
e502f94d 411 .dhcp6_pd = -1,
4afd9867 412 .dhcp6_pd_announce = true,
99e015e2 413 .dhcp6_pd_assign = true,
fec1b650 414 .dhcp6_pd_manage_temporary_address = true,
197aec7e 415 .dhcp6_pd_subnet_id = -1,
d0619f2c 416 .dhcp6_pd_route_metric = DHCP6PD_ROUTE_METRIC,
9efa8a3c 417
21b6b87e 418 .dhcp_server_bind_to_interface = true,
2a71d57f
LP
419 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
420 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
421 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
17f9c355
YW
422 .dhcp_server_emit_router = true,
423 .dhcp_server_emit_timezone = true,
424
4f1ac4a3 425 .router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
c9e2c2da 426 .router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
17f9c355
YW
427 .router_emit_dns = true,
428 .router_emit_domains = true,
429
430 .use_bpdu = -1,
431 .hairpin = -1,
432 .fast_leave = -1,
433 .allow_port_to_be_root = -1,
434 .unicast_flood = -1,
7f15b714 435 .multicast_flood = -1,
d3aa8b49 436 .multicast_to_unicast = -1,
7f15b714
TJ
437 .neighbor_suppression = -1,
438 .learning = -1,
1087623b
SS
439 .bridge_proxy_arp = -1,
440 .bridge_proxy_arp_wifi = -1,
17f9c355 441 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 442 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
443
444 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
c01b9b87 445 .lldp_multicast_mode = _SD_LLDP_MULTICAST_MODE_INVALID,
17f9c355 446
7ece6f58 447 .dns_default_route = -1,
17f9c355
YW
448 .llmnr = RESOLVE_SUPPORT_YES,
449 .mdns = RESOLVE_SUPPORT_NO,
450 .dnssec_mode = _DNSSEC_MODE_INVALID,
451 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
452
0321cea7 453 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 454 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 455 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 456
94d76d07 457 .ipv4_accept_local = -1,
d75bf6cf 458 .ipv4_route_localnet = -1,
17f9c355 459 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
17f9c355
YW
460 .ipv6_dad_transmits = -1,
461 .ipv6_hop_limit = -1,
462 .ipv6_proxy_ndp = -1,
17f9c355 463 .proxy_arp = -1,
db5756f3 464
7d93b92f 465 .ipv6_accept_ra = -1,
17f9c355 466 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
467 .ipv6_accept_ra_use_autonomous_prefix = true,
468 .ipv6_accept_ra_use_onlink_prefix = true,
7d93b92f 469 .ipv6_accept_ra_use_mtu = true,
17f9c355 470 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
8ebafba9 471 .ipv6_accept_ra_route_metric = DHCP_ROUTE_METRIC,
cabe5711 472 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
c423be28 473
52aa38f1 474 .can_termination = -1,
17f9c355 475 };
f579559b 476
4f9ff96a 477 r = config_parse_many(
8b8024f1 478 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
4f9ff96a
LP
479 "Match\0"
480 "Link\0"
518cd6b5 481 "SR-IOV\0"
4f9ff96a
LP
482 "Network\0"
483 "Address\0"
484 "Neighbor\0"
485 "IPv6AddressLabel\0"
486 "RoutingPolicyRule\0"
487 "Route\0"
488 "NextHop\0"
489 "DHCP\0" /* compat */
490 "DHCPv4\0"
491 "DHCPv6\0"
b209cff2 492 "DHCPv6PrefixDelegation\0"
4f9ff96a 493 "DHCPServer\0"
c517a49b 494 "DHCPServerStaticLease\0"
4f9ff96a
LP
495 "IPv6AcceptRA\0"
496 "IPv6NDPProxyAddress\0"
497 "Bridge\0"
498 "BridgeFDB\0"
3db468ea 499 "BridgeMDB\0"
4f9ff96a 500 "BridgeVLAN\0"
27ff0490 501 "IPv6SendRA\0"
4f9ff96a
LP
502 "IPv6PrefixDelegation\0"
503 "IPv6Prefix\0"
504 "IPv6RoutePrefix\0"
505 "LLDP\0"
506 "TrafficControlQueueingDiscipline\0"
507 "CAN\0"
508 "QDisc\0"
509 "BFIFO\0"
510 "CAKE\0"
511 "ControlledDelay\0"
512 "DeficitRoundRobinScheduler\0"
513 "DeficitRoundRobinSchedulerClass\0"
d474aa51 514 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
515 "FairQueueing\0"
516 "FairQueueingControlledDelay\0"
8f6b6d70 517 "FlowQueuePIE\0"
4f9ff96a
LP
518 "GenericRandomEarlyDetection\0"
519 "HeavyHitterFilter\0"
520 "HierarchyTokenBucket\0"
521 "HierarchyTokenBucketClass\0"
522 "NetworkEmulator\0"
b12aaee5
SS
523 "PFIFO\0"
524 "PFIFOFast\0"
525 "PFIFOHeadDrop\0"
4f9ff96a 526 "PIE\0"
b12aaee5 527 "QuickFairQueueing\0"
4d7ddaf9 528 "QuickFairQueueingClass\0"
4f9ff96a
LP
529 "StochasticFairBlue\0"
530 "StochasticFairnessQueueing\0"
531 "TokenBucketFilter\0"
532 "TrivialLinkEqualizer\0",
533 config_item_perf_lookup, network_network_gperf_lookup,
534 CONFIG_PARSE_WARN,
535 network,
8524db50 536 &network->stats_by_path);
102bc043 537 if (r < 0)
f579559b 538 return r;
f579559b 539
fa7cd711
YW
540 r = network_add_ipv4ll_route(network);
541 if (r < 0)
9202b567 542 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
fa7cd711 543
5d5003ab
YW
544 r = network_add_default_route_on_device(network);
545 if (r < 0)
9202b567
YW
546 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
547 network->filename);
5d5003ab 548
9202b567
YW
549 r = network_verify(network);
550 if (r == -ENOMEM)
551 return r;
552 if (r < 0)
7f06b3e1
YW
553 /* Ignore .network files that do not match the conditions. */
554 return 0;
555
9fa3e794 556 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
dbffab87
TG
557 if (r < 0)
558 return r;
559
b5b9b0e7 560 TAKE_PTR(network);
f579559b
TG
561 return 0;
562}
563
7f06b3e1 564int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
565 _cleanup_strv_free_ char **files = NULL;
566 char **f;
f579559b
TG
567 int r;
568
569 assert(manager);
570
7f06b3e1 571 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 572
dc0d4078 573 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
574 if (r < 0)
575 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 576
715d398e 577 STRV_FOREACH(f, files) {
7f06b3e1 578 r = network_load_one(manager, networks, *f);
f579559b 579 if (r < 0)
9202b567 580 return log_error_errno(r, "Failed to load %s: %m", *f);
f579559b
TG
581 }
582
f579559b
TG
583 return 0;
584}
585
8524db50
YW
586static bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
587 struct stat *st_a, *st_b;
588 const char *path;
589
590 assert(a);
591 assert(b);
592
593 if (hashmap_size(a) != hashmap_size(b))
594 return false;
595
596 HASHMAP_FOREACH_KEY(st_a, path, a) {
597 st_b = hashmap_get(b, path);
598 if (!st_b)
599 return false;
600
601 if (!stat_inode_unmodified(st_a, st_b))
602 return false;
603 }
604
605 return true;
606}
607
7f06b3e1
YW
608int network_reload(Manager *manager) {
609 OrderedHashmap *new_networks = NULL;
610 Network *n, *old;
7f06b3e1
YW
611 int r;
612
613 assert(manager);
614
615 r = network_load(manager, &new_networks);
616 if (r < 0)
617 goto failure;
618
90e74a66 619 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1 620 r = network_get_by_name(manager, n->name, &old);
8524db50
YW
621 if (r < 0) {
622 log_debug("Found new .network file: %s", n->filename);
623 continue;
624 }
7f06b3e1 625
8524db50
YW
626 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
627 log_debug("Found updated .network file: %s", n->filename);
7f06b3e1 628 continue;
8524db50 629 }
7f06b3e1
YW
630
631 r = ordered_hashmap_replace(new_networks, old->name, old);
632 if (r < 0)
633 goto failure;
634
635 network_ref(old);
636 network_unref(n);
637 }
638
639 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
640 manager->networks = new_networks;
641
642 return 0;
643
644failure:
645 ordered_hashmap_free_with_destructor(new_networks, network_unref);
646
647 return r;
648}
649
35ac3b76 650static Network *network_free(Network *network) {
f579559b 651 if (!network)
35ac3b76 652 return NULL;
f579559b
TG
653
654 free(network->filename);
8524db50 655 hashmap_free(network->stats_by_path);
f579559b 656
5722fb89 657 net_match_clear(&network->match);
c4f58dea 658 condition_free_list(network->conditions);
f579559b 659
11c38d3e
YA
660 free(network->dhcp_server_relay_agent_circuit_id);
661 free(network->dhcp_server_relay_agent_remote_id);
662
f579559b 663 free(network->description);
edb85f0d 664 free(network->dhcp_vendor_class_identifier);
7b8d23a9 665 free(network->dhcp_mudurl);
af1c0de0 666 strv_free(network->dhcp_user_class);
27cb34f5 667 free(network->dhcp_hostname);
d419ef02 668 free(network->dhcp_label);
6b000af4 669 set_free(network->dhcp_deny_listed_ip);
98ebef62 670 set_free(network->dhcp_allow_listed_ip);
5bc945be 671 set_free(network->dhcp_request_options);
35f6a5cb 672 set_free(network->dhcp6_request_options);
c106cc36 673 free(network->mac);
3175a8c2 674 free(network->dhcp6_mudurl);
f37f2a6b 675 strv_free(network->dhcp6_user_class);
ed0d1b2e 676 strv_free(network->dhcp6_vendor_class);
c106cc36 677
b0e39c82 678 strv_free(network->ntp);
e77bd3fd
YW
679 for (unsigned i = 0; i < network->n_dns; i++)
680 in_addr_full_free(network->dns[i]);
5512a963 681 free(network->dns);
5e276772
YW
682 ordered_set_free(network->search_domains);
683 ordered_set_free(network->route_domains);
0d4ad91d 684 strv_free(network->bind_carrier);
cdd7812b 685
5e276772 686 ordered_set_free(network->router_search_domains);
cdd7812b 687 free(network->router_dns);
c995fa02
YW
688 set_free(network->ndisc_deny_listed_router);
689 set_free(network->ndisc_allow_listed_router);
690 set_free(network->ndisc_deny_listed_prefix);
691 set_free(network->ndisc_allow_listed_prefix);
692 set_free(network->ndisc_deny_listed_route_prefix);
693 set_free(network->ndisc_allow_listed_route_prefix);
3bef724f 694
c0267a59 695 free(network->batadv_name);
cebe1257
YW
696 free(network->bridge_name);
697 free(network->bond_name);
698 free(network->vrf_name);
699 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 700 netdev_unref(network->bridge);
47e2dc31 701 netdev_unref(network->bond);
6cb955c6 702 netdev_unref(network->vrf);
fa6f1e54 703 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 704
d349f502 705 set_free_free(network->ipv6_proxy_ndp_addresses);
9cd9fc8f 706 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 707 hashmap_free_with_destructor(network->routes_by_section, route_free);
b82663dd 708 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
9671ae9d 709 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
ff9e0783 710 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
b0ba6938 711 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
d6a2a0f9 712 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
ecb0e85e
YW
713 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
714 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
ca183bf8 715 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
c517a49b 716 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
518cd6b5 717 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
34658df2 718 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 719
dbffab87 720 free(network->name);
f579559b 721
8eb9058d 722 free(network->dhcp_server_timezone);
165d7c5c 723 free(network->dhcp_server_uplink_name);
63295b42 724 free(network->router_uplink_name);
2a71d57f 725
2324fd3a 726 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
2a71d57f 727 free(network->dhcp_server_emit[t].addresses);
8eb9058d 728
8a516214
LP
729 set_free_free(network->dnssec_negative_trust_anchors);
730
c01b9b87 731 free(network->lldp_mudurl);
e9a8c550 732
0e96961d 733 ordered_hashmap_free(network->dhcp_client_send_options);
7354900d 734 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
0e96961d 735 ordered_hashmap_free(network->dhcp_server_send_options);
7354900d 736 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
1c3ec1cd 737 ordered_hashmap_free(network->dhcp6_client_send_options);
b4ccc5de 738 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
f5960e0a 739 set_free(network->dhcp6_pd_tokens);
3bac5fe6 740 set_free(network->ndisc_tokens);
cb29c156 741
35ac3b76 742 return mfree(network);
f579559b
TG
743}
744
35ac3b76
YW
745DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
746
dbffab87
TG
747int network_get_by_name(Manager *manager, const char *name, Network **ret) {
748 Network *network;
749
750 assert(manager);
751 assert(name);
752 assert(ret);
753
715d398e 754 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
755 if (!network)
756 return -ENOENT;
757
758 *ret = network;
759
760 return 0;
761}
762
adfeee49 763bool network_has_static_ipv6_configurations(Network *network) {
439689c6 764 Address *address;
adfeee49 765 Route *route;
9671ae9d 766 BridgeFDB *fdb;
ff9e0783 767 BridgeMDB *mdb;
adfeee49 768 Neighbor *neighbor;
439689c6
SS
769
770 assert(network);
771
9cd9fc8f 772 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
773 if (address->family == AF_INET6)
774 return true;
adfeee49 775
2a54a044 776 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
777 if (route->family == AF_INET6)
778 return true;
779
9671ae9d 780 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
adfeee49
YW
781 if (fdb->family == AF_INET6)
782 return true;
783
ff9e0783 784 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
3db468ea
DM
785 if (mdb->family == AF_INET6)
786 return true;
787
b0ba6938 788 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
adfeee49
YW
789 if (neighbor->family == AF_INET6)
790 return true;
791
d6a2a0f9 792 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
793 return true;
794
ecb0e85e 795 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 796 return true;
d30081c2
YW
797
798 if (!hashmap_isempty(network->route_prefixes_by_section))
799 return true;
439689c6
SS
800
801 return false;
802}
803
63481576
YW
804int config_parse_stacked_netdev(
805 const char *unit,
02b59d57
TG
806 const char *filename,
807 unsigned line,
808 const char *section,
809 unsigned section_line,
810 const char *lvalue,
811 int ltype,
812 const char *rvalue,
813 void *data,
814 void *userdata) {
63481576 815
95dba435
YW
816 _cleanup_free_ char *name = NULL;
817 NetDevKind kind = ltype;
cebe1257 818 Hashmap **h = data;
02b59d57
TG
819 int r;
820
821 assert(filename);
822 assert(lvalue);
823 assert(rvalue);
824 assert(data);
95dba435
YW
825 assert(IN_SET(kind,
826 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 827 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 828 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
829 NETDEV_KIND_XFRM));
54abf461 830
cebe1257 831 if (!ifname_valid(rvalue)) {
d96edb2c 832 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 833 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
834 return 0;
835 }
836
cebe1257
YW
837 name = strdup(rvalue);
838 if (!name)
839 return log_oom();
3e570042 840
6de530f2
SS
841 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
842 if (r == -ENOMEM)
cebe1257 843 return log_oom();
83ec4592 844 if (r < 0)
d96edb2c 845 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
846 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
847 else if (r == 0)
848 log_syntax(unit, LOG_DEBUG, filename, line, r,
849 "NetDev '%s' specified twice, ignoring.", name);
850 else
0c7bd7ec 851 TAKE_PTR(name);
47e2dc31 852
fe6b2d55
TG
853 return 0;
854}
7951dea2 855
3df9bec5
LP
856int config_parse_domains(
857 const char *unit,
858 const char *filename,
859 unsigned line,
860 const char *section,
861 unsigned section_line,
862 const char *lvalue,
863 int ltype,
864 const char *rvalue,
865 void *data,
866 void *userdata) {
867
5aafd5b1 868 Network *n = userdata;
6192b846
TG
869 int r;
870
5aafd5b1 871 assert(filename);
3df9bec5
LP
872 assert(lvalue);
873 assert(rvalue);
5aafd5b1 874 assert(n);
6192b846 875
3df9bec5 876 if (isempty(rvalue)) {
5e276772
YW
877 n->search_domains = ordered_set_free(n->search_domains);
878 n->route_domains = ordered_set_free(n->route_domains);
3df9bec5
LP
879 return 0;
880 }
67272d15 881
d96edb2c 882 for (const char *p = rvalue;;) {
3df9bec5
LP
883 _cleanup_free_ char *w = NULL, *normalized = NULL;
884 const char *domain;
885 bool is_route;
886
887 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
888 if (r == -ENOMEM)
889 return log_oom();
3df9bec5 890 if (r < 0) {
d96edb2c 891 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 892 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 893 return 0;
3df9bec5
LP
894 }
895 if (r == 0)
d96edb2c 896 return 0;
3df9bec5
LP
897
898 is_route = w[0] == '~';
899 domain = is_route ? w + 1 : w;
900
901 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
902 /* If the root domain appears as is, or the special token "*" is found, we'll
903 * consider this as routing domain, unconditionally. */
3df9bec5 904 is_route = true;
ab24039f
ZJS
905 domain = "."; /* make sure we don't allow empty strings, thus write the root
906 * domain as "." */
3df9bec5 907 } else {
7470cc4c 908 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 909 if (r < 0) {
d96edb2c 910 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 911 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
912 continue;
913 }
914
915 domain = normalized;
916
917 if (is_localhost(domain)) {
d96edb2c 918 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
919 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
920 domain);
37de2509 921 continue;
3df9bec5 922 }
37de2509 923 }
40274ed6 924
5e2a51d5 925 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
cf453507
YW
926 r = ordered_set_put_strdup(set, domain);
927 if (r == -EEXIST)
928 continue;
09451975
LP
929 if (r < 0)
930 return log_oom();
40274ed6 931 }
6192b846
TG
932}
933
1ac608c9
LP
934int config_parse_hostname(
935 const char *unit,
936 const char *filename,
937 unsigned line,
938 const char *section,
939 unsigned section_line,
940 const char *lvalue,
941 int ltype,
942 const char *rvalue,
943 void *data,
944 void *userdata) {
945
6528693a 946 char **hostname = data;
a7d0ef44
SS
947 int r;
948
949 assert(filename);
950 assert(lvalue);
951 assert(rvalue);
b40b8b06 952 assert(data);
a7d0ef44 953
b40b8b06
YW
954 if (isempty(rvalue)) {
955 *hostname = mfree(*hostname);
956 return 0;
957 }
a7d0ef44 958
b40b8b06 959 if (!hostname_is_valid(rvalue, 0)) {
d96edb2c 960 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 961 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
962 return 0;
963 }
964
b40b8b06 965 r = dns_name_is_valid(rvalue);
6528693a 966 if (r < 0) {
d96edb2c 967 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 968 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
969 return 0;
970 }
971 if (r == 0) {
d96edb2c 972 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 973 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
974 return 0;
975 }
976
b40b8b06 977 return free_and_strdup_warn(hostname, rvalue);
a7d0ef44 978}
8eb9058d
LP
979
980int config_parse_timezone(
981 const char *unit,
982 const char *filename,
983 unsigned line,
984 const char *section,
985 unsigned section_line,
986 const char *lvalue,
987 int ltype,
988 const char *rvalue,
989 void *data,
990 void *userdata) {
991
b40b8b06 992 char **tz = data;
8eb9058d
LP
993 int r;
994
995 assert(filename);
996 assert(lvalue);
997 assert(rvalue);
b40b8b06 998 assert(data);
8eb9058d 999
b40b8b06
YW
1000 if (isempty(rvalue)) {
1001 *tz = mfree(*tz);
1002 return 0;
1003 }
8eb9058d 1004
b40b8b06
YW
1005 r = verify_timezone(rvalue, LOG_WARNING);
1006 if (r < 0) {
1007 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1008 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1009 return 0;
1010 }
1011
b40b8b06 1012 return free_and_strdup_warn(tz, rvalue);
8eb9058d 1013}
1a04db0f 1014
53253824
SS
1015int config_parse_dns(
1016 const char *unit,
1017 const char *filename,
1018 unsigned line,
1019 const char *section,
1020 unsigned section_line,
1021 const char *lvalue,
1022 int ltype,
1023 const char *rvalue,
1024 void *data,
1025 void *userdata) {
1026
1027 Network *n = userdata;
1028 int r;
1029
1030 assert(filename);
1031 assert(lvalue);
1032 assert(rvalue);
5aafd5b1 1033 assert(n);
53253824 1034
d96edb2c 1035 if (isempty(rvalue)) {
e77bd3fd
YW
1036 for (unsigned i = 0; i < n->n_dns; i++)
1037 in_addr_full_free(n->dns[i]);
d96edb2c
YW
1038 n->dns = mfree(n->dns);
1039 n->n_dns = 0;
1040 return 0;
1041 }
1042
1043 for (const char *p = rvalue;;) {
e77bd3fd 1044 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 1045 _cleanup_free_ char *w = NULL;
e77bd3fd 1046 struct in_addr_full **m;
53253824 1047
d96edb2c 1048 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
1049 if (r == -ENOMEM)
1050 return log_oom();
1051 if (r < 0) {
d96edb2c 1052 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1053 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 1054 return 0;
53253824 1055 }
5512a963 1056 if (r == 0)
d96edb2c 1057 return 0;
53253824 1058
e77bd3fd 1059 r = in_addr_full_new_from_string(w, &dns);
53253824 1060 if (r < 0) {
d96edb2c 1061 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1062 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1063 continue;
1064 }
1065
e77bd3fd
YW
1066 if (IN_SET(dns->port, 53, 853))
1067 dns->port = 0;
1068
1069 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 1070 if (!m)
53253824
SS
1071 return log_oom();
1072
e77bd3fd 1073 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 1074 n->dns = m;
53253824 1075 }
53253824
SS
1076}
1077
8a516214
LP
1078int config_parse_dnssec_negative_trust_anchors(
1079 const char *unit,
1080 const char *filename,
1081 unsigned line,
1082 const char *section,
1083 unsigned section_line,
1084 const char *lvalue,
1085 int ltype,
1086 const char *rvalue,
1087 void *data,
1088 void *userdata) {
1089
5aafd5b1 1090 Set **nta = data;
8a516214
LP
1091 int r;
1092
5aafd5b1 1093 assert(filename);
8a516214
LP
1094 assert(lvalue);
1095 assert(rvalue);
5aafd5b1 1096 assert(nta);
8a516214
LP
1097
1098 if (isempty(rvalue)) {
5aafd5b1 1099 *nta = set_free_free(*nta);
8a516214
LP
1100 return 0;
1101 }
1102
d96edb2c 1103 for (const char *p = rvalue;;) {
8a516214
LP
1104 _cleanup_free_ char *w = NULL;
1105
1106 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1107 if (r == -ENOMEM)
1108 return log_oom();
8a516214 1109 if (r < 0) {
d96edb2c 1110 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1111 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1112 return 0;
8a516214
LP
1113 }
1114 if (r == 0)
d96edb2c 1115 return 0;
8a516214
LP
1116
1117 r = dns_name_is_valid(w);
1118 if (r <= 0) {
d96edb2c 1119 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1120 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1121 continue;
1122 }
1123
5aafd5b1 1124 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1125 if (r < 0)
1126 return log_oom();
8a516214 1127 }
8a516214 1128}
b2a81c0b 1129
26575990
LP
1130int config_parse_ntp(
1131 const char *unit,
1132 const char *filename,
1133 unsigned line,
1134 const char *section,
1135 unsigned section_line,
1136 const char *lvalue,
1137 int ltype,
1138 const char *rvalue,
1139 void *data,
1140 void *userdata) {
1141
1142 char ***l = data;
1143 int r;
1144
5aafd5b1 1145 assert(filename);
26575990
LP
1146 assert(lvalue);
1147 assert(rvalue);
5aafd5b1 1148 assert(l);
26575990
LP
1149
1150 if (isempty(rvalue)) {
1151 *l = strv_free(*l);
1152 return 0;
1153 }
1154
d96edb2c 1155 for (const char *p = rvalue;;) {
26575990
LP
1156 _cleanup_free_ char *w = NULL;
1157
d96edb2c 1158 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1159 if (r == -ENOMEM)
1160 return log_oom();
1161 if (r < 0) {
d96edb2c 1162 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1163 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1164 return 0;
26575990
LP
1165 }
1166 if (r == 0)
d96edb2c 1167 return 0;
26575990
LP
1168
1169 r = dns_name_is_valid_or_address(w);
1170 if (r <= 0) {
d96edb2c 1171 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1172 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1173 continue;
af1c0de0
SS
1174 }
1175
c448459d
ZJS
1176 if (strv_length(*l) > MAX_NTP_SERVERS) {
1177 log_syntax(unit, LOG_WARNING, filename, line, 0,
1178 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1179 MAX_NTP_SERVERS, w);
d96edb2c 1180 return 0;
c448459d
ZJS
1181 }
1182
1183 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1184 if (r < 0)
1185 return log_oom();
af1c0de0 1186 }
af1c0de0
SS
1187}
1188
4ac77d63
YW
1189int config_parse_required_for_online(
1190 const char *unit,
1191 const char *filename,
1192 unsigned line,
1193 const char *section,
1194 unsigned section_line,
1195 const char *lvalue,
1196 int ltype,
1197 const char *rvalue,
1198 void *data,
1199 void *userdata) {
1200
5aafd5b1 1201 Network *network = userdata;
75cd4a5d 1202 LinkOperationalStateRange range;
4ac77d63
YW
1203 bool required = true;
1204 int r;
1205
5aafd5b1
YW
1206 assert(filename);
1207 assert(lvalue);
1208 assert(rvalue);
1209 assert(network);
1210
4ac77d63 1211 if (isempty(rvalue)) {
7c644a69 1212 network->required_for_online = -1;
75cd4a5d 1213 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1214 return 0;
1215 }
1216
75cd4a5d
DDM
1217 r = parse_operational_state_range(rvalue, &range);
1218 if (r < 0) {
4ac77d63
YW
1219 r = parse_boolean(rvalue);
1220 if (r < 0) {
d96edb2c 1221 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1222 "Failed to parse %s= setting, ignoring assignment: %s",
1223 lvalue, rvalue);
1224 return 0;
1225 }
1226
1227 required = r;
75cd4a5d 1228 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1229 }
1230
1231 network->required_for_online = required;
75cd4a5d 1232 network->required_operstate_for_online = range;
4ac77d63
YW
1233
1234 return 0;
1235}
7da377ef 1236
f0c09831
YW
1237int config_parse_link_group(
1238 const char *unit,
1239 const char *filename,
1240 unsigned line,
1241 const char *section,
1242 unsigned section_line,
1243 const char *lvalue,
1244 int ltype,
1245 const char *rvalue,
1246 void *data,
1247 void *userdata) {
1248
1249 Network *network = userdata;
1250 int r;
1251
1252 assert(filename);
1253 assert(lvalue);
1254 assert(rvalue);
1255 assert(network);
1256
1257 if (isempty(rvalue)) {
1258 network->group = 0;
1259 network->group_set = false;
1260 return 0;
1261 }
1262
1263 r = safe_atou32(rvalue, &network->group);
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
1270 network->group_set = true;
1271 return 0;
1272}
1273
8430841b
L
1274DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1275 "Failed to parse RequiredFamilyForOnline= setting");
1276
7da377ef
SS
1277DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1278 "Failed to parse KeepConfiguration= setting");
1279
1280static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1281 [KEEP_CONFIGURATION_NO] = "no",
1282 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1283 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1284 [KEEP_CONFIGURATION_STATIC] = "static",
1285 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1286};
1287
1288DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9
YW
1289
1290static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1291 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1292 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1293 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1294 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1295};
1296
1297DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1298DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_link_local_address_gen_mode, ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode, "Failed to parse IPv6 link local address generation mode");
61135582
DS
1299
1300static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1301 [ACTIVATION_POLICY_UP] = "up",
1302 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1303 [ACTIVATION_POLICY_MANUAL] = "manual",
1304 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1305 [ACTIVATION_POLICY_DOWN] = "down",
1306 [ACTIVATION_POLICY_BOUND] = "bound",
1307};
1308
1309DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1310DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");