]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
Merge pull request #18886 from anitazha/shutdownconsole
[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"
fb486c90 16#include "networkd-address-label.h"
093e3533 17#include "networkd-address.h"
22d37e5d 18#include "networkd-dhcp-common.h"
7e19cc54 19#include "networkd-dhcp-server.h"
ee446d57 20#include "networkd-fdb.h"
23f53b99 21#include "networkd-manager.h"
dbf63196 22#include "networkd-mdb.h"
3773eb54 23#include "networkd-ndisc.h"
1939ebeb 24#include "networkd-neighbor.h"
3ffd4af2 25#include "networkd-network.h"
75156ccb 26#include "networkd-nexthop.h"
b5ce4047 27#include "networkd-radv.h"
ca183bf8 28#include "networkd-routing-policy-rule.h"
518cd6b5 29#include "networkd-sriov.h"
6bedfcbb 30#include "parse-util.h"
b0c82192 31#include "path-lookup.h"
8a516214 32#include "set.h"
cebe1257 33#include "socket-util.h"
8fcde012 34#include "stat-util.h"
8b43440b 35#include "string-table.h"
07630cea 36#include "string-util.h"
700f1186 37#include "strv.h"
34658df2 38#include "tc.h"
07630cea 39#include "util.h"
f579559b 40
c448459d
ZJS
41/* Let's assume that anything above this number is a user misconfiguration. */
42#define MAX_NTP_SERVERS 128
43
add8d07d 44/* Set defaults following RFC7844 */
45void network_apply_anonymize_if_set(Network *network) {
46 if (!network->dhcp_anonymize)
47 return;
48 /* RFC7844 3.7
49 SHOULD NOT send the Host Name option */
50 network->dhcp_send_hostname = false;
51 /* RFC7844 section 3.:
52 MAY contain the Client Identifier option
53 Section 3.5:
54 clients MUST use client identifiers based solely
55 on the link-layer address */
56 /* NOTE: Using MAC, as it does not reveal extra information,
57 * and some servers might not answer if this option is not sent */
58 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
59 /* RFC 7844 3.10:
60 SHOULD NOT use the Vendor Class Identifier option */
727ba17f 61 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
add8d07d 62 /* RFC7844 section 3.6.:
63 The client intending to protect its privacy SHOULD only request a
64 minimal number of options in the PRL and SHOULD also randomly shuffle
43bf2874 65 the ordering of option codes in the PRL. If this random ordering
add8d07d 66 cannot be implemented, the client MAY order the option codes in the
67 PRL by option code number (lowest to highest).
68 */
69 /* NOTE: dhcp_use_mtu is false by default,
70 * though it was not initiallized to any value in network_load_one.
71 * Maybe there should be another var called *send*?
72 * (to use the MTU sent by the server but to do not send
73 * the option in the PRL). */
74 network->dhcp_use_mtu = false;
28522b0d 75 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
76 * but this is needed to use them. */
77 network->dhcp_use_routes = true;
add8d07d 78 /* RFC7844 section 3.6.
79 * same comments as previous option */
80 network->dhcp_use_timezone = false;
81}
82
cebe1257
YW
83static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
84 const char *kind_string;
85 NetDev *netdev;
86 int r;
87
96db6412
YW
88 /* For test-networkd-conf, the check must be earlier than the assertions. */
89 if (!name)
90 return 0;
91
cebe1257
YW
92 assert(network);
93 assert(network->manager);
94 assert(network->filename);
95 assert(ret_netdev);
96
cebe1257
YW
97 if (kind == _NETDEV_KIND_TUNNEL)
98 kind_string = "tunnel";
99 else {
100 kind_string = netdev_kind_to_string(kind);
101 if (!kind_string)
102 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
103 "%s: Invalid NetDev kind of %s, ignoring assignment.",
104 network->filename, name);
105 }
106
107 r = netdev_get(network->manager, name, &netdev);
108 if (r < 0)
109 return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
110 network->filename, name);
111
112 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
113 IN_SET(netdev->kind,
114 NETDEV_KIND_IPIP,
115 NETDEV_KIND_SIT,
116 NETDEV_KIND_GRE,
117 NETDEV_KIND_GRETAP,
118 NETDEV_KIND_IP6GRE,
119 NETDEV_KIND_IP6GRETAP,
120 NETDEV_KIND_VTI,
121 NETDEV_KIND_VTI6,
9282f75b
YW
122 NETDEV_KIND_IP6TNL,
123 NETDEV_KIND_ERSPAN)))
cebe1257
YW
124 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
125 "%s: NetDev %s is not a %s, ignoring assignment",
126 network->filename, name, kind_string);
127
128 *ret_netdev = netdev_ref(netdev);
129 return 1;
130}
131
132static int network_resolve_stacked_netdevs(Network *network) {
133 void *name, *kind;
cebe1257
YW
134 int r;
135
136 assert(network);
137
90e74a66 138 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names) {
cebe1257
YW
139 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
140
141 r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
142 if (r <= 0)
143 continue;
144
dcd46cc4
SS
145 r = hashmap_ensure_put(&network->stacked_netdevs, &string_hash_ops, netdev->ifname, netdev);
146 if (r == -ENOMEM)
cebe1257 147 return log_oom();
cebe1257
YW
148 if (r < 0)
149 return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
150 network->filename, (const char *) name);
151
152 netdev = NULL;
153 }
154
155 return 0;
156}
157
96db6412 158int network_verify(Network *network) {
0321cea7
YW
159 assert(network);
160 assert(network->filename);
161
5722fb89 162 if (net_match_is_empty(&network->match) && !network->conditions)
dade7349
ZJS
163 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
164 "%s: No valid settings found in the [Match] section, ignoring file. "
165 "To match all interfaces, add Name=* in the [Match] section.",
166 network->filename);
84ea567e 167
cebe1257 168 /* skip out early if configuration does not match the environment */
a0b191b7 169 if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
cebe1257 170 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
171 "%s: Conditions in the file do not match the system environment, skipping.",
172 network->filename);
cebe1257 173
c0267a59 174 (void) network_resolve_netdev_one(network, network->batadv_name, NETDEV_KIND_BATADV, &network->batadv);
cebe1257
YW
175 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
176 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
177 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
178 (void) network_resolve_stacked_netdevs(network);
179
180 /* Free unnecessary entries. */
c0267a59 181 network->batadv_name = mfree(network->batadv_name);
cebe1257
YW
182 network->bond_name = mfree(network->bond_name);
183 network->bridge_name = mfree(network->bridge_name);
184 network->vrf_name = mfree(network->vrf_name);
185 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
186
0321cea7
YW
187 if (network->bond) {
188 /* Bonding slave does not support addressing. */
0321cea7 189 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
190 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
191 network->filename);
0321cea7
YW
192 network->link_local = ADDRESS_FAMILY_NO;
193 }
0321cea7 194 if (network->dhcp_server) {
ab24039f
ZJS
195 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
196 network->filename);
0321cea7
YW
197 network->dhcp_server = false;
198 }
9cd9fc8f 199 if (!ordered_hashmap_isempty(network->addresses_by_section))
ab24039f
ZJS
200 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
201 network->filename);
2a54a044 202 if (!hashmap_isempty(network->routes_by_section))
ab24039f
ZJS
203 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
204 network->filename);
9cd9fc8f
YW
205
206 network->addresses_by_section = ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 207 network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
0321cea7
YW
208 }
209
210 if (network->link_local < 0)
8f191801
YW
211 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
212
48ed2766
FW
213 /* IPMasquerade implies IPForward */
214 network->ip_forward |= network->ip_masquerade;
0321cea7 215
3773eb54 216 network_adjust_ipv6_accept_ra(network);
22d37e5d 217 network_adjust_dhcp(network);
69e0f833 218 network_adjust_radv(network);
3773eb54 219
933c70a0 220 if (network->mtu > 0 && network->dhcp_use_mtu) {
0321cea7
YW
221 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
222 "Disabling UseMTU=.", network->filename);
223 network->dhcp_use_mtu = false;
224 }
225
589397a2
DS
226 if (network->dhcp_use_gateway < 0)
227 network->dhcp_use_gateway = network->dhcp_use_routes;
228
7da377ef
SS
229 if (network->dhcp_critical >= 0) {
230 if (network->keep_configuration >= 0)
231 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
232 "Ignoring CriticalConnection=.", network->filename);
233 else if (network->dhcp_critical)
234 /* CriticalConnection=yes also preserve foreign static configurations. */
235 network->keep_configuration = KEEP_CONFIGURATION_YES;
236 else
80060352 237 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef
SS
238 }
239
61135582
DS
240 if (!strv_isempty(network->bind_carrier)) {
241 if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND))
242 log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. "
243 "Setting ActivationPolicy=bound.", network->filename);
244 network->activation_policy = ACTIVATION_POLICY_BOUND;
245 } else if (network->activation_policy == ACTIVATION_POLICY_BOUND) {
246 log_warning("%s: ActivationPolicy=bound requires BindCarrier=. "
247 "Ignoring ActivationPolicy=bound.", network->filename);
248 network->activation_policy = ACTIVATION_POLICY_UP;
249 }
250
251 if (network->activation_policy == _ACTIVATION_POLICY_INVALID)
252 network->activation_policy = ACTIVATION_POLICY_UP;
253
254 if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
255 if (network->ignore_carrier_loss == false)
256 log_warning("%s: IgnoreCarrierLoss=false conflicts with ActivationPolicy=always-up. "
257 "Setting IgnoreCarrierLoss=true.", network->filename);
258 network->ignore_carrier_loss = true;
259 }
260
261 if (network->ignore_carrier_loss < 0)
262 network->ignore_carrier_loss = network->configure_without_carrier;
263
7da377ef 264 if (network->keep_configuration < 0)
80060352 265 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef 266
87851e0f
YW
267 if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
268 log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
269 network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
270 }
271
13ffa39f
YW
272 network_drop_invalid_addresses(network);
273 network_drop_invalid_routes(network);
274 network_drop_invalid_nexthops(network);
275 network_drop_invalid_fdb_entries(network);
276 network_drop_invalid_mdb_entries(network);
277 network_drop_invalid_neighbors(network);
278 network_drop_invalid_address_labels(network);
279 network_drop_invalid_prefixes(network);
280 network_drop_invalid_route_prefixes(network);
281 network_drop_invalid_routing_policy_rules(network);
282 network_drop_invalid_traffic_control(network);
283 network_drop_invalid_sr_iov(network);
518cd6b5 284
0321cea7
YW
285 return 0;
286}
287
7f06b3e1 288int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
838b2f7a 289 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 290 _cleanup_(network_unrefp) Network *network = NULL;
047a0dac 291 const char *dropin_dirname;
838b2f7a 292 char *d;
f579559b
TG
293 int r;
294
bf1bc670
TA
295 assert(manager);
296 assert(filename);
297
4e54a17d
YW
298 r = null_or_empty_path(filename);
299 if (r == -ENOENT)
300 return 0;
301 if (r < 0)
302 return r;
303 if (r > 0) {
ed88bcfb 304 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
305 return 0;
306 }
307
838b2f7a
YW
308 fname = strdup(filename);
309 if (!fname)
310 return log_oom();
311
312 name = strdup(basename(filename));
313 if (!name)
314 return log_oom();
315
316 d = strrchr(name, '.');
317 if (!d)
318 return -EINVAL;
319
320 *d = '\0';
321
322 dropin_dirname = strjoina(name, ".network.d");
323
17f9c355 324 network = new(Network, 1);
f579559b
TG
325 if (!network)
326 return log_oom();
327
17f9c355 328 *network = (Network) {
838b2f7a
YW
329 .filename = TAKE_PTR(fname),
330 .name = TAKE_PTR(name),
17f9c355 331
715d398e 332 .manager = manager,
35ac3b76
YW
333 .n_ref = 1,
334
17f9c355 335 .required_for_online = true,
75cd4a5d 336 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
61135582 337 .activation_policy = _ACTIVATION_POLICY_INVALID,
db5756f3
YW
338 .arp = -1,
339 .multicast = -1,
340 .allmulticast = -1,
937e305e 341 .promiscuous = -1,
db5756f3
YW
342
343 .configure_without_carrier = false,
344 .ignore_carrier_loss = -1,
345 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
346
17f9c355 347 .dhcp = ADDRESS_FAMILY_NO,
db5756f3 348 .duid.type = _DUID_TYPE_INVALID,
7da377ef 349 .dhcp_critical = -1,
17f9c355 350 .dhcp_use_ntp = true,
299d578f 351 .dhcp_use_sip = true,
17f9c355
YW
352 .dhcp_use_dns = true,
353 .dhcp_use_hostname = true,
354 .dhcp_use_routes = true,
589397a2 355 .dhcp_use_gateway = -1,
5238e957 356 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355 357 .dhcp_send_hostname = true,
5f3b5f19 358 .dhcp_send_release = true,
17f9c355
YW
359 /* To enable/disable RFC7844 Anonymity Profiles */
360 .dhcp_anonymize = false,
361 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 362 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
363 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
364 .dhcp_route_table = RT_TABLE_MAIN,
365 .dhcp_route_table_set = false,
366 /* NOTE: from man: UseMTU=... Defaults to false*/
367 .dhcp_use_mtu = false,
368 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
369 .dhcp_use_timezone = false,
db5756f3 370 .dhcp_ip_service_type = -1,
17f9c355 371
1536b7b2
YW
372 .dhcp6_use_address = true,
373 .dhcp6_use_dns = true,
38ba3da0 374 .dhcp6_use_hostname = true,
1536b7b2 375 .dhcp6_use_ntp = true,
db5756f3 376 .dhcp6_rapid_commit = true,
1bf1bfd9 377 .dhcp6_route_metric = DHCP_ROUTE_METRIC,
caa8ca42 378
e502f94d 379 .dhcp6_pd = -1,
4afd9867 380 .dhcp6_pd_announce = true,
99e015e2 381 .dhcp6_pd_assign = true,
fec1b650 382 .dhcp6_pd_manage_temporary_address = true,
4afd9867 383 .dhcp6_pd_subnet_id = -1,
9efa8a3c 384
2a71d57f
LP
385 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
386 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
387 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
388
17f9c355
YW
389 .dhcp_server_emit_router = true,
390 .dhcp_server_emit_timezone = true,
391
71a5db49 392 .router_lifetime_usec = 30 * USEC_PER_MINUTE,
17f9c355
YW
393 .router_emit_dns = true,
394 .router_emit_domains = true,
395
396 .use_bpdu = -1,
397 .hairpin = -1,
398 .fast_leave = -1,
399 .allow_port_to_be_root = -1,
400 .unicast_flood = -1,
7f15b714 401 .multicast_flood = -1,
d3aa8b49 402 .multicast_to_unicast = -1,
7f15b714
TJ
403 .neighbor_suppression = -1,
404 .learning = -1,
1087623b
SS
405 .bridge_proxy_arp = -1,
406 .bridge_proxy_arp_wifi = -1,
17f9c355 407 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 408 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
409
410 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
411
7ece6f58 412 .dns_default_route = -1,
17f9c355
YW
413 .llmnr = RESOLVE_SUPPORT_YES,
414 .mdns = RESOLVE_SUPPORT_NO,
415 .dnssec_mode = _DNSSEC_MODE_INVALID,
416 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
417
0321cea7 418 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 419 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 420 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 421
94d76d07 422 .ipv4_accept_local = -1,
d75bf6cf 423 .ipv4_route_localnet = -1,
17f9c355
YW
424 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
425 .ipv6_accept_ra = -1,
426 .ipv6_dad_transmits = -1,
427 .ipv6_hop_limit = -1,
428 .ipv6_proxy_ndp = -1,
17f9c355 429 .proxy_arp = -1,
db5756f3 430
17f9c355 431 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
432 .ipv6_accept_ra_use_autonomous_prefix = true,
433 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 434 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 435 .ipv6_accept_ra_route_table_set = false,
cabe5711 436 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
c423be28
CG
437
438 .can_triple_sampling = -1,
77b67404 439 .can_berr_reporting = -1,
52aa38f1 440 .can_termination = -1,
f594b5fe
CG
441 .can_listen_only = -1,
442 .can_fd_mode = -1,
443 .can_non_iso = -1,
17f9c355 444 };
f579559b 445
4f9ff96a 446 r = config_parse_many(
8b8024f1 447 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
4f9ff96a
LP
448 "Match\0"
449 "Link\0"
518cd6b5 450 "SR-IOV\0"
4f9ff96a
LP
451 "Network\0"
452 "Address\0"
453 "Neighbor\0"
454 "IPv6AddressLabel\0"
455 "RoutingPolicyRule\0"
456 "Route\0"
457 "NextHop\0"
458 "DHCP\0" /* compat */
459 "DHCPv4\0"
460 "DHCPv6\0"
b209cff2 461 "DHCPv6PrefixDelegation\0"
4f9ff96a
LP
462 "DHCPServer\0"
463 "IPv6AcceptRA\0"
464 "IPv6NDPProxyAddress\0"
465 "Bridge\0"
466 "BridgeFDB\0"
3db468ea 467 "BridgeMDB\0"
4f9ff96a 468 "BridgeVLAN\0"
27ff0490 469 "IPv6SendRA\0"
4f9ff96a
LP
470 "IPv6PrefixDelegation\0"
471 "IPv6Prefix\0"
472 "IPv6RoutePrefix\0"
473 "LLDP\0"
474 "TrafficControlQueueingDiscipline\0"
475 "CAN\0"
476 "QDisc\0"
477 "BFIFO\0"
478 "CAKE\0"
479 "ControlledDelay\0"
480 "DeficitRoundRobinScheduler\0"
481 "DeficitRoundRobinSchedulerClass\0"
d474aa51 482 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
483 "FairQueueing\0"
484 "FairQueueingControlledDelay\0"
8f6b6d70 485 "FlowQueuePIE\0"
4f9ff96a
LP
486 "GenericRandomEarlyDetection\0"
487 "HeavyHitterFilter\0"
488 "HierarchyTokenBucket\0"
489 "HierarchyTokenBucketClass\0"
490 "NetworkEmulator\0"
b12aaee5
SS
491 "PFIFO\0"
492 "PFIFOFast\0"
493 "PFIFOHeadDrop\0"
4f9ff96a 494 "PIE\0"
b12aaee5 495 "QuickFairQueueing\0"
4d7ddaf9 496 "QuickFairQueueingClass\0"
4f9ff96a
LP
497 "StochasticFairBlue\0"
498 "StochasticFairnessQueueing\0"
499 "TokenBucketFilter\0"
500 "TrivialLinkEqualizer\0",
501 config_item_perf_lookup, network_network_gperf_lookup,
502 CONFIG_PARSE_WARN,
503 network,
504 &network->timestamp);
102bc043 505 if (r < 0)
f579559b 506 return r;
f579559b 507
add8d07d 508 network_apply_anonymize_if_set(network);
509
fa7cd711
YW
510 r = network_add_ipv4ll_route(network);
511 if (r < 0)
512 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
513
5d5003ab
YW
514 r = network_add_default_route_on_device(network);
515 if (r < 0)
516 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
517 network->filename);
518
7f06b3e1
YW
519 if (network_verify(network) < 0)
520 /* Ignore .network files that do not match the conditions. */
521 return 0;
522
9fa3e794 523 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
dbffab87
TG
524 if (r < 0)
525 return r;
526
b5b9b0e7 527 TAKE_PTR(network);
f579559b
TG
528 return 0;
529}
530
7f06b3e1 531int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
532 _cleanup_strv_free_ char **files = NULL;
533 char **f;
f579559b
TG
534 int r;
535
536 assert(manager);
537
7f06b3e1 538 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 539
dc0d4078 540 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
541 if (r < 0)
542 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 543
715d398e 544 STRV_FOREACH(f, files) {
7f06b3e1 545 r = network_load_one(manager, networks, *f);
f579559b 546 if (r < 0)
be711082 547 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
548 }
549
f579559b
TG
550 return 0;
551}
552
7f06b3e1
YW
553int network_reload(Manager *manager) {
554 OrderedHashmap *new_networks = NULL;
555 Network *n, *old;
7f06b3e1
YW
556 int r;
557
558 assert(manager);
559
560 r = network_load(manager, &new_networks);
561 if (r < 0)
562 goto failure;
563
90e74a66 564 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1
YW
565 r = network_get_by_name(manager, n->name, &old);
566 if (r < 0)
567 continue; /* The .network file is new. */
568
569 if (n->timestamp != old->timestamp)
570 continue; /* The .network file is modified. */
571
572 if (!streq(n->filename, old->filename))
573 continue;
574
575 r = ordered_hashmap_replace(new_networks, old->name, old);
576 if (r < 0)
577 goto failure;
578
579 network_ref(old);
580 network_unref(n);
581 }
582
583 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
584 manager->networks = new_networks;
585
586 return 0;
587
588failure:
589 ordered_hashmap_free_with_destructor(new_networks, network_unref);
590
591 return r;
592}
593
35ac3b76 594static Network *network_free(Network *network) {
f579559b 595 if (!network)
35ac3b76 596 return NULL;
f579559b
TG
597
598 free(network->filename);
599
5722fb89 600 net_match_clear(&network->match);
c4f58dea 601 condition_free_list(network->conditions);
f579559b
TG
602
603 free(network->description);
edb85f0d 604 free(network->dhcp_vendor_class_identifier);
7b8d23a9 605 free(network->dhcp_mudurl);
af1c0de0 606 strv_free(network->dhcp_user_class);
27cb34f5 607 free(network->dhcp_hostname);
6b000af4 608 set_free(network->dhcp_deny_listed_ip);
98ebef62 609 set_free(network->dhcp_allow_listed_ip);
5bc945be 610 set_free(network->dhcp_request_options);
35f6a5cb 611 set_free(network->dhcp6_request_options);
c106cc36 612 free(network->mac);
3175a8c2 613 free(network->dhcp6_mudurl);
f37f2a6b 614 strv_free(network->dhcp6_user_class);
ed0d1b2e 615 strv_free(network->dhcp6_vendor_class);
c106cc36 616
b0e39c82 617 strv_free(network->ntp);
e77bd3fd
YW
618 for (unsigned i = 0; i < network->n_dns; i++)
619 in_addr_full_free(network->dns[i]);
5512a963 620 free(network->dns);
5e276772
YW
621 ordered_set_free(network->search_domains);
622 ordered_set_free(network->route_domains);
0d4ad91d 623 strv_free(network->bind_carrier);
cdd7812b 624
5e276772 625 ordered_set_free(network->router_search_domains);
cdd7812b 626 free(network->router_dns);
75d26411
YW
627 set_free_free(network->ndisc_deny_listed_router);
628 set_free_free(network->ndisc_allow_listed_router);
6b000af4 629 set_free_free(network->ndisc_deny_listed_prefix);
de6b6ff8 630 set_free_free(network->ndisc_allow_listed_prefix);
16c89e64 631 set_free_free(network->ndisc_deny_listed_route_prefix);
de6b6ff8 632 set_free_free(network->ndisc_allow_listed_route_prefix);
3bef724f 633
c0267a59 634 free(network->batadv_name);
cebe1257
YW
635 free(network->bridge_name);
636 free(network->bond_name);
637 free(network->vrf_name);
638 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 639 netdev_unref(network->bridge);
47e2dc31 640 netdev_unref(network->bond);
6cb955c6 641 netdev_unref(network->vrf);
fa6f1e54 642 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 643
d349f502 644 set_free_free(network->ipv6_proxy_ndp_addresses);
9cd9fc8f 645 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 646 hashmap_free_with_destructor(network->routes_by_section, route_free);
b82663dd 647 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
62ed9442 648 hashmap_free_with_destructor(network->fdb_entries_by_section, fdb_entry_free);
03c9738e 649 hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free);
b0ba6938 650 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
d6a2a0f9 651 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
ecb0e85e
YW
652 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
653 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
ca183bf8 654 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
518cd6b5 655 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
34658df2 656 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 657
7f06b3e1
YW
658 if (network->manager &&
659 network->manager->duids_requesting_uuid)
660 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
661
662 free(network->name);
f579559b 663
8eb9058d 664 free(network->dhcp_server_timezone);
2a71d57f 665
2324fd3a 666 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
2a71d57f 667 free(network->dhcp_server_emit[t].addresses);
8eb9058d 668
8a516214
LP
669 set_free_free(network->dnssec_negative_trust_anchors);
670
e9a8c550
SS
671 free(network->lldp_mud);
672
0e96961d 673 ordered_hashmap_free(network->dhcp_client_send_options);
7354900d 674 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
0e96961d 675 ordered_hashmap_free(network->dhcp_server_send_options);
7354900d 676 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
2c621495 677 ordered_set_free(network->ipv6_tokens);
1c3ec1cd 678 ordered_hashmap_free(network->dhcp6_client_send_options);
b4ccc5de 679 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
cb29c156 680
35ac3b76 681 return mfree(network);
f579559b
TG
682}
683
35ac3b76
YW
684DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
685
dbffab87
TG
686int network_get_by_name(Manager *manager, const char *name, Network **ret) {
687 Network *network;
688
689 assert(manager);
690 assert(name);
691 assert(ret);
692
715d398e 693 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
694 if (!network)
695 return -ENOENT;
696
697 *ret = network;
698
699 return 0;
700}
701
ef62949a 702int network_get(Manager *manager, unsigned short iftype, sd_device *device,
c643bda5
YW
703 const char *ifname, char * const *alternative_names, const char *driver,
704 const struct ether_addr *mac, const struct ether_addr *permanent_mac,
78404d22
YW
705 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
706 Network **ret) {
51517f9e 707 Network *network;
f579559b
TG
708
709 assert(manager);
f579559b 710 assert(ret);
af3aa302 711
90e74a66 712 ORDERED_HASHMAP_FOREACH(network, manager->networks)
5722fb89 713 if (net_match_config(&network->match, device, mac, permanent_mac, driver, iftype,
4bb7cc82 714 ifname, alternative_names, wlan_iftype, ssid, bssid)) {
5722fb89 715 if (network->match.ifname && device) {
ca6038b8
TG
716 const char *attr;
717 uint8_t name_assign_type = NET_NAME_UNKNOWN;
718
51517f9e 719 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 720 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
721
722 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
723 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
724 ifname, network->filename);
32bc8adc 725 else
a2fae7bb 726 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 727 } else
a2fae7bb 728 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 729
f579559b
TG
730 *ret = network;
731 return 0;
732 }
f579559b
TG
733
734 *ret = NULL;
735
736 return -ENOENT;
737}
738
adfeee49 739bool network_has_static_ipv6_configurations(Network *network) {
439689c6 740 Address *address;
adfeee49
YW
741 Route *route;
742 FdbEntry *fdb;
3db468ea 743 MdbEntry *mdb;
adfeee49 744 Neighbor *neighbor;
439689c6
SS
745
746 assert(network);
747
9cd9fc8f 748 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
749 if (address->family == AF_INET6)
750 return true;
adfeee49 751
2a54a044 752 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
753 if (route->family == AF_INET6)
754 return true;
755
62ed9442 756 HASHMAP_FOREACH(fdb, network->fdb_entries_by_section)
adfeee49
YW
757 if (fdb->family == AF_INET6)
758 return true;
759
03c9738e 760 HASHMAP_FOREACH(mdb, network->mdb_entries_by_section)
3db468ea
DM
761 if (mdb->family == AF_INET6)
762 return true;
763
b0ba6938 764 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
adfeee49
YW
765 if (neighbor->family == AF_INET6)
766 return true;
767
d6a2a0f9 768 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
769 return true;
770
ecb0e85e 771 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 772 return true;
d30081c2
YW
773
774 if (!hashmap_isempty(network->route_prefixes_by_section))
775 return true;
439689c6
SS
776
777 return false;
778}
779
cebe1257 780int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
781 const char *filename,
782 unsigned line,
783 const char *section,
784 unsigned section_line,
785 const char *lvalue,
786 int ltype,
787 const char *rvalue,
788 void *data,
789 void *userdata) {
95dba435
YW
790 _cleanup_free_ char *name = NULL;
791 NetDevKind kind = ltype;
cebe1257 792 Hashmap **h = data;
02b59d57
TG
793 int r;
794
795 assert(filename);
796 assert(lvalue);
797 assert(rvalue);
798 assert(data);
95dba435
YW
799 assert(IN_SET(kind,
800 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 801 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 802 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
803 NETDEV_KIND_XFRM));
54abf461 804
cebe1257 805 if (!ifname_valid(rvalue)) {
d96edb2c 806 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 807 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
808 return 0;
809 }
810
cebe1257
YW
811 name = strdup(rvalue);
812 if (!name)
813 return log_oom();
3e570042 814
6de530f2
SS
815 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
816 if (r == -ENOMEM)
cebe1257 817 return log_oom();
83ec4592 818 if (r < 0)
d96edb2c 819 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
820 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
821 else if (r == 0)
822 log_syntax(unit, LOG_DEBUG, filename, line, r,
823 "NetDev '%s' specified twice, ignoring.", name);
824 else
0c7bd7ec 825 TAKE_PTR(name);
47e2dc31 826
fe6b2d55
TG
827 return 0;
828}
7951dea2 829
3df9bec5
LP
830int config_parse_domains(
831 const char *unit,
832 const char *filename,
833 unsigned line,
834 const char *section,
835 unsigned section_line,
836 const char *lvalue,
837 int ltype,
838 const char *rvalue,
839 void *data,
840 void *userdata) {
841
3df9bec5 842 Network *n = data;
6192b846
TG
843 int r;
844
3df9bec5
LP
845 assert(n);
846 assert(lvalue);
847 assert(rvalue);
6192b846 848
3df9bec5 849 if (isempty(rvalue)) {
5e276772
YW
850 n->search_domains = ordered_set_free(n->search_domains);
851 n->route_domains = ordered_set_free(n->route_domains);
3df9bec5
LP
852 return 0;
853 }
67272d15 854
d96edb2c 855 for (const char *p = rvalue;;) {
3df9bec5
LP
856 _cleanup_free_ char *w = NULL, *normalized = NULL;
857 const char *domain;
858 bool is_route;
859
860 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
861 if (r == -ENOMEM)
862 return log_oom();
3df9bec5 863 if (r < 0) {
d96edb2c 864 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 865 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 866 return 0;
3df9bec5
LP
867 }
868 if (r == 0)
d96edb2c 869 return 0;
3df9bec5
LP
870
871 is_route = w[0] == '~';
872 domain = is_route ? w + 1 : w;
873
874 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
875 /* If the root domain appears as is, or the special token "*" is found, we'll
876 * consider this as routing domain, unconditionally. */
3df9bec5 877 is_route = true;
ab24039f
ZJS
878 domain = "."; /* make sure we don't allow empty strings, thus write the root
879 * domain as "." */
3df9bec5 880 } else {
7470cc4c 881 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 882 if (r < 0) {
d96edb2c 883 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 884 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
885 continue;
886 }
887
888 domain = normalized;
889
890 if (is_localhost(domain)) {
d96edb2c 891 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
892 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
893 domain);
37de2509 894 continue;
3df9bec5 895 }
37de2509 896 }
40274ed6 897
5e2a51d5 898 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
5e276772 899 r = ordered_set_ensure_allocated(set, &string_hash_ops_free);
5e2a51d5 900 if (r < 0)
d96edb2c 901 return log_oom();
5e2a51d5
ZJS
902
903 r = ordered_set_put_strdup(*set, domain);
09451975
LP
904 if (r < 0)
905 return log_oom();
40274ed6 906 }
6192b846
TG
907}
908
1ac608c9
LP
909int config_parse_hostname(
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
6528693a
YW
921 _cleanup_free_ char *hn = NULL;
922 char **hostname = data;
a7d0ef44
SS
923 int r;
924
925 assert(filename);
926 assert(lvalue);
927 assert(rvalue);
928
1ac608c9 929 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
930 if (r < 0)
931 return r;
932
52ef5dd7 933 if (!hostname_is_valid(hn, 0)) {
d96edb2c 934 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 935 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
936 return 0;
937 }
938
6528693a
YW
939 r = dns_name_is_valid(hn);
940 if (r < 0) {
d96edb2c 941 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 942 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
943 return 0;
944 }
945 if (r == 0) {
d96edb2c 946 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 947 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
948 return 0;
949 }
950
951 return free_and_replace(*hostname, hn);
a7d0ef44 952}
8eb9058d
LP
953
954int config_parse_timezone(
955 const char *unit,
956 const char *filename,
957 unsigned line,
958 const char *section,
959 unsigned section_line,
960 const char *lvalue,
961 int ltype,
962 const char *rvalue,
963 void *data,
964 void *userdata) {
965
19f9e4e2
YW
966 _cleanup_free_ char *tz = NULL;
967 char **datap = data;
8eb9058d
LP
968 int r;
969
970 assert(filename);
971 assert(lvalue);
972 assert(rvalue);
973
974 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
975 if (r < 0)
976 return r;
977
d96edb2c
YW
978 if (!timezone_is_valid(tz, LOG_WARNING)) {
979 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 980 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
981 return 0;
982 }
983
19f9e4e2 984 return free_and_replace(*datap, tz);
8eb9058d 985}
1a04db0f 986
53253824
SS
987int config_parse_dns(
988 const char *unit,
989 const char *filename,
990 unsigned line,
991 const char *section,
992 unsigned section_line,
993 const char *lvalue,
994 int ltype,
995 const char *rvalue,
996 void *data,
997 void *userdata) {
998
999 Network *n = userdata;
1000 int r;
1001
1002 assert(filename);
1003 assert(lvalue);
1004 assert(rvalue);
1005
d96edb2c 1006 if (isempty(rvalue)) {
e77bd3fd
YW
1007 for (unsigned i = 0; i < n->n_dns; i++)
1008 in_addr_full_free(n->dns[i]);
d96edb2c
YW
1009 n->dns = mfree(n->dns);
1010 n->n_dns = 0;
1011 return 0;
1012 }
1013
1014 for (const char *p = rvalue;;) {
e77bd3fd 1015 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 1016 _cleanup_free_ char *w = NULL;
e77bd3fd 1017 struct in_addr_full **m;
53253824 1018
d96edb2c 1019 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
1020 if (r == -ENOMEM)
1021 return log_oom();
1022 if (r < 0) {
d96edb2c 1023 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1024 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 1025 return 0;
53253824 1026 }
5512a963 1027 if (r == 0)
d96edb2c 1028 return 0;
53253824 1029
e77bd3fd 1030 r = in_addr_full_new_from_string(w, &dns);
53253824 1031 if (r < 0) {
d96edb2c 1032 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1033 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1034 continue;
1035 }
1036
e77bd3fd
YW
1037 if (IN_SET(dns->port, 53, 853))
1038 dns->port = 0;
1039
1040 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 1041 if (!m)
53253824
SS
1042 return log_oom();
1043
e77bd3fd 1044 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 1045 n->dns = m;
53253824 1046 }
53253824
SS
1047}
1048
8a516214
LP
1049int config_parse_dnssec_negative_trust_anchors(
1050 const char *unit,
1051 const char *filename,
1052 unsigned line,
1053 const char *section,
1054 unsigned section_line,
1055 const char *lvalue,
1056 int ltype,
1057 const char *rvalue,
1058 void *data,
1059 void *userdata) {
1060
8a516214
LP
1061 Network *n = data;
1062 int r;
1063
3df9bec5 1064 assert(n);
8a516214
LP
1065 assert(lvalue);
1066 assert(rvalue);
1067
1068 if (isempty(rvalue)) {
1069 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1070 return 0;
1071 }
1072
d96edb2c 1073 for (const char *p = rvalue;;) {
8a516214
LP
1074 _cleanup_free_ char *w = NULL;
1075
1076 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1077 if (r == -ENOMEM)
1078 return log_oom();
8a516214 1079 if (r < 0) {
d96edb2c 1080 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1081 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1082 return 0;
8a516214
LP
1083 }
1084 if (r == 0)
d96edb2c 1085 return 0;
8a516214
LP
1086
1087 r = dns_name_is_valid(w);
1088 if (r <= 0) {
d96edb2c 1089 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1090 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1091 continue;
1092 }
1093
35e601d4 1094 r = set_ensure_consume(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1095 if (r < 0)
1096 return log_oom();
8a516214 1097 }
8a516214 1098}
b2a81c0b 1099
26575990
LP
1100int config_parse_ntp(
1101 const char *unit,
1102 const char *filename,
1103 unsigned line,
1104 const char *section,
1105 unsigned section_line,
1106 const char *lvalue,
1107 int ltype,
1108 const char *rvalue,
1109 void *data,
1110 void *userdata) {
1111
1112 char ***l = data;
1113 int r;
1114
1115 assert(l);
1116 assert(lvalue);
1117 assert(rvalue);
1118
1119 if (isempty(rvalue)) {
1120 *l = strv_free(*l);
1121 return 0;
1122 }
1123
d96edb2c 1124 for (const char *p = rvalue;;) {
26575990
LP
1125 _cleanup_free_ char *w = NULL;
1126
d96edb2c 1127 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1128 if (r == -ENOMEM)
1129 return log_oom();
1130 if (r < 0) {
d96edb2c 1131 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1132 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1133 return 0;
26575990
LP
1134 }
1135 if (r == 0)
d96edb2c 1136 return 0;
26575990
LP
1137
1138 r = dns_name_is_valid_or_address(w);
1139 if (r <= 0) {
d96edb2c 1140 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1141 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1142 continue;
af1c0de0
SS
1143 }
1144
c448459d
ZJS
1145 if (strv_length(*l) > MAX_NTP_SERVERS) {
1146 log_syntax(unit, LOG_WARNING, filename, line, 0,
1147 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1148 MAX_NTP_SERVERS, w);
d96edb2c 1149 return 0;
c448459d
ZJS
1150 }
1151
1152 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1153 if (r < 0)
1154 return log_oom();
af1c0de0 1155 }
af1c0de0
SS
1156}
1157
4ac77d63
YW
1158int config_parse_required_for_online(
1159 const char *unit,
1160 const char *filename,
1161 unsigned line,
1162 const char *section,
1163 unsigned section_line,
1164 const char *lvalue,
1165 int ltype,
1166 const char *rvalue,
1167 void *data,
1168 void *userdata) {
1169
1170 Network *network = data;
75cd4a5d 1171 LinkOperationalStateRange range;
4ac77d63
YW
1172 bool required = true;
1173 int r;
1174
1175 if (isempty(rvalue)) {
1176 network->required_for_online = true;
75cd4a5d 1177 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1178 return 0;
1179 }
1180
75cd4a5d
DDM
1181 r = parse_operational_state_range(rvalue, &range);
1182 if (r < 0) {
4ac77d63
YW
1183 r = parse_boolean(rvalue);
1184 if (r < 0) {
d96edb2c 1185 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1186 "Failed to parse %s= setting, ignoring assignment: %s",
1187 lvalue, rvalue);
1188 return 0;
1189 }
1190
1191 required = r;
75cd4a5d 1192 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1193 }
1194
1195 network->required_for_online = required;
75cd4a5d 1196 network->required_operstate_for_online = range;
4ac77d63
YW
1197
1198 return 0;
1199}
7da377ef
SS
1200
1201DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1202 "Failed to parse KeepConfiguration= setting");
1203
1204static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1205 [KEEP_CONFIGURATION_NO] = "no",
1206 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1207 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1208 [KEEP_CONFIGURATION_STATIC] = "static",
1209 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1210};
1211
1212DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9
YW
1213
1214static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1215 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1216 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1217 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1218 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1219};
1220
1221DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1222DEFINE_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
1223
1224static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1225 [ACTIVATION_POLICY_UP] = "up",
1226 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1227 [ACTIVATION_POLICY_MANUAL] = "manual",
1228 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1229 [ACTIVATION_POLICY_DOWN] = "down",
1230 [ACTIVATION_POLICY_BOUND] = "bound",
1231};
1232
1233DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1234DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");