]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
udev/net: use null_or_empty_path()
[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;
f579559b 291 _cleanup_fclose_ FILE *file = NULL;
047a0dac 292 const char *dropin_dirname;
838b2f7a 293 char *d;
f579559b
TG
294 int r;
295
bf1bc670
TA
296 assert(manager);
297 assert(filename);
298
f579559b
TG
299 file = fopen(filename, "re");
300 if (!file) {
301 if (errno == ENOENT)
302 return 0;
1e7a0e21
LP
303
304 return -errno;
f579559b
TG
305 }
306
ed88bcfb
ZJS
307 if (null_or_empty_fd(fileno(file))) {
308 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
309 return 0;
310 }
311
838b2f7a
YW
312 fname = strdup(filename);
313 if (!fname)
314 return log_oom();
315
316 name = strdup(basename(filename));
317 if (!name)
318 return log_oom();
319
320 d = strrchr(name, '.');
321 if (!d)
322 return -EINVAL;
323
324 *d = '\0';
325
326 dropin_dirname = strjoina(name, ".network.d");
327
17f9c355 328 network = new(Network, 1);
f579559b
TG
329 if (!network)
330 return log_oom();
331
17f9c355 332 *network = (Network) {
838b2f7a
YW
333 .filename = TAKE_PTR(fname),
334 .name = TAKE_PTR(name),
17f9c355 335
715d398e 336 .manager = manager,
35ac3b76
YW
337 .n_ref = 1,
338
17f9c355 339 .required_for_online = true,
75cd4a5d 340 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
61135582 341 .activation_policy = _ACTIVATION_POLICY_INVALID,
db5756f3
YW
342 .arp = -1,
343 .multicast = -1,
344 .allmulticast = -1,
937e305e 345 .promiscuous = -1,
db5756f3
YW
346
347 .configure_without_carrier = false,
348 .ignore_carrier_loss = -1,
349 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
350
17f9c355 351 .dhcp = ADDRESS_FAMILY_NO,
db5756f3 352 .duid.type = _DUID_TYPE_INVALID,
7da377ef 353 .dhcp_critical = -1,
17f9c355 354 .dhcp_use_ntp = true,
299d578f 355 .dhcp_use_sip = true,
17f9c355
YW
356 .dhcp_use_dns = true,
357 .dhcp_use_hostname = true,
358 .dhcp_use_routes = true,
589397a2 359 .dhcp_use_gateway = -1,
5238e957 360 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355 361 .dhcp_send_hostname = true,
5f3b5f19 362 .dhcp_send_release = true,
17f9c355
YW
363 /* To enable/disable RFC7844 Anonymity Profiles */
364 .dhcp_anonymize = false,
365 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 366 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
367 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
368 .dhcp_route_table = RT_TABLE_MAIN,
369 .dhcp_route_table_set = false,
370 /* NOTE: from man: UseMTU=... Defaults to false*/
371 .dhcp_use_mtu = false,
372 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
373 .dhcp_use_timezone = false,
db5756f3 374 .dhcp_ip_service_type = -1,
17f9c355 375
1536b7b2
YW
376 .dhcp6_use_address = true,
377 .dhcp6_use_dns = true,
38ba3da0 378 .dhcp6_use_hostname = true,
1536b7b2 379 .dhcp6_use_ntp = true,
db5756f3 380 .dhcp6_rapid_commit = true,
1bf1bfd9 381 .dhcp6_route_metric = DHCP_ROUTE_METRIC,
caa8ca42 382
e502f94d 383 .dhcp6_pd = -1,
4afd9867 384 .dhcp6_pd_announce = true,
99e015e2 385 .dhcp6_pd_assign = true,
fec1b650 386 .dhcp6_pd_manage_temporary_address = true,
4afd9867 387 .dhcp6_pd_subnet_id = -1,
9efa8a3c 388
2a71d57f
LP
389 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
390 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
391 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
392
17f9c355
YW
393 .dhcp_server_emit_router = true,
394 .dhcp_server_emit_timezone = true,
395
71a5db49 396 .router_lifetime_usec = 30 * USEC_PER_MINUTE,
17f9c355
YW
397 .router_emit_dns = true,
398 .router_emit_domains = true,
399
400 .use_bpdu = -1,
401 .hairpin = -1,
402 .fast_leave = -1,
403 .allow_port_to_be_root = -1,
404 .unicast_flood = -1,
7f15b714 405 .multicast_flood = -1,
d3aa8b49 406 .multicast_to_unicast = -1,
7f15b714
TJ
407 .neighbor_suppression = -1,
408 .learning = -1,
1087623b
SS
409 .bridge_proxy_arp = -1,
410 .bridge_proxy_arp_wifi = -1,
17f9c355 411 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 412 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
413
414 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
415
7ece6f58 416 .dns_default_route = -1,
17f9c355
YW
417 .llmnr = RESOLVE_SUPPORT_YES,
418 .mdns = RESOLVE_SUPPORT_NO,
419 .dnssec_mode = _DNSSEC_MODE_INVALID,
420 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
421
0321cea7 422 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 423 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 424 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 425
94d76d07 426 .ipv4_accept_local = -1,
d75bf6cf 427 .ipv4_route_localnet = -1,
17f9c355
YW
428 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
429 .ipv6_accept_ra = -1,
430 .ipv6_dad_transmits = -1,
431 .ipv6_hop_limit = -1,
432 .ipv6_proxy_ndp = -1,
17f9c355 433 .proxy_arp = -1,
db5756f3 434
17f9c355 435 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
436 .ipv6_accept_ra_use_autonomous_prefix = true,
437 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 438 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 439 .ipv6_accept_ra_route_table_set = false,
cabe5711 440 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
c423be28
CG
441
442 .can_triple_sampling = -1,
77b67404 443 .can_berr_reporting = -1,
52aa38f1 444 .can_termination = -1,
f594b5fe
CG
445 .can_listen_only = -1,
446 .can_fd_mode = -1,
447 .can_non_iso = -1,
17f9c355 448 };
f579559b 449
4f9ff96a 450 r = config_parse_many(
8b8024f1 451 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
4f9ff96a
LP
452 "Match\0"
453 "Link\0"
518cd6b5 454 "SR-IOV\0"
4f9ff96a
LP
455 "Network\0"
456 "Address\0"
457 "Neighbor\0"
458 "IPv6AddressLabel\0"
459 "RoutingPolicyRule\0"
460 "Route\0"
461 "NextHop\0"
462 "DHCP\0" /* compat */
463 "DHCPv4\0"
464 "DHCPv6\0"
b209cff2 465 "DHCPv6PrefixDelegation\0"
4f9ff96a
LP
466 "DHCPServer\0"
467 "IPv6AcceptRA\0"
468 "IPv6NDPProxyAddress\0"
469 "Bridge\0"
470 "BridgeFDB\0"
3db468ea 471 "BridgeMDB\0"
4f9ff96a 472 "BridgeVLAN\0"
27ff0490 473 "IPv6SendRA\0"
4f9ff96a
LP
474 "IPv6PrefixDelegation\0"
475 "IPv6Prefix\0"
476 "IPv6RoutePrefix\0"
477 "LLDP\0"
478 "TrafficControlQueueingDiscipline\0"
479 "CAN\0"
480 "QDisc\0"
481 "BFIFO\0"
482 "CAKE\0"
483 "ControlledDelay\0"
484 "DeficitRoundRobinScheduler\0"
485 "DeficitRoundRobinSchedulerClass\0"
d474aa51 486 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
487 "FairQueueing\0"
488 "FairQueueingControlledDelay\0"
8f6b6d70 489 "FlowQueuePIE\0"
4f9ff96a
LP
490 "GenericRandomEarlyDetection\0"
491 "HeavyHitterFilter\0"
492 "HierarchyTokenBucket\0"
493 "HierarchyTokenBucketClass\0"
494 "NetworkEmulator\0"
b12aaee5
SS
495 "PFIFO\0"
496 "PFIFOFast\0"
497 "PFIFOHeadDrop\0"
4f9ff96a 498 "PIE\0"
b12aaee5 499 "QuickFairQueueing\0"
4d7ddaf9 500 "QuickFairQueueingClass\0"
4f9ff96a
LP
501 "StochasticFairBlue\0"
502 "StochasticFairnessQueueing\0"
503 "TokenBucketFilter\0"
504 "TrivialLinkEqualizer\0",
505 config_item_perf_lookup, network_network_gperf_lookup,
506 CONFIG_PARSE_WARN,
507 network,
508 &network->timestamp);
102bc043 509 if (r < 0)
f579559b 510 return r;
f579559b 511
add8d07d 512 network_apply_anonymize_if_set(network);
513
fa7cd711
YW
514 r = network_add_ipv4ll_route(network);
515 if (r < 0)
516 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
517
5d5003ab
YW
518 r = network_add_default_route_on_device(network);
519 if (r < 0)
520 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
521 network->filename);
522
7f06b3e1
YW
523 if (network_verify(network) < 0)
524 /* Ignore .network files that do not match the conditions. */
525 return 0;
526
9fa3e794 527 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
dbffab87
TG
528 if (r < 0)
529 return r;
530
b5b9b0e7 531 TAKE_PTR(network);
f579559b
TG
532 return 0;
533}
534
7f06b3e1 535int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
536 _cleanup_strv_free_ char **files = NULL;
537 char **f;
f579559b
TG
538 int r;
539
540 assert(manager);
541
7f06b3e1 542 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 543
dc0d4078 544 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
545 if (r < 0)
546 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 547
715d398e 548 STRV_FOREACH(f, files) {
7f06b3e1 549 r = network_load_one(manager, networks, *f);
f579559b 550 if (r < 0)
be711082 551 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
552 }
553
f579559b
TG
554 return 0;
555}
556
7f06b3e1
YW
557int network_reload(Manager *manager) {
558 OrderedHashmap *new_networks = NULL;
559 Network *n, *old;
7f06b3e1
YW
560 int r;
561
562 assert(manager);
563
564 r = network_load(manager, &new_networks);
565 if (r < 0)
566 goto failure;
567
90e74a66 568 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1
YW
569 r = network_get_by_name(manager, n->name, &old);
570 if (r < 0)
571 continue; /* The .network file is new. */
572
573 if (n->timestamp != old->timestamp)
574 continue; /* The .network file is modified. */
575
576 if (!streq(n->filename, old->filename))
577 continue;
578
579 r = ordered_hashmap_replace(new_networks, old->name, old);
580 if (r < 0)
581 goto failure;
582
583 network_ref(old);
584 network_unref(n);
585 }
586
587 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
588 manager->networks = new_networks;
589
590 return 0;
591
592failure:
593 ordered_hashmap_free_with_destructor(new_networks, network_unref);
594
595 return r;
596}
597
35ac3b76 598static Network *network_free(Network *network) {
f579559b 599 if (!network)
35ac3b76 600 return NULL;
f579559b
TG
601
602 free(network->filename);
603
5722fb89 604 net_match_clear(&network->match);
c4f58dea 605 condition_free_list(network->conditions);
f579559b
TG
606
607 free(network->description);
edb85f0d 608 free(network->dhcp_vendor_class_identifier);
7b8d23a9 609 free(network->dhcp_mudurl);
af1c0de0 610 strv_free(network->dhcp_user_class);
27cb34f5 611 free(network->dhcp_hostname);
6b000af4 612 set_free(network->dhcp_deny_listed_ip);
98ebef62 613 set_free(network->dhcp_allow_listed_ip);
5bc945be 614 set_free(network->dhcp_request_options);
35f6a5cb 615 set_free(network->dhcp6_request_options);
c106cc36 616 free(network->mac);
3175a8c2 617 free(network->dhcp6_mudurl);
f37f2a6b 618 strv_free(network->dhcp6_user_class);
ed0d1b2e 619 strv_free(network->dhcp6_vendor_class);
c106cc36 620
b0e39c82 621 strv_free(network->ntp);
e77bd3fd
YW
622 for (unsigned i = 0; i < network->n_dns; i++)
623 in_addr_full_free(network->dns[i]);
5512a963 624 free(network->dns);
5e276772
YW
625 ordered_set_free(network->search_domains);
626 ordered_set_free(network->route_domains);
0d4ad91d 627 strv_free(network->bind_carrier);
cdd7812b 628
5e276772 629 ordered_set_free(network->router_search_domains);
cdd7812b 630 free(network->router_dns);
75d26411
YW
631 set_free_free(network->ndisc_deny_listed_router);
632 set_free_free(network->ndisc_allow_listed_router);
6b000af4 633 set_free_free(network->ndisc_deny_listed_prefix);
de6b6ff8 634 set_free_free(network->ndisc_allow_listed_prefix);
16c89e64 635 set_free_free(network->ndisc_deny_listed_route_prefix);
de6b6ff8 636 set_free_free(network->ndisc_allow_listed_route_prefix);
3bef724f 637
c0267a59 638 free(network->batadv_name);
cebe1257
YW
639 free(network->bridge_name);
640 free(network->bond_name);
641 free(network->vrf_name);
642 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 643 netdev_unref(network->bridge);
47e2dc31 644 netdev_unref(network->bond);
6cb955c6 645 netdev_unref(network->vrf);
fa6f1e54 646 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 647
d349f502 648 set_free_free(network->ipv6_proxy_ndp_addresses);
9cd9fc8f 649 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 650 hashmap_free_with_destructor(network->routes_by_section, route_free);
b82663dd 651 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
62ed9442 652 hashmap_free_with_destructor(network->fdb_entries_by_section, fdb_entry_free);
03c9738e 653 hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free);
b0ba6938 654 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
d6a2a0f9 655 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
ecb0e85e
YW
656 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
657 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
ca183bf8 658 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
518cd6b5 659 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
34658df2 660 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 661
7f06b3e1
YW
662 if (network->manager &&
663 network->manager->duids_requesting_uuid)
664 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
665
666 free(network->name);
f579559b 667
8eb9058d 668 free(network->dhcp_server_timezone);
2a71d57f 669
2324fd3a 670 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
2a71d57f 671 free(network->dhcp_server_emit[t].addresses);
8eb9058d 672
8a516214
LP
673 set_free_free(network->dnssec_negative_trust_anchors);
674
e9a8c550
SS
675 free(network->lldp_mud);
676
0e96961d 677 ordered_hashmap_free(network->dhcp_client_send_options);
7354900d 678 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
0e96961d 679 ordered_hashmap_free(network->dhcp_server_send_options);
7354900d 680 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
2c621495 681 ordered_set_free(network->ipv6_tokens);
1c3ec1cd 682 ordered_hashmap_free(network->dhcp6_client_send_options);
b4ccc5de 683 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
cb29c156 684
35ac3b76 685 return mfree(network);
f579559b
TG
686}
687
35ac3b76
YW
688DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
689
dbffab87
TG
690int network_get_by_name(Manager *manager, const char *name, Network **ret) {
691 Network *network;
692
693 assert(manager);
694 assert(name);
695 assert(ret);
696
715d398e 697 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
698 if (!network)
699 return -ENOENT;
700
701 *ret = network;
702
703 return 0;
704}
705
ef62949a 706int network_get(Manager *manager, unsigned short iftype, sd_device *device,
c643bda5
YW
707 const char *ifname, char * const *alternative_names, const char *driver,
708 const struct ether_addr *mac, const struct ether_addr *permanent_mac,
78404d22
YW
709 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
710 Network **ret) {
51517f9e 711 Network *network;
f579559b
TG
712
713 assert(manager);
f579559b 714 assert(ret);
af3aa302 715
90e74a66 716 ORDERED_HASHMAP_FOREACH(network, manager->networks)
5722fb89 717 if (net_match_config(&network->match, device, mac, permanent_mac, driver, iftype,
4bb7cc82 718 ifname, alternative_names, wlan_iftype, ssid, bssid)) {
5722fb89 719 if (network->match.ifname && device) {
ca6038b8
TG
720 const char *attr;
721 uint8_t name_assign_type = NET_NAME_UNKNOWN;
722
51517f9e 723 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 724 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
725
726 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
727 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
728 ifname, network->filename);
32bc8adc 729 else
a2fae7bb 730 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 731 } else
a2fae7bb 732 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 733
f579559b
TG
734 *ret = network;
735 return 0;
736 }
f579559b
TG
737
738 *ret = NULL;
739
740 return -ENOENT;
741}
742
adfeee49 743bool network_has_static_ipv6_configurations(Network *network) {
439689c6 744 Address *address;
adfeee49
YW
745 Route *route;
746 FdbEntry *fdb;
3db468ea 747 MdbEntry *mdb;
adfeee49 748 Neighbor *neighbor;
439689c6
SS
749
750 assert(network);
751
9cd9fc8f 752 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
753 if (address->family == AF_INET6)
754 return true;
adfeee49 755
2a54a044 756 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
757 if (route->family == AF_INET6)
758 return true;
759
62ed9442 760 HASHMAP_FOREACH(fdb, network->fdb_entries_by_section)
adfeee49
YW
761 if (fdb->family == AF_INET6)
762 return true;
763
03c9738e 764 HASHMAP_FOREACH(mdb, network->mdb_entries_by_section)
3db468ea
DM
765 if (mdb->family == AF_INET6)
766 return true;
767
b0ba6938 768 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
adfeee49
YW
769 if (neighbor->family == AF_INET6)
770 return true;
771
d6a2a0f9 772 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
773 return true;
774
ecb0e85e 775 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 776 return true;
d30081c2
YW
777
778 if (!hashmap_isempty(network->route_prefixes_by_section))
779 return true;
439689c6
SS
780
781 return false;
782}
783
cebe1257 784int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
785 const char *filename,
786 unsigned line,
787 const char *section,
788 unsigned section_line,
789 const char *lvalue,
790 int ltype,
791 const char *rvalue,
792 void *data,
793 void *userdata) {
95dba435
YW
794 _cleanup_free_ char *name = NULL;
795 NetDevKind kind = ltype;
cebe1257 796 Hashmap **h = data;
02b59d57
TG
797 int r;
798
799 assert(filename);
800 assert(lvalue);
801 assert(rvalue);
802 assert(data);
95dba435
YW
803 assert(IN_SET(kind,
804 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 805 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 806 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
807 NETDEV_KIND_XFRM));
54abf461 808
cebe1257 809 if (!ifname_valid(rvalue)) {
d96edb2c 810 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 811 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
812 return 0;
813 }
814
cebe1257
YW
815 name = strdup(rvalue);
816 if (!name)
817 return log_oom();
3e570042 818
6de530f2
SS
819 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
820 if (r == -ENOMEM)
cebe1257 821 return log_oom();
83ec4592 822 if (r < 0)
d96edb2c 823 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
824 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
825 else if (r == 0)
826 log_syntax(unit, LOG_DEBUG, filename, line, r,
827 "NetDev '%s' specified twice, ignoring.", name);
828 else
0c7bd7ec 829 TAKE_PTR(name);
47e2dc31 830
fe6b2d55
TG
831 return 0;
832}
7951dea2 833
3df9bec5
LP
834int config_parse_domains(
835 const char *unit,
836 const char *filename,
837 unsigned line,
838 const char *section,
839 unsigned section_line,
840 const char *lvalue,
841 int ltype,
842 const char *rvalue,
843 void *data,
844 void *userdata) {
845
3df9bec5 846 Network *n = data;
6192b846
TG
847 int r;
848
3df9bec5
LP
849 assert(n);
850 assert(lvalue);
851 assert(rvalue);
6192b846 852
3df9bec5 853 if (isempty(rvalue)) {
5e276772
YW
854 n->search_domains = ordered_set_free(n->search_domains);
855 n->route_domains = ordered_set_free(n->route_domains);
3df9bec5
LP
856 return 0;
857 }
67272d15 858
d96edb2c 859 for (const char *p = rvalue;;) {
3df9bec5
LP
860 _cleanup_free_ char *w = NULL, *normalized = NULL;
861 const char *domain;
862 bool is_route;
863
864 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
865 if (r == -ENOMEM)
866 return log_oom();
3df9bec5 867 if (r < 0) {
d96edb2c 868 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 869 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 870 return 0;
3df9bec5
LP
871 }
872 if (r == 0)
d96edb2c 873 return 0;
3df9bec5
LP
874
875 is_route = w[0] == '~';
876 domain = is_route ? w + 1 : w;
877
878 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
879 /* If the root domain appears as is, or the special token "*" is found, we'll
880 * consider this as routing domain, unconditionally. */
3df9bec5 881 is_route = true;
ab24039f
ZJS
882 domain = "."; /* make sure we don't allow empty strings, thus write the root
883 * domain as "." */
3df9bec5 884 } else {
7470cc4c 885 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 886 if (r < 0) {
d96edb2c 887 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 888 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
889 continue;
890 }
891
892 domain = normalized;
893
894 if (is_localhost(domain)) {
d96edb2c 895 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
896 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
897 domain);
37de2509 898 continue;
3df9bec5 899 }
37de2509 900 }
40274ed6 901
5e2a51d5 902 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
5e276772 903 r = ordered_set_ensure_allocated(set, &string_hash_ops_free);
5e2a51d5 904 if (r < 0)
d96edb2c 905 return log_oom();
5e2a51d5
ZJS
906
907 r = ordered_set_put_strdup(*set, domain);
09451975
LP
908 if (r < 0)
909 return log_oom();
40274ed6 910 }
6192b846
TG
911}
912
1ac608c9
LP
913int config_parse_hostname(
914 const char *unit,
915 const char *filename,
916 unsigned line,
917 const char *section,
918 unsigned section_line,
919 const char *lvalue,
920 int ltype,
921 const char *rvalue,
922 void *data,
923 void *userdata) {
924
6528693a
YW
925 _cleanup_free_ char *hn = NULL;
926 char **hostname = data;
a7d0ef44
SS
927 int r;
928
929 assert(filename);
930 assert(lvalue);
931 assert(rvalue);
932
1ac608c9 933 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
934 if (r < 0)
935 return r;
936
52ef5dd7 937 if (!hostname_is_valid(hn, 0)) {
d96edb2c 938 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 939 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
940 return 0;
941 }
942
6528693a
YW
943 r = dns_name_is_valid(hn);
944 if (r < 0) {
d96edb2c 945 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 946 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
947 return 0;
948 }
949 if (r == 0) {
d96edb2c 950 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 951 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
952 return 0;
953 }
954
955 return free_and_replace(*hostname, hn);
a7d0ef44 956}
8eb9058d
LP
957
958int config_parse_timezone(
959 const char *unit,
960 const char *filename,
961 unsigned line,
962 const char *section,
963 unsigned section_line,
964 const char *lvalue,
965 int ltype,
966 const char *rvalue,
967 void *data,
968 void *userdata) {
969
19f9e4e2
YW
970 _cleanup_free_ char *tz = NULL;
971 char **datap = data;
8eb9058d
LP
972 int r;
973
974 assert(filename);
975 assert(lvalue);
976 assert(rvalue);
977
978 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
979 if (r < 0)
980 return r;
981
d96edb2c
YW
982 if (!timezone_is_valid(tz, LOG_WARNING)) {
983 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 984 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
985 return 0;
986 }
987
19f9e4e2 988 return free_and_replace(*datap, tz);
8eb9058d 989}
1a04db0f 990
53253824
SS
991int config_parse_dns(
992 const char *unit,
993 const char *filename,
994 unsigned line,
995 const char *section,
996 unsigned section_line,
997 const char *lvalue,
998 int ltype,
999 const char *rvalue,
1000 void *data,
1001 void *userdata) {
1002
1003 Network *n = userdata;
1004 int r;
1005
1006 assert(filename);
1007 assert(lvalue);
1008 assert(rvalue);
1009
d96edb2c 1010 if (isempty(rvalue)) {
e77bd3fd
YW
1011 for (unsigned i = 0; i < n->n_dns; i++)
1012 in_addr_full_free(n->dns[i]);
d96edb2c
YW
1013 n->dns = mfree(n->dns);
1014 n->n_dns = 0;
1015 return 0;
1016 }
1017
1018 for (const char *p = rvalue;;) {
e77bd3fd 1019 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 1020 _cleanup_free_ char *w = NULL;
e77bd3fd 1021 struct in_addr_full **m;
53253824 1022
d96edb2c 1023 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
1024 if (r == -ENOMEM)
1025 return log_oom();
1026 if (r < 0) {
d96edb2c 1027 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1028 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 1029 return 0;
53253824 1030 }
5512a963 1031 if (r == 0)
d96edb2c 1032 return 0;
53253824 1033
e77bd3fd 1034 r = in_addr_full_new_from_string(w, &dns);
53253824 1035 if (r < 0) {
d96edb2c 1036 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1037 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1038 continue;
1039 }
1040
e77bd3fd
YW
1041 if (IN_SET(dns->port, 53, 853))
1042 dns->port = 0;
1043
1044 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 1045 if (!m)
53253824
SS
1046 return log_oom();
1047
e77bd3fd 1048 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 1049 n->dns = m;
53253824 1050 }
53253824
SS
1051}
1052
8a516214
LP
1053int config_parse_dnssec_negative_trust_anchors(
1054 const char *unit,
1055 const char *filename,
1056 unsigned line,
1057 const char *section,
1058 unsigned section_line,
1059 const char *lvalue,
1060 int ltype,
1061 const char *rvalue,
1062 void *data,
1063 void *userdata) {
1064
8a516214
LP
1065 Network *n = data;
1066 int r;
1067
3df9bec5 1068 assert(n);
8a516214
LP
1069 assert(lvalue);
1070 assert(rvalue);
1071
1072 if (isempty(rvalue)) {
1073 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1074 return 0;
1075 }
1076
d96edb2c 1077 for (const char *p = rvalue;;) {
8a516214
LP
1078 _cleanup_free_ char *w = NULL;
1079
1080 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1081 if (r == -ENOMEM)
1082 return log_oom();
8a516214 1083 if (r < 0) {
d96edb2c 1084 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1085 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1086 return 0;
8a516214
LP
1087 }
1088 if (r == 0)
d96edb2c 1089 return 0;
8a516214
LP
1090
1091 r = dns_name_is_valid(w);
1092 if (r <= 0) {
d96edb2c 1093 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1094 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1095 continue;
1096 }
1097
35e601d4 1098 r = set_ensure_consume(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1099 if (r < 0)
1100 return log_oom();
8a516214 1101 }
8a516214 1102}
b2a81c0b 1103
26575990
LP
1104int config_parse_ntp(
1105 const char *unit,
1106 const char *filename,
1107 unsigned line,
1108 const char *section,
1109 unsigned section_line,
1110 const char *lvalue,
1111 int ltype,
1112 const char *rvalue,
1113 void *data,
1114 void *userdata) {
1115
1116 char ***l = data;
1117 int r;
1118
1119 assert(l);
1120 assert(lvalue);
1121 assert(rvalue);
1122
1123 if (isempty(rvalue)) {
1124 *l = strv_free(*l);
1125 return 0;
1126 }
1127
d96edb2c 1128 for (const char *p = rvalue;;) {
26575990
LP
1129 _cleanup_free_ char *w = NULL;
1130
d96edb2c 1131 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1132 if (r == -ENOMEM)
1133 return log_oom();
1134 if (r < 0) {
d96edb2c 1135 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1136 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1137 return 0;
26575990
LP
1138 }
1139 if (r == 0)
d96edb2c 1140 return 0;
26575990
LP
1141
1142 r = dns_name_is_valid_or_address(w);
1143 if (r <= 0) {
d96edb2c 1144 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1145 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1146 continue;
af1c0de0
SS
1147 }
1148
c448459d
ZJS
1149 if (strv_length(*l) > MAX_NTP_SERVERS) {
1150 log_syntax(unit, LOG_WARNING, filename, line, 0,
1151 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1152 MAX_NTP_SERVERS, w);
d96edb2c 1153 return 0;
c448459d
ZJS
1154 }
1155
1156 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1157 if (r < 0)
1158 return log_oom();
af1c0de0 1159 }
af1c0de0
SS
1160}
1161
4ac77d63
YW
1162int config_parse_required_for_online(
1163 const char *unit,
1164 const char *filename,
1165 unsigned line,
1166 const char *section,
1167 unsigned section_line,
1168 const char *lvalue,
1169 int ltype,
1170 const char *rvalue,
1171 void *data,
1172 void *userdata) {
1173
1174 Network *network = data;
75cd4a5d 1175 LinkOperationalStateRange range;
4ac77d63
YW
1176 bool required = true;
1177 int r;
1178
1179 if (isempty(rvalue)) {
1180 network->required_for_online = true;
75cd4a5d 1181 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1182 return 0;
1183 }
1184
75cd4a5d
DDM
1185 r = parse_operational_state_range(rvalue, &range);
1186 if (r < 0) {
4ac77d63
YW
1187 r = parse_boolean(rvalue);
1188 if (r < 0) {
d96edb2c 1189 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1190 "Failed to parse %s= setting, ignoring assignment: %s",
1191 lvalue, rvalue);
1192 return 0;
1193 }
1194
1195 required = r;
75cd4a5d 1196 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1197 }
1198
1199 network->required_for_online = required;
75cd4a5d 1200 network->required_operstate_for_online = range;
4ac77d63
YW
1201
1202 return 0;
1203}
7da377ef
SS
1204
1205DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1206 "Failed to parse KeepConfiguration= setting");
1207
1208static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1209 [KEEP_CONFIGURATION_NO] = "no",
1210 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1211 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1212 [KEEP_CONFIGURATION_STATIC] = "static",
1213 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1214};
1215
1216DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9
YW
1217
1218static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1219 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1220 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1221 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1222 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1223};
1224
1225DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1226DEFINE_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
1227
1228static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1229 [ACTIVATION_POLICY_UP] = "up",
1230 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1231 [ACTIVATION_POLICY_MANUAL] = "manual",
1232 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1233 [ACTIVATION_POLICY_DOWN] = "down",
1234 [ACTIVATION_POLICY_BOUND] = "bound",
1235};
1236
1237DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1238DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");