]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: drop noisy log message
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f579559b 2
9aa5d8ba
YW
3#include <net/if.h>
4#include <netinet/in.h>
01234e1f 5#include <linux/netdevice.h>
69a93e7d 6
b5efdb8a 7#include "alloc-util.h"
f579559b
TG
8#include "conf-files.h"
9#include "conf-parser.h"
37de2509 10#include "dns-domain.h"
3ffd4af2 11#include "fd-util.h"
07630cea 12#include "hostname-util.h"
88295a05 13#include "in-addr-util.h"
fc2f9534 14#include "network-internal.h"
23f53b99 15#include "networkd-manager.h"
3ffd4af2 16#include "networkd-network.h"
6bedfcbb 17#include "parse-util.h"
8a516214 18#include "set.h"
cebe1257 19#include "socket-util.h"
8fcde012 20#include "stat-util.h"
8b43440b 21#include "string-table.h"
07630cea 22#include "string-util.h"
700f1186 23#include "strv.h"
07630cea 24#include "util.h"
f579559b 25
c448459d
ZJS
26/* Let's assume that anything above this number is a user misconfiguration. */
27#define MAX_NTP_SERVERS 128
28
add8d07d 29/* Set defaults following RFC7844 */
30void network_apply_anonymize_if_set(Network *network) {
31 if (!network->dhcp_anonymize)
32 return;
33 /* RFC7844 3.7
34 SHOULD NOT send the Host Name option */
35 network->dhcp_send_hostname = false;
36 /* RFC7844 section 3.:
37 MAY contain the Client Identifier option
38 Section 3.5:
39 clients MUST use client identifiers based solely
40 on the link-layer address */
41 /* NOTE: Using MAC, as it does not reveal extra information,
42 * and some servers might not answer if this option is not sent */
43 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
44 /* RFC 7844 3.10:
45 SHOULD NOT use the Vendor Class Identifier option */
727ba17f 46 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
add8d07d 47 /* RFC7844 section 3.6.:
48 The client intending to protect its privacy SHOULD only request a
49 minimal number of options in the PRL and SHOULD also randomly shuffle
50 the ordering of option codes in the PRL. If this random ordering
51 cannot be implemented, the client MAY order the option codes in the
52 PRL by option code number (lowest to highest).
53 */
54 /* NOTE: dhcp_use_mtu is false by default,
55 * though it was not initiallized to any value in network_load_one.
56 * Maybe there should be another var called *send*?
57 * (to use the MTU sent by the server but to do not send
58 * the option in the PRL). */
59 network->dhcp_use_mtu = false;
28522b0d 60 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
61 * but this is needed to use them. */
62 network->dhcp_use_routes = true;
add8d07d 63 /* RFC7844 section 3.6.
64 * same comments as previous option */
65 network->dhcp_use_timezone = false;
66}
67
cebe1257
YW
68static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
69 const char *kind_string;
70 NetDev *netdev;
71 int r;
72
96db6412
YW
73 /* For test-networkd-conf, the check must be earlier than the assertions. */
74 if (!name)
75 return 0;
76
cebe1257
YW
77 assert(network);
78 assert(network->manager);
79 assert(network->filename);
80 assert(ret_netdev);
81
cebe1257
YW
82 if (kind == _NETDEV_KIND_TUNNEL)
83 kind_string = "tunnel";
84 else {
85 kind_string = netdev_kind_to_string(kind);
86 if (!kind_string)
87 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
88 "%s: Invalid NetDev kind of %s, ignoring assignment.",
89 network->filename, name);
90 }
91
92 r = netdev_get(network->manager, name, &netdev);
93 if (r < 0)
94 return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
95 network->filename, name);
96
97 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
98 IN_SET(netdev->kind,
99 NETDEV_KIND_IPIP,
100 NETDEV_KIND_SIT,
101 NETDEV_KIND_GRE,
102 NETDEV_KIND_GRETAP,
103 NETDEV_KIND_IP6GRE,
104 NETDEV_KIND_IP6GRETAP,
105 NETDEV_KIND_VTI,
106 NETDEV_KIND_VTI6,
9282f75b
YW
107 NETDEV_KIND_IP6TNL,
108 NETDEV_KIND_ERSPAN)))
cebe1257
YW
109 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
110 "%s: NetDev %s is not a %s, ignoring assignment",
111 network->filename, name, kind_string);
112
113 *ret_netdev = netdev_ref(netdev);
114 return 1;
115}
116
117static int network_resolve_stacked_netdevs(Network *network) {
118 void *name, *kind;
119 Iterator i;
120 int r;
121
122 assert(network);
123
124 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
125 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
126
127 r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
128 if (r <= 0)
129 continue;
130
131 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
132 if (r < 0)
133 return log_oom();
134
135 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
136 if (r < 0)
137 return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
138 network->filename, (const char *) name);
139
140 netdev = NULL;
141 }
142
143 return 0;
144}
145
96db6412 146int network_verify(Network *network) {
4bec2f23
YW
147 Address *address, *address_next;
148 Route *route, *route_next;
fcbf4cb7
YW
149 FdbEntry *fdb, *fdb_next;
150 Neighbor *neighbor, *neighbor_next;
151 AddressLabel *label, *label_next;
152 Prefix *prefix, *prefix_next;
153 RoutingPolicyRule *rule, *rule_next;
0321cea7
YW
154
155 assert(network);
156 assert(network->filename);
157
84ea567e
YW
158 if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
159 strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
44005bfb
YW
160 strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
161 !network->conditions)
84ea567e
YW
162 log_warning("%s: No valid settings found in the [Match] section. "
163 "The file will match all interfaces. "
164 "If that is intended, please add Name=* in the [Match] section.",
165 network->filename);
166
cebe1257 167 /* skip out early if configuration does not match the environment */
c4f58dea 168 if (!condition_test_list(network->conditions, NULL, NULL, NULL))
cebe1257 169 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
170 "%s: Conditions in the file do not match the system environment, skipping.",
171 network->filename);
cebe1257
YW
172
173 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
174 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
175 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
176 (void) network_resolve_stacked_netdevs(network);
177
178 /* Free unnecessary entries. */
179 network->bond_name = mfree(network->bond_name);
180 network->bridge_name = mfree(network->bridge_name);
181 network->vrf_name = mfree(network->vrf_name);
182 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
183
0321cea7
YW
184 if (network->bond) {
185 /* Bonding slave does not support addressing. */
186 if (network->ipv6_accept_ra > 0) {
ab24039f
ZJS
187 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
188 network->filename);
0321cea7
YW
189 network->ipv6_accept_ra = 0;
190 }
191 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
192 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
193 network->filename);
0321cea7
YW
194 network->link_local = ADDRESS_FAMILY_NO;
195 }
196 if (network->dhcp != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
197 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
198 network->filename);
0321cea7
YW
199 network->dhcp = ADDRESS_FAMILY_NO;
200 }
201 if (network->dhcp_server) {
ab24039f
ZJS
202 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
203 network->filename);
0321cea7
YW
204 network->dhcp_server = false;
205 }
206 if (network->n_static_addresses > 0) {
ab24039f
ZJS
207 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
208 network->filename);
0321cea7
YW
209 while ((address = network->static_addresses))
210 address_free(address);
211 }
212 if (network->n_static_routes > 0) {
ab24039f
ZJS
213 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
214 network->filename);
0321cea7
YW
215 while ((route = network->static_routes))
216 route_free(route);
217 }
218 }
219
220 if (network->link_local < 0)
8f191801
YW
221 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
222
44013aa4
YW
223 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
224 if (network->ipv6_accept_ra > 0) {
225 log_warning("%s: IPv6AcceptRA= is enabled by the .network file but IPv6 link local addressing is disabled. "
226 "Disabling IPv6AcceptRA=.", network->filename);
227 network->ipv6_accept_ra = false;
228 }
229
230 if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
231 log_warning("%s: DHCPv6 client is enabled by the .network file but IPv6 link local addressing is disabled. "
232 "Disabling DHCPv6 client.", network->filename);
233 SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
234 }
235
236 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) {
237 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
238 "Disabling IPv6PrefixDelegation=.", network->filename);
239 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
240 }
241 }
242
29e81083
YW
243 if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
244 !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
245 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
246 "Disabling the fallback assignment.", network->filename);
247 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
248 }
249
8f191801
YW
250 if (network->ipv6_accept_ra < 0 && network->bridge)
251 network->ipv6_accept_ra = false;
0321cea7
YW
252
253 /* IPMasquerade=yes implies IPForward=yes */
254 if (network->ip_masquerade)
255 network->ip_forward |= ADDRESS_FAMILY_IPV4;
256
933c70a0 257 if (network->mtu > 0 && network->dhcp_use_mtu) {
0321cea7
YW
258 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
259 "Disabling UseMTU=.", network->filename);
260 network->dhcp_use_mtu = false;
261 }
262
7da377ef
SS
263 if (network->dhcp_critical >= 0) {
264 if (network->keep_configuration >= 0)
265 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
266 "Ignoring CriticalConnection=.", network->filename);
267 else if (network->dhcp_critical)
268 /* CriticalConnection=yes also preserve foreign static configurations. */
269 network->keep_configuration = KEEP_CONFIGURATION_YES;
270 else
95355a28
YW
271 /* For backward compatibility, we do not release DHCP addresses on manager stop. */
272 network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
7da377ef
SS
273 }
274
275 if (network->keep_configuration < 0)
95355a28
YW
276 /* For backward compatibility, we do not release DHCP addresses on manager stop. */
277 network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
7da377ef 278
4bec2f23 279 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
fcbf4cb7 280 if (address_section_verify(address) < 0)
4bec2f23 281 address_free(address);
4bec2f23 282
fcbf4cb7
YW
283 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
284 if (route_section_verify(route, network) < 0)
4bec2f23 285 route_free(route);
0321cea7 286
fcbf4cb7
YW
287 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
288 if (section_is_invalid(fdb->section))
289 fdb_entry_free(fdb);
290
291 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
044d4b40 292 if (neighbor_section_verify(neighbor) < 0)
fcbf4cb7
YW
293 neighbor_free(neighbor);
294
295 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
296 if (section_is_invalid(label->section))
297 address_label_free(label);
298
299 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
300 if (section_is_invalid(prefix->section))
301 prefix_free(prefix);
302
714a199e
YW
303 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_route_prefixes)
304 if (section_is_invalid(prefix->section))
305 prefix_free(prefix);
306
fcbf4cb7 307 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
0aabccc8 308 if (routing_policy_rule_section_verify(rule) < 0)
fcbf4cb7 309 routing_policy_rule_free(rule);
4912ab77 310
0321cea7
YW
311 return 0;
312}
313
212bd73c 314int network_load_one(Manager *manager, const char *filename) {
838b2f7a 315 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 316 _cleanup_(network_unrefp) Network *network = NULL;
f579559b 317 _cleanup_fclose_ FILE *file = NULL;
047a0dac 318 const char *dropin_dirname;
838b2f7a 319 char *d;
f579559b
TG
320 int r;
321
bf1bc670
TA
322 assert(manager);
323 assert(filename);
324
f579559b
TG
325 file = fopen(filename, "re");
326 if (!file) {
327 if (errno == ENOENT)
328 return 0;
1e7a0e21
LP
329
330 return -errno;
f579559b
TG
331 }
332
ed88bcfb
ZJS
333 if (null_or_empty_fd(fileno(file))) {
334 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
335 return 0;
336 }
337
838b2f7a
YW
338 fname = strdup(filename);
339 if (!fname)
340 return log_oom();
341
342 name = strdup(basename(filename));
343 if (!name)
344 return log_oom();
345
346 d = strrchr(name, '.');
347 if (!d)
348 return -EINVAL;
349
350 *d = '\0';
351
352 dropin_dirname = strjoina(name, ".network.d");
353
17f9c355 354 network = new(Network, 1);
f579559b
TG
355 if (!network)
356 return log_oom();
357
17f9c355 358 *network = (Network) {
838b2f7a
YW
359 .filename = TAKE_PTR(fname),
360 .name = TAKE_PTR(name),
17f9c355 361
715d398e 362 .manager = manager,
35ac3b76
YW
363 .n_ref = 1,
364
17f9c355 365 .required_for_online = true,
4ac77d63 366 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
17f9c355 367 .dhcp = ADDRESS_FAMILY_NO,
7da377ef 368 .dhcp_critical = -1,
17f9c355 369 .dhcp_use_ntp = true,
299d578f 370 .dhcp_use_sip = true,
17f9c355
YW
371 .dhcp_use_dns = true,
372 .dhcp_use_hostname = true,
373 .dhcp_use_routes = true,
5238e957 374 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
375 .dhcp_send_hostname = true,
376 /* To enable/disable RFC7844 Anonymity Profiles */
377 .dhcp_anonymize = false,
378 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 379 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
380 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
381 .dhcp_route_table = RT_TABLE_MAIN,
382 .dhcp_route_table_set = false,
383 /* NOTE: from man: UseMTU=... Defaults to false*/
384 .dhcp_use_mtu = false,
385 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
386 .dhcp_use_timezone = false,
387 .rapid_commit = true,
388
caa8ca42
SS
389 .dhcp6_use_ntp = true,
390 .dhcp6_use_dns = true,
391
17f9c355
YW
392 .dhcp_server_emit_dns = true,
393 .dhcp_server_emit_ntp = true,
299d578f 394 .dhcp_server_emit_sip = true,
17f9c355
YW
395 .dhcp_server_emit_router = true,
396 .dhcp_server_emit_timezone = true,
397
398 .router_emit_dns = true,
399 .router_emit_domains = true,
400
401 .use_bpdu = -1,
402 .hairpin = -1,
403 .fast_leave = -1,
404 .allow_port_to_be_root = -1,
405 .unicast_flood = -1,
7f15b714 406 .multicast_flood = -1,
d3aa8b49 407 .multicast_to_unicast = -1,
7f15b714
TJ
408 .neighbor_suppression = -1,
409 .learning = -1,
1087623b
SS
410 .bridge_proxy_arp = -1,
411 .bridge_proxy_arp_wifi = -1,
17f9c355 412 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 413 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
414
415 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
416
7ece6f58 417 .dns_default_route = -1,
17f9c355
YW
418 .llmnr = RESOLVE_SUPPORT_YES,
419 .mdns = RESOLVE_SUPPORT_NO,
420 .dnssec_mode = _DNSSEC_MODE_INVALID,
421 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
422
0321cea7 423 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 424 .link_local = _ADDRESS_FAMILY_INVALID,
17f9c355
YW
425
426 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
427 .ipv6_accept_ra = -1,
428 .ipv6_dad_transmits = -1,
429 .ipv6_hop_limit = -1,
430 .ipv6_proxy_ndp = -1,
431 .duid.type = _DUID_TYPE_INVALID,
432 .proxy_arp = -1,
433 .arp = -1,
434 .multicast = -1,
435 .allmulticast = -1,
436 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
437 .ipv6_accept_ra_use_autonomous_prefix = true,
438 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 439 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 440 .ipv6_accept_ra_route_table_set = false,
c423be28 441
7da377ef
SS
442 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
443
c423be28 444 .can_triple_sampling = -1,
17f9c355 445 };
f579559b 446
dc0d4078 447 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
448 "Match\0"
449 "Link\0"
450 "Network\0"
451 "Address\0"
e4a71bf3 452 "Neighbor\0"
95b74ef6 453 "IPv6AddressLabel\0"
bce67bbe 454 "RoutingPolicyRule\0"
23bb31aa
ZJS
455 "Route\0"
456 "DHCP\0"
457 "DHCPv4\0" /* compat */
caa8ca42 458 "DHCPv6\0"
23bb31aa
ZJS
459 "DHCPServer\0"
460 "IPv6AcceptRA\0"
a0e5c15d 461 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
462 "Bridge\0"
463 "BridgeFDB\0"
9d5d0090 464 "BridgeVLAN\0"
7d5cac19 465 "IPv6PrefixDelegation\0"
06828bb6 466 "IPv6Prefix\0"
203d4df5 467 "IPv6RoutePrefix\0"
06828bb6 468 "CAN\0",
23bb31aa 469 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 470 CONFIG_PARSE_WARN, network);
102bc043 471 if (r < 0)
f579559b 472 return r;
f579559b 473
add8d07d 474 network_apply_anonymize_if_set(network);
475
fa7cd711
YW
476 r = network_add_ipv4ll_route(network);
477 if (r < 0)
478 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
479
5d5003ab
YW
480 r = network_add_default_route_on_device(network);
481 if (r < 0)
482 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
483 network->filename);
484
715d398e 485 r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
dbffab87
TG
486 if (r < 0)
487 return r;
488
715d398e 489 r = ordered_hashmap_put(manager->networks, network->name, network);
dbffab87
TG
490 if (r < 0)
491 return r;
492
0321cea7
YW
493 if (network_verify(network) < 0)
494 return 0;
b3070dc0 495
f579559b 496 network = NULL;
f579559b
TG
497 return 0;
498}
499
500int network_load(Manager *manager) {
477e73b5
ZJS
501 _cleanup_strv_free_ char **files = NULL;
502 char **f;
f579559b
TG
503 int r;
504
505 assert(manager);
506
715d398e 507 ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
f579559b 508
dc0d4078 509 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
510 if (r < 0)
511 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 512
715d398e 513 STRV_FOREACH(f, files) {
f579559b
TG
514 r = network_load_one(manager, *f);
515 if (r < 0)
be711082 516 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
517 }
518
f579559b
TG
519 return 0;
520}
521
35ac3b76 522static Network *network_free(Network *network) {
a0e5c15d 523 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
524 RoutingPolicyRule *rule;
525 FdbEntry *fdb_entry;
e4a71bf3 526 Neighbor *neighbor;
95b74ef6 527 AddressLabel *label;
057abfd8 528 Prefix *prefix;
bce67bbe 529 Address *address;
bce67bbe 530 Route *route;
f579559b
TG
531
532 if (!network)
35ac3b76 533 return NULL;
f579559b
TG
534
535 free(network->filename);
536
e90d0374 537 set_free_free(network->match_mac);
5256e00e
TG
538 strv_free(network->match_path);
539 strv_free(network->match_driver);
540 strv_free(network->match_type);
541 strv_free(network->match_name);
44005bfb 542 strv_free(network->match_property);
c4f58dea 543 condition_free_list(network->conditions);
f579559b
TG
544
545 free(network->description);
edb85f0d 546 free(network->dhcp_vendor_class_identifier);
af1c0de0 547 strv_free(network->dhcp_user_class);
27cb34f5 548 free(network->dhcp_hostname);
727b5734 549 set_free(network->dhcp_black_listed_ip);
5bc945be 550 set_free(network->dhcp_request_options);
c106cc36
TG
551 free(network->mac);
552
b0e39c82 553 strv_free(network->ntp);
5512a963 554 free(network->dns);
299d578f 555 strv_free(network->sip);
5e2a51d5
ZJS
556 ordered_set_free_free(network->search_domains);
557 ordered_set_free_free(network->route_domains);
0d4ad91d 558 strv_free(network->bind_carrier);
cdd7812b 559
5e2a51d5 560 ordered_set_free_free(network->router_search_domains);
cdd7812b 561 free(network->router_dns);
e520ce64 562 set_free_free(network->ndisc_black_listed_prefix);
3bef724f 563
cebe1257
YW
564 free(network->bridge_name);
565 free(network->bond_name);
566 free(network->vrf_name);
567 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 568 netdev_unref(network->bridge);
47e2dc31 569 netdev_unref(network->bond);
6cb955c6 570 netdev_unref(network->vrf);
fa6f1e54 571 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 572
f048a16b 573 while ((route = network->static_routes))
f579559b
TG
574 route_free(route);
575
f048a16b 576 while ((address = network->static_addresses))
f579559b
TG
577 address_free(address);
578
b98b483b
AR
579 while ((fdb_entry = network->static_fdb_entries))
580 fdb_entry_free(fdb_entry);
581
a0e5c15d
FK
582 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
583 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
584
e4a71bf3
WKI
585 while ((neighbor = network->neighbors))
586 neighbor_free(neighbor);
587
95b74ef6
SS
588 while ((label = network->address_labels))
589 address_label_free(label);
590
057abfd8
PF
591 while ((prefix = network->static_prefixes))
592 prefix_free(prefix);
593
bce67bbe
SS
594 while ((rule = network->rules))
595 routing_policy_rule_free(rule);
596
6ae115c1
TG
597 hashmap_free(network->addresses_by_section);
598 hashmap_free(network->routes_by_section);
b98b483b 599 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 600 hashmap_free(network->neighbors_by_section);
95b74ef6 601 hashmap_free(network->address_labels_by_section);
057abfd8 602 hashmap_free(network->prefixes_by_section);
bce67bbe 603 hashmap_free(network->rules_by_section);
6ae115c1 604
dbffab87 605 if (network->manager) {
715d398e
YW
606 if (network->manager->networks && network->name)
607 ordered_hashmap_remove(network->manager->networks, network->name);
27dfc982
YW
608
609 if (network->manager->duids_requesting_uuid)
610 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
611 }
612
613 free(network->name);
f579559b 614
8eb9058d 615 free(network->dhcp_server_timezone);
1a04db0f
LP
616 free(network->dhcp_server_dns);
617 free(network->dhcp_server_ntp);
299d578f 618 free(network->dhcp_server_sip);
8eb9058d 619
8a516214
LP
620 set_free_free(network->dnssec_negative_trust_anchors);
621
35ac3b76 622 return mfree(network);
f579559b
TG
623}
624
35ac3b76
YW
625DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
626
dbffab87
TG
627int network_get_by_name(Manager *manager, const char *name, Network **ret) {
628 Network *network;
629
630 assert(manager);
631 assert(name);
632 assert(ret);
633
715d398e 634 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
635 if (!network)
636 return -ENOENT;
637
638 *ret = network;
639
640 return 0;
641}
642
51517f9e 643int network_get(Manager *manager, sd_device *device,
505f8da7
TG
644 const char *ifname, const struct ether_addr *address,
645 Network **ret) {
51517f9e 646 Network *network;
715d398e 647 Iterator i;
f579559b
TG
648
649 assert(manager);
f579559b 650 assert(ret);
af3aa302 651
715d398e 652 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
44005bfb
YW
653 if (net_match_config(network->match_mac, network->match_path, network->match_driver,
654 network->match_type, network->match_name, network->match_property,
b38de0e9 655 device, address, ifname)) {
24c083df 656 if (network->match_name && device) {
ca6038b8
TG
657 const char *attr;
658 uint8_t name_assign_type = NET_NAME_UNKNOWN;
659
51517f9e 660 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 661 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
662
663 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
664 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
665 ifname, network->filename);
32bc8adc 666 else
a2fae7bb 667 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 668 } else
a2fae7bb 669 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 670
f579559b
TG
671 *ret = network;
672 return 0;
673 }
f579559b
TG
674
675 *ret = NULL;
676
677 return -ENOENT;
678}
679
7d342c03 680int network_apply(Network *network, Link *link) {
c4a03a56
TG
681 assert(network);
682 assert(link);
683
c9c908a6 684 link->network = network_ref(network);
f579559b 685
5512a963 686 if (network->n_dns > 0 ||
3df9bec5 687 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
688 !ordered_set_isempty(network->search_domains) ||
689 !ordered_set_isempty(network->route_domains))
84de38c5 690 link_dirty(link);
3bef724f 691
f579559b
TG
692 return 0;
693}
02b59d57 694
adfeee49 695bool network_has_static_ipv6_configurations(Network *network) {
439689c6 696 Address *address;
adfeee49
YW
697 Route *route;
698 FdbEntry *fdb;
699 Neighbor *neighbor;
439689c6
SS
700
701 assert(network);
702
adfeee49 703 LIST_FOREACH(addresses, address, network->static_addresses)
439689c6
SS
704 if (address->family == AF_INET6)
705 return true;
adfeee49
YW
706
707 LIST_FOREACH(routes, route, network->static_routes)
708 if (route->family == AF_INET6)
709 return true;
710
711 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
712 if (fdb->family == AF_INET6)
713 return true;
714
715 LIST_FOREACH(neighbors, neighbor, network->neighbors)
716 if (neighbor->family == AF_INET6)
717 return true;
718
719 if (!LIST_IS_EMPTY(network->address_labels))
720 return true;
721
722 if (!LIST_IS_EMPTY(network->static_prefixes))
723 return true;
439689c6
SS
724
725 return false;
726}
727
cebe1257 728int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
729 const char *filename,
730 unsigned line,
731 const char *section,
732 unsigned section_line,
733 const char *lvalue,
734 int ltype,
735 const char *rvalue,
736 void *data,
737 void *userdata) {
95dba435
YW
738 _cleanup_free_ char *name = NULL;
739 NetDevKind kind = ltype;
cebe1257 740 Hashmap **h = data;
02b59d57
TG
741 int r;
742
743 assert(filename);
744 assert(lvalue);
745 assert(rvalue);
746 assert(data);
95dba435
YW
747 assert(IN_SET(kind,
748 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 749 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 750 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
751 NETDEV_KIND_XFRM));
54abf461 752
cebe1257 753 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
754 log_syntax(unit, LOG_ERR, filename, line, 0,
755 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
756 return 0;
757 }
758
cebe1257
YW
759 name = strdup(rvalue);
760 if (!name)
761 return log_oom();
3e570042 762
cebe1257
YW
763 r = hashmap_ensure_allocated(h, &string_hash_ops);
764 if (r < 0)
765 return log_oom();
326cb406 766
cebe1257 767 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 768 if (r < 0)
3772cfde 769 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
770 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
771 else if (r == 0)
772 log_syntax(unit, LOG_DEBUG, filename, line, r,
773 "NetDev '%s' specified twice, ignoring.", name);
774 else
775 name = NULL;
47e2dc31 776
fe6b2d55
TG
777 return 0;
778}
7951dea2 779
3df9bec5
LP
780int config_parse_domains(
781 const char *unit,
782 const char *filename,
783 unsigned line,
784 const char *section,
785 unsigned section_line,
786 const char *lvalue,
787 int ltype,
788 const char *rvalue,
789 void *data,
790 void *userdata) {
791
792 const char *p;
793 Network *n = data;
6192b846
TG
794 int r;
795
3df9bec5
LP
796 assert(n);
797 assert(lvalue);
798 assert(rvalue);
6192b846 799
3df9bec5 800 if (isempty(rvalue)) {
5e2a51d5
ZJS
801 n->search_domains = ordered_set_free_free(n->search_domains);
802 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
803 return 0;
804 }
67272d15 805
3df9bec5
LP
806 p = rvalue;
807 for (;;) {
808 _cleanup_free_ char *w = NULL, *normalized = NULL;
809 const char *domain;
810 bool is_route;
811
812 r = extract_first_word(&p, &w, NULL, 0);
813 if (r < 0) {
ab24039f
ZJS
814 log_syntax(unit, LOG_ERR, filename, line, r,
815 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
816 break;
817 }
818 if (r == 0)
819 break;
820
821 is_route = w[0] == '~';
822 domain = is_route ? w + 1 : w;
823
824 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
825 /* If the root domain appears as is, or the special token "*" is found, we'll
826 * consider this as routing domain, unconditionally. */
3df9bec5 827 is_route = true;
ab24039f
ZJS
828 domain = "."; /* make sure we don't allow empty strings, thus write the root
829 * domain as "." */
3df9bec5 830 } else {
7470cc4c 831 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 832 if (r < 0) {
ab24039f
ZJS
833 log_syntax(unit, LOG_ERR, filename, line, r,
834 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
835 continue;
836 }
837
838 domain = normalized;
839
840 if (is_localhost(domain)) {
ab24039f
ZJS
841 log_syntax(unit, LOG_ERR, filename, line, 0,
842 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
843 domain);
37de2509 844 continue;
3df9bec5 845 }
37de2509 846 }
40274ed6 847
5e2a51d5
ZJS
848 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
849 r = ordered_set_ensure_allocated(set, &string_hash_ops);
850 if (r < 0)
851 return r;
852
853 r = ordered_set_put_strdup(*set, domain);
09451975
LP
854 if (r < 0)
855 return log_oom();
40274ed6 856 }
f15b6e5a 857
6192b846
TG
858 return 0;
859}
860
60c35566 861int config_parse_ipv6token(
7f77697a
TG
862 const char* unit,
863 const char *filename,
864 unsigned line,
865 const char *section,
866 unsigned section_line,
867 const char *lvalue,
868 int ltype,
869 const char *rvalue,
870 void *data,
871 void *userdata) {
872
873 union in_addr_union buffer;
874 struct in6_addr *token = data;
875 int r;
876
877 assert(filename);
878 assert(lvalue);
879 assert(rvalue);
880 assert(token);
881
882 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
883 if (r < 0) {
ab24039f
ZJS
884 log_syntax(unit, LOG_ERR, filename, line, r,
885 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
886 return 0;
887 }
888
c606db69 889 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
890 log_syntax(unit, LOG_ERR, filename, line, 0,
891 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
892 return 0;
893 }
894
895 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
896 log_syntax(unit, LOG_ERR, filename, line, 0,
897 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
898 return 0;
899 }
900
901 *token = buffer.in6;
902
903 return 0;
904}
8add5f79 905
49092e22 906static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
907 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
908 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
909 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
910};
911
b146ad71
YW
912DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
913 IPV6_PRIVACY_EXTENSIONS_YES);
49092e22
SS
914
915int config_parse_ipv6_privacy_extensions(
916 const char* unit,
917 const char *filename,
918 unsigned line,
919 const char *section,
920 unsigned section_line,
921 const char *lvalue,
922 int ltype,
923 const char *rvalue,
924 void *data,
925 void *userdata) {
926
b146ad71 927 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
49092e22
SS
928
929 assert(filename);
930 assert(lvalue);
931 assert(rvalue);
932 assert(ipv6_privacy_extensions);
933
b146ad71
YW
934 s = ipv6_privacy_extensions_from_string(rvalue);
935 if (s < 0) {
936 if (streq(rvalue, "kernel"))
937 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
938 else {
939 log_syntax(unit, LOG_ERR, filename, line, 0,
940 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
941 return 0;
49092e22 942 }
49092e22
SS
943 }
944
b146ad71
YW
945 *ipv6_privacy_extensions = s;
946
49092e22
SS
947 return 0;
948}
a7d0ef44 949
1ac608c9
LP
950int config_parse_hostname(
951 const char *unit,
952 const char *filename,
953 unsigned line,
954 const char *section,
955 unsigned section_line,
956 const char *lvalue,
957 int ltype,
958 const char *rvalue,
959 void *data,
960 void *userdata) {
961
6528693a
YW
962 _cleanup_free_ char *hn = NULL;
963 char **hostname = data;
a7d0ef44
SS
964 int r;
965
966 assert(filename);
967 assert(lvalue);
968 assert(rvalue);
969
1ac608c9 970 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
971 if (r < 0)
972 return r;
973
1ac608c9 974 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
975 log_syntax(unit, LOG_ERR, filename, line, 0,
976 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
977 return 0;
978 }
979
6528693a
YW
980 r = dns_name_is_valid(hn);
981 if (r < 0) {
ab24039f
ZJS
982 log_syntax(unit, LOG_ERR, filename, line, r,
983 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
984 return 0;
985 }
986 if (r == 0) {
ab24039f
ZJS
987 log_syntax(unit, LOG_ERR, filename, line, 0,
988 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
989 return 0;
990 }
991
992 return free_and_replace(*hostname, hn);
a7d0ef44 993}
8eb9058d
LP
994
995int config_parse_timezone(
996 const char *unit,
997 const char *filename,
998 unsigned line,
999 const char *section,
1000 unsigned section_line,
1001 const char *lvalue,
1002 int ltype,
1003 const char *rvalue,
1004 void *data,
1005 void *userdata) {
1006
19f9e4e2
YW
1007 _cleanup_free_ char *tz = NULL;
1008 char **datap = data;
8eb9058d
LP
1009 int r;
1010
1011 assert(filename);
1012 assert(lvalue);
1013 assert(rvalue);
1014
1015 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1016 if (r < 0)
1017 return r;
1018
089fb865 1019 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1020 log_syntax(unit, LOG_ERR, filename, line, 0,
1021 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1022 return 0;
1023 }
1024
19f9e4e2 1025 return free_and_replace(*datap, tz);
8eb9058d 1026}
1a04db0f 1027
53253824
SS
1028int config_parse_dns(
1029 const char *unit,
1030 const char *filename,
1031 unsigned line,
1032 const char *section,
1033 unsigned section_line,
1034 const char *lvalue,
1035 int ltype,
1036 const char *rvalue,
1037 void *data,
1038 void *userdata) {
1039
1040 Network *n = userdata;
1041 int r;
1042
1043 assert(filename);
1044 assert(lvalue);
1045 assert(rvalue);
1046
1047 for (;;) {
1048 _cleanup_free_ char *w = NULL;
1049 union in_addr_union a;
5512a963 1050 struct in_addr_data *m;
53253824
SS
1051 int family;
1052
5512a963 1053 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1054 if (r == -ENOMEM)
1055 return log_oom();
1056 if (r < 0) {
ab24039f
ZJS
1057 log_syntax(unit, LOG_ERR, filename, line, r,
1058 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1059 break;
1060 }
5512a963
LP
1061 if (r == 0)
1062 break;
53253824
SS
1063
1064 r = in_addr_from_string_auto(w, &family, &a);
1065 if (r < 0) {
ab24039f
ZJS
1066 log_syntax(unit, LOG_ERR, filename, line, r,
1067 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1068 continue;
1069 }
1070
62d74c78 1071 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1072 if (!m)
53253824
SS
1073 return log_oom();
1074
5512a963
LP
1075 m[n->n_dns++] = (struct in_addr_data) {
1076 .family = family,
1077 .address = a,
1078 };
1079
1080 n->dns = m;
53253824
SS
1081 }
1082
1083 return 0;
1084}
1085
8a516214
LP
1086int config_parse_dnssec_negative_trust_anchors(
1087 const char *unit,
1088 const char *filename,
1089 unsigned line,
1090 const char *section,
1091 unsigned section_line,
1092 const char *lvalue,
1093 int ltype,
1094 const char *rvalue,
1095 void *data,
1096 void *userdata) {
1097
1098 const char *p = rvalue;
1099 Network *n = data;
1100 int r;
1101
3df9bec5 1102 assert(n);
8a516214
LP
1103 assert(lvalue);
1104 assert(rvalue);
1105
1106 if (isempty(rvalue)) {
1107 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1108 return 0;
1109 }
1110
1111 for (;;) {
1112 _cleanup_free_ char *w = NULL;
1113
1114 r = extract_first_word(&p, &w, NULL, 0);
1115 if (r < 0) {
ab24039f
ZJS
1116 log_syntax(unit, LOG_ERR, filename, line, r,
1117 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1118 break;
1119 }
1120 if (r == 0)
1121 break;
1122
1123 r = dns_name_is_valid(w);
1124 if (r <= 0) {
ab24039f
ZJS
1125 log_syntax(unit, LOG_ERR, filename, line, r,
1126 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1127 continue;
1128 }
1129
cbbf38ae
LP
1130 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1131 if (r < 0)
1132 return log_oom();
1133
8a516214
LP
1134 r = set_put(n->dnssec_negative_trust_anchors, w);
1135 if (r < 0)
1136 return log_oom();
1137 if (r > 0)
1138 w = NULL;
1139 }
1140
1141 return 0;
1142}
b2a81c0b 1143
26575990
LP
1144int config_parse_ntp(
1145 const char *unit,
1146 const char *filename,
1147 unsigned line,
1148 const char *section,
1149 unsigned section_line,
1150 const char *lvalue,
1151 int ltype,
1152 const char *rvalue,
1153 void *data,
1154 void *userdata) {
1155
1156 char ***l = data;
1157 int r;
1158
1159 assert(l);
1160 assert(lvalue);
1161 assert(rvalue);
1162
1163 if (isempty(rvalue)) {
1164 *l = strv_free(*l);
1165 return 0;
1166 }
1167
1168 for (;;) {
1169 _cleanup_free_ char *w = NULL;
1170
1171 r = extract_first_word(&rvalue, &w, NULL, 0);
1172 if (r == -ENOMEM)
1173 return log_oom();
1174 if (r < 0) {
ab24039f
ZJS
1175 log_syntax(unit, LOG_ERR, filename, line, r,
1176 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1177 break;
1178 }
1179 if (r == 0)
1180 break;
1181
1182 r = dns_name_is_valid_or_address(w);
1183 if (r <= 0) {
ab24039f
ZJS
1184 log_syntax(unit, LOG_ERR, filename, line, r,
1185 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1186 continue;
af1c0de0
SS
1187 }
1188
c448459d
ZJS
1189 if (strv_length(*l) > MAX_NTP_SERVERS) {
1190 log_syntax(unit, LOG_WARNING, filename, line, 0,
1191 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1192 MAX_NTP_SERVERS, w);
1193 break;
1194 }
1195
1196 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1197 if (r < 0)
1198 return log_oom();
af1c0de0
SS
1199 }
1200
1201 return 0;
1202}
1203
4ac77d63
YW
1204int config_parse_required_for_online(
1205 const char *unit,
1206 const char *filename,
1207 unsigned line,
1208 const char *section,
1209 unsigned section_line,
1210 const char *lvalue,
1211 int ltype,
1212 const char *rvalue,
1213 void *data,
1214 void *userdata) {
1215
1216 Network *network = data;
1217 LinkOperationalState s;
1218 bool required = true;
1219 int r;
1220
1221 if (isempty(rvalue)) {
1222 network->required_for_online = true;
1223 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1224 return 0;
1225 }
1226
1227 s = link_operstate_from_string(rvalue);
1228 if (s < 0) {
1229 r = parse_boolean(rvalue);
1230 if (r < 0) {
1231 log_syntax(unit, LOG_ERR, filename, line, r,
1232 "Failed to parse %s= setting, ignoring assignment: %s",
1233 lvalue, rvalue);
1234 return 0;
1235 }
1236
1237 required = r;
1238 s = LINK_OPERSTATE_DEGRADED;
1239 }
1240
1241 network->required_for_online = required;
1242 network->required_operstate_for_online = s;
1243
1244 return 0;
1245}
7da377ef
SS
1246
1247DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1248 "Failed to parse KeepConfiguration= setting");
1249
1250static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1251 [KEEP_CONFIGURATION_NO] = "no",
1252 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1253 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1254 [KEEP_CONFIGURATION_STATIC] = "static",
1255 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1256};
1257
1258DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);