]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: use SIGUSR2 to do a restart
[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,
afe42aef 445 .ip_service_type = -1,
17f9c355 446 };
f579559b 447
dc0d4078 448 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
449 "Match\0"
450 "Link\0"
451 "Network\0"
452 "Address\0"
e4a71bf3 453 "Neighbor\0"
95b74ef6 454 "IPv6AddressLabel\0"
bce67bbe 455 "RoutingPolicyRule\0"
23bb31aa
ZJS
456 "Route\0"
457 "DHCP\0"
458 "DHCPv4\0" /* compat */
caa8ca42 459 "DHCPv6\0"
23bb31aa
ZJS
460 "DHCPServer\0"
461 "IPv6AcceptRA\0"
a0e5c15d 462 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
463 "Bridge\0"
464 "BridgeFDB\0"
9d5d0090 465 "BridgeVLAN\0"
7d5cac19 466 "IPv6PrefixDelegation\0"
06828bb6 467 "IPv6Prefix\0"
203d4df5 468 "IPv6RoutePrefix\0"
06828bb6 469 "CAN\0",
23bb31aa 470 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 471 CONFIG_PARSE_WARN, network);
102bc043 472 if (r < 0)
f579559b 473 return r;
f579559b 474
add8d07d 475 network_apply_anonymize_if_set(network);
476
fa7cd711
YW
477 r = network_add_ipv4ll_route(network);
478 if (r < 0)
479 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
480
5d5003ab
YW
481 r = network_add_default_route_on_device(network);
482 if (r < 0)
483 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
484 network->filename);
485
715d398e 486 r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
dbffab87
TG
487 if (r < 0)
488 return r;
489
715d398e 490 r = ordered_hashmap_put(manager->networks, network->name, network);
dbffab87
TG
491 if (r < 0)
492 return r;
493
0321cea7
YW
494 if (network_verify(network) < 0)
495 return 0;
b3070dc0 496
f579559b 497 network = NULL;
f579559b
TG
498 return 0;
499}
500
501int network_load(Manager *manager) {
477e73b5
ZJS
502 _cleanup_strv_free_ char **files = NULL;
503 char **f;
f579559b
TG
504 int r;
505
506 assert(manager);
507
715d398e 508 ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
f579559b 509
dc0d4078 510 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
511 if (r < 0)
512 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 513
715d398e 514 STRV_FOREACH(f, files) {
f579559b
TG
515 r = network_load_one(manager, *f);
516 if (r < 0)
be711082 517 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
518 }
519
f579559b
TG
520 return 0;
521}
522
35ac3b76 523static Network *network_free(Network *network) {
a0e5c15d 524 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
525 RoutingPolicyRule *rule;
526 FdbEntry *fdb_entry;
e4a71bf3 527 Neighbor *neighbor;
95b74ef6 528 AddressLabel *label;
057abfd8 529 Prefix *prefix;
bce67bbe 530 Address *address;
bce67bbe 531 Route *route;
f579559b
TG
532
533 if (!network)
35ac3b76 534 return NULL;
f579559b
TG
535
536 free(network->filename);
537
e90d0374 538 set_free_free(network->match_mac);
5256e00e
TG
539 strv_free(network->match_path);
540 strv_free(network->match_driver);
541 strv_free(network->match_type);
542 strv_free(network->match_name);
44005bfb 543 strv_free(network->match_property);
c4f58dea 544 condition_free_list(network->conditions);
f579559b
TG
545
546 free(network->description);
edb85f0d 547 free(network->dhcp_vendor_class_identifier);
af1c0de0 548 strv_free(network->dhcp_user_class);
27cb34f5 549 free(network->dhcp_hostname);
727b5734 550 set_free(network->dhcp_black_listed_ip);
5bc945be 551 set_free(network->dhcp_request_options);
c106cc36
TG
552 free(network->mac);
553
b0e39c82 554 strv_free(network->ntp);
5512a963 555 free(network->dns);
299d578f 556 strv_free(network->sip);
5e2a51d5
ZJS
557 ordered_set_free_free(network->search_domains);
558 ordered_set_free_free(network->route_domains);
0d4ad91d 559 strv_free(network->bind_carrier);
cdd7812b 560
5e2a51d5 561 ordered_set_free_free(network->router_search_domains);
cdd7812b 562 free(network->router_dns);
e520ce64 563 set_free_free(network->ndisc_black_listed_prefix);
3bef724f 564
cebe1257
YW
565 free(network->bridge_name);
566 free(network->bond_name);
567 free(network->vrf_name);
568 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 569 netdev_unref(network->bridge);
47e2dc31 570 netdev_unref(network->bond);
6cb955c6 571 netdev_unref(network->vrf);
fa6f1e54 572 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 573
f048a16b 574 while ((route = network->static_routes))
f579559b
TG
575 route_free(route);
576
f048a16b 577 while ((address = network->static_addresses))
f579559b
TG
578 address_free(address);
579
b98b483b
AR
580 while ((fdb_entry = network->static_fdb_entries))
581 fdb_entry_free(fdb_entry);
582
a0e5c15d
FK
583 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
584 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
585
e4a71bf3
WKI
586 while ((neighbor = network->neighbors))
587 neighbor_free(neighbor);
588
95b74ef6
SS
589 while ((label = network->address_labels))
590 address_label_free(label);
591
057abfd8
PF
592 while ((prefix = network->static_prefixes))
593 prefix_free(prefix);
594
bce67bbe
SS
595 while ((rule = network->rules))
596 routing_policy_rule_free(rule);
597
6ae115c1
TG
598 hashmap_free(network->addresses_by_section);
599 hashmap_free(network->routes_by_section);
b98b483b 600 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 601 hashmap_free(network->neighbors_by_section);
95b74ef6 602 hashmap_free(network->address_labels_by_section);
057abfd8 603 hashmap_free(network->prefixes_by_section);
bce67bbe 604 hashmap_free(network->rules_by_section);
6ae115c1 605
dbffab87 606 if (network->manager) {
715d398e
YW
607 if (network->manager->networks && network->name)
608 ordered_hashmap_remove(network->manager->networks, network->name);
27dfc982
YW
609
610 if (network->manager->duids_requesting_uuid)
611 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
612 }
613
614 free(network->name);
f579559b 615
8eb9058d 616 free(network->dhcp_server_timezone);
1a04db0f
LP
617 free(network->dhcp_server_dns);
618 free(network->dhcp_server_ntp);
299d578f 619 free(network->dhcp_server_sip);
8eb9058d 620
8a516214
LP
621 set_free_free(network->dnssec_negative_trust_anchors);
622
35ac3b76 623 return mfree(network);
f579559b
TG
624}
625
35ac3b76
YW
626DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
627
dbffab87
TG
628int network_get_by_name(Manager *manager, const char *name, Network **ret) {
629 Network *network;
630
631 assert(manager);
632 assert(name);
633 assert(ret);
634
715d398e 635 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
636 if (!network)
637 return -ENOENT;
638
639 *ret = network;
640
641 return 0;
642}
643
51517f9e 644int network_get(Manager *manager, sd_device *device,
505f8da7
TG
645 const char *ifname, const struct ether_addr *address,
646 Network **ret) {
51517f9e 647 Network *network;
715d398e 648 Iterator i;
f579559b
TG
649
650 assert(manager);
f579559b 651 assert(ret);
af3aa302 652
715d398e 653 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
44005bfb
YW
654 if (net_match_config(network->match_mac, network->match_path, network->match_driver,
655 network->match_type, network->match_name, network->match_property,
b38de0e9 656 device, address, ifname)) {
24c083df 657 if (network->match_name && device) {
ca6038b8
TG
658 const char *attr;
659 uint8_t name_assign_type = NET_NAME_UNKNOWN;
660
51517f9e 661 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 662 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
663
664 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
665 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
666 ifname, network->filename);
32bc8adc 667 else
a2fae7bb 668 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 669 } else
a2fae7bb 670 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 671
f579559b
TG
672 *ret = network;
673 return 0;
674 }
f579559b
TG
675
676 *ret = NULL;
677
678 return -ENOENT;
679}
680
7d342c03 681int network_apply(Network *network, Link *link) {
c4a03a56
TG
682 assert(network);
683 assert(link);
684
c9c908a6 685 link->network = network_ref(network);
f579559b 686
5512a963 687 if (network->n_dns > 0 ||
3df9bec5 688 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
689 !ordered_set_isempty(network->search_domains) ||
690 !ordered_set_isempty(network->route_domains))
84de38c5 691 link_dirty(link);
3bef724f 692
f579559b
TG
693 return 0;
694}
02b59d57 695
adfeee49 696bool network_has_static_ipv6_configurations(Network *network) {
439689c6 697 Address *address;
adfeee49
YW
698 Route *route;
699 FdbEntry *fdb;
700 Neighbor *neighbor;
439689c6
SS
701
702 assert(network);
703
adfeee49 704 LIST_FOREACH(addresses, address, network->static_addresses)
439689c6
SS
705 if (address->family == AF_INET6)
706 return true;
adfeee49
YW
707
708 LIST_FOREACH(routes, route, network->static_routes)
709 if (route->family == AF_INET6)
710 return true;
711
712 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
713 if (fdb->family == AF_INET6)
714 return true;
715
716 LIST_FOREACH(neighbors, neighbor, network->neighbors)
717 if (neighbor->family == AF_INET6)
718 return true;
719
720 if (!LIST_IS_EMPTY(network->address_labels))
721 return true;
722
723 if (!LIST_IS_EMPTY(network->static_prefixes))
724 return true;
439689c6
SS
725
726 return false;
727}
728
cebe1257 729int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
730 const char *filename,
731 unsigned line,
732 const char *section,
733 unsigned section_line,
734 const char *lvalue,
735 int ltype,
736 const char *rvalue,
737 void *data,
738 void *userdata) {
95dba435
YW
739 _cleanup_free_ char *name = NULL;
740 NetDevKind kind = ltype;
cebe1257 741 Hashmap **h = data;
02b59d57
TG
742 int r;
743
744 assert(filename);
745 assert(lvalue);
746 assert(rvalue);
747 assert(data);
95dba435
YW
748 assert(IN_SET(kind,
749 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 750 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 751 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
752 NETDEV_KIND_XFRM));
54abf461 753
cebe1257 754 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
755 log_syntax(unit, LOG_ERR, filename, line, 0,
756 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
757 return 0;
758 }
759
cebe1257
YW
760 name = strdup(rvalue);
761 if (!name)
762 return log_oom();
3e570042 763
cebe1257
YW
764 r = hashmap_ensure_allocated(h, &string_hash_ops);
765 if (r < 0)
766 return log_oom();
326cb406 767
cebe1257 768 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 769 if (r < 0)
3772cfde 770 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
771 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
772 else if (r == 0)
773 log_syntax(unit, LOG_DEBUG, filename, line, r,
774 "NetDev '%s' specified twice, ignoring.", name);
775 else
776 name = NULL;
47e2dc31 777
fe6b2d55
TG
778 return 0;
779}
7951dea2 780
3df9bec5
LP
781int config_parse_domains(
782 const char *unit,
783 const char *filename,
784 unsigned line,
785 const char *section,
786 unsigned section_line,
787 const char *lvalue,
788 int ltype,
789 const char *rvalue,
790 void *data,
791 void *userdata) {
792
793 const char *p;
794 Network *n = data;
6192b846
TG
795 int r;
796
3df9bec5
LP
797 assert(n);
798 assert(lvalue);
799 assert(rvalue);
6192b846 800
3df9bec5 801 if (isempty(rvalue)) {
5e2a51d5
ZJS
802 n->search_domains = ordered_set_free_free(n->search_domains);
803 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
804 return 0;
805 }
67272d15 806
3df9bec5
LP
807 p = rvalue;
808 for (;;) {
809 _cleanup_free_ char *w = NULL, *normalized = NULL;
810 const char *domain;
811 bool is_route;
812
813 r = extract_first_word(&p, &w, NULL, 0);
814 if (r < 0) {
ab24039f
ZJS
815 log_syntax(unit, LOG_ERR, filename, line, r,
816 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
817 break;
818 }
819 if (r == 0)
820 break;
821
822 is_route = w[0] == '~';
823 domain = is_route ? w + 1 : w;
824
825 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
826 /* If the root domain appears as is, or the special token "*" is found, we'll
827 * consider this as routing domain, unconditionally. */
3df9bec5 828 is_route = true;
ab24039f
ZJS
829 domain = "."; /* make sure we don't allow empty strings, thus write the root
830 * domain as "." */
3df9bec5 831 } else {
7470cc4c 832 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 833 if (r < 0) {
ab24039f
ZJS
834 log_syntax(unit, LOG_ERR, filename, line, r,
835 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
836 continue;
837 }
838
839 domain = normalized;
840
841 if (is_localhost(domain)) {
ab24039f
ZJS
842 log_syntax(unit, LOG_ERR, filename, line, 0,
843 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
844 domain);
37de2509 845 continue;
3df9bec5 846 }
37de2509 847 }
40274ed6 848
5e2a51d5
ZJS
849 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
850 r = ordered_set_ensure_allocated(set, &string_hash_ops);
851 if (r < 0)
852 return r;
853
854 r = ordered_set_put_strdup(*set, domain);
09451975
LP
855 if (r < 0)
856 return log_oom();
40274ed6 857 }
f15b6e5a 858
6192b846
TG
859 return 0;
860}
861
60c35566 862int config_parse_ipv6token(
7f77697a
TG
863 const char* unit,
864 const char *filename,
865 unsigned line,
866 const char *section,
867 unsigned section_line,
868 const char *lvalue,
869 int ltype,
870 const char *rvalue,
871 void *data,
872 void *userdata) {
873
874 union in_addr_union buffer;
875 struct in6_addr *token = data;
876 int r;
877
878 assert(filename);
879 assert(lvalue);
880 assert(rvalue);
881 assert(token);
882
883 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
884 if (r < 0) {
ab24039f
ZJS
885 log_syntax(unit, LOG_ERR, filename, line, r,
886 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
887 return 0;
888 }
889
c606db69 890 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
891 log_syntax(unit, LOG_ERR, filename, line, 0,
892 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
893 return 0;
894 }
895
896 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
897 log_syntax(unit, LOG_ERR, filename, line, 0,
898 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
899 return 0;
900 }
901
902 *token = buffer.in6;
903
904 return 0;
905}
8add5f79 906
49092e22 907static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
908 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
909 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
910 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
911};
912
b146ad71
YW
913DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
914 IPV6_PRIVACY_EXTENSIONS_YES);
49092e22
SS
915
916int config_parse_ipv6_privacy_extensions(
917 const char* unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
921 unsigned section_line,
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
927
b146ad71 928 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
49092e22
SS
929
930 assert(filename);
931 assert(lvalue);
932 assert(rvalue);
933 assert(ipv6_privacy_extensions);
934
b146ad71
YW
935 s = ipv6_privacy_extensions_from_string(rvalue);
936 if (s < 0) {
937 if (streq(rvalue, "kernel"))
938 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
939 else {
940 log_syntax(unit, LOG_ERR, filename, line, 0,
941 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
942 return 0;
49092e22 943 }
49092e22
SS
944 }
945
b146ad71
YW
946 *ipv6_privacy_extensions = s;
947
49092e22
SS
948 return 0;
949}
a7d0ef44 950
1ac608c9
LP
951int config_parse_hostname(
952 const char *unit,
953 const char *filename,
954 unsigned line,
955 const char *section,
956 unsigned section_line,
957 const char *lvalue,
958 int ltype,
959 const char *rvalue,
960 void *data,
961 void *userdata) {
962
6528693a
YW
963 _cleanup_free_ char *hn = NULL;
964 char **hostname = data;
a7d0ef44
SS
965 int r;
966
967 assert(filename);
968 assert(lvalue);
969 assert(rvalue);
970
1ac608c9 971 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
972 if (r < 0)
973 return r;
974
1ac608c9 975 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
976 log_syntax(unit, LOG_ERR, filename, line, 0,
977 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
978 return 0;
979 }
980
6528693a
YW
981 r = dns_name_is_valid(hn);
982 if (r < 0) {
ab24039f
ZJS
983 log_syntax(unit, LOG_ERR, filename, line, r,
984 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
985 return 0;
986 }
987 if (r == 0) {
ab24039f
ZJS
988 log_syntax(unit, LOG_ERR, filename, line, 0,
989 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
990 return 0;
991 }
992
993 return free_and_replace(*hostname, hn);
a7d0ef44 994}
8eb9058d
LP
995
996int config_parse_timezone(
997 const char *unit,
998 const char *filename,
999 unsigned line,
1000 const char *section,
1001 unsigned section_line,
1002 const char *lvalue,
1003 int ltype,
1004 const char *rvalue,
1005 void *data,
1006 void *userdata) {
1007
19f9e4e2
YW
1008 _cleanup_free_ char *tz = NULL;
1009 char **datap = data;
8eb9058d
LP
1010 int r;
1011
1012 assert(filename);
1013 assert(lvalue);
1014 assert(rvalue);
1015
1016 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1017 if (r < 0)
1018 return r;
1019
089fb865 1020 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1021 log_syntax(unit, LOG_ERR, filename, line, 0,
1022 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1023 return 0;
1024 }
1025
19f9e4e2 1026 return free_and_replace(*datap, tz);
8eb9058d 1027}
1a04db0f 1028
53253824
SS
1029int config_parse_dns(
1030 const char *unit,
1031 const char *filename,
1032 unsigned line,
1033 const char *section,
1034 unsigned section_line,
1035 const char *lvalue,
1036 int ltype,
1037 const char *rvalue,
1038 void *data,
1039 void *userdata) {
1040
1041 Network *n = userdata;
1042 int r;
1043
1044 assert(filename);
1045 assert(lvalue);
1046 assert(rvalue);
1047
1048 for (;;) {
1049 _cleanup_free_ char *w = NULL;
1050 union in_addr_union a;
5512a963 1051 struct in_addr_data *m;
53253824
SS
1052 int family;
1053
5512a963 1054 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1055 if (r == -ENOMEM)
1056 return log_oom();
1057 if (r < 0) {
ab24039f
ZJS
1058 log_syntax(unit, LOG_ERR, filename, line, r,
1059 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1060 break;
1061 }
5512a963
LP
1062 if (r == 0)
1063 break;
53253824
SS
1064
1065 r = in_addr_from_string_auto(w, &family, &a);
1066 if (r < 0) {
ab24039f
ZJS
1067 log_syntax(unit, LOG_ERR, filename, line, r,
1068 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1069 continue;
1070 }
1071
62d74c78 1072 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1073 if (!m)
53253824
SS
1074 return log_oom();
1075
5512a963
LP
1076 m[n->n_dns++] = (struct in_addr_data) {
1077 .family = family,
1078 .address = a,
1079 };
1080
1081 n->dns = m;
53253824
SS
1082 }
1083
1084 return 0;
1085}
1086
8a516214
LP
1087int config_parse_dnssec_negative_trust_anchors(
1088 const char *unit,
1089 const char *filename,
1090 unsigned line,
1091 const char *section,
1092 unsigned section_line,
1093 const char *lvalue,
1094 int ltype,
1095 const char *rvalue,
1096 void *data,
1097 void *userdata) {
1098
1099 const char *p = rvalue;
1100 Network *n = data;
1101 int r;
1102
3df9bec5 1103 assert(n);
8a516214
LP
1104 assert(lvalue);
1105 assert(rvalue);
1106
1107 if (isempty(rvalue)) {
1108 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1109 return 0;
1110 }
1111
1112 for (;;) {
1113 _cleanup_free_ char *w = NULL;
1114
1115 r = extract_first_word(&p, &w, NULL, 0);
1116 if (r < 0) {
ab24039f
ZJS
1117 log_syntax(unit, LOG_ERR, filename, line, r,
1118 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1119 break;
1120 }
1121 if (r == 0)
1122 break;
1123
1124 r = dns_name_is_valid(w);
1125 if (r <= 0) {
ab24039f
ZJS
1126 log_syntax(unit, LOG_ERR, filename, line, r,
1127 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1128 continue;
1129 }
1130
cbbf38ae
LP
1131 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1132 if (r < 0)
1133 return log_oom();
1134
8a516214
LP
1135 r = set_put(n->dnssec_negative_trust_anchors, w);
1136 if (r < 0)
1137 return log_oom();
1138 if (r > 0)
1139 w = NULL;
1140 }
1141
1142 return 0;
1143}
b2a81c0b 1144
26575990
LP
1145int config_parse_ntp(
1146 const char *unit,
1147 const char *filename,
1148 unsigned line,
1149 const char *section,
1150 unsigned section_line,
1151 const char *lvalue,
1152 int ltype,
1153 const char *rvalue,
1154 void *data,
1155 void *userdata) {
1156
1157 char ***l = data;
1158 int r;
1159
1160 assert(l);
1161 assert(lvalue);
1162 assert(rvalue);
1163
1164 if (isempty(rvalue)) {
1165 *l = strv_free(*l);
1166 return 0;
1167 }
1168
1169 for (;;) {
1170 _cleanup_free_ char *w = NULL;
1171
1172 r = extract_first_word(&rvalue, &w, NULL, 0);
1173 if (r == -ENOMEM)
1174 return log_oom();
1175 if (r < 0) {
ab24039f
ZJS
1176 log_syntax(unit, LOG_ERR, filename, line, r,
1177 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1178 break;
1179 }
1180 if (r == 0)
1181 break;
1182
1183 r = dns_name_is_valid_or_address(w);
1184 if (r <= 0) {
ab24039f
ZJS
1185 log_syntax(unit, LOG_ERR, filename, line, r,
1186 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1187 continue;
af1c0de0
SS
1188 }
1189
c448459d
ZJS
1190 if (strv_length(*l) > MAX_NTP_SERVERS) {
1191 log_syntax(unit, LOG_WARNING, filename, line, 0,
1192 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1193 MAX_NTP_SERVERS, w);
1194 break;
1195 }
1196
1197 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1198 if (r < 0)
1199 return log_oom();
af1c0de0
SS
1200 }
1201
1202 return 0;
1203}
1204
4ac77d63
YW
1205int config_parse_required_for_online(
1206 const char *unit,
1207 const char *filename,
1208 unsigned line,
1209 const char *section,
1210 unsigned section_line,
1211 const char *lvalue,
1212 int ltype,
1213 const char *rvalue,
1214 void *data,
1215 void *userdata) {
1216
1217 Network *network = data;
1218 LinkOperationalState s;
1219 bool required = true;
1220 int r;
1221
1222 if (isempty(rvalue)) {
1223 network->required_for_online = true;
1224 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1225 return 0;
1226 }
1227
1228 s = link_operstate_from_string(rvalue);
1229 if (s < 0) {
1230 r = parse_boolean(rvalue);
1231 if (r < 0) {
1232 log_syntax(unit, LOG_ERR, filename, line, r,
1233 "Failed to parse %s= setting, ignoring assignment: %s",
1234 lvalue, rvalue);
1235 return 0;
1236 }
1237
1238 required = r;
1239 s = LINK_OPERSTATE_DEGRADED;
1240 }
1241
1242 network->required_for_online = required;
1243 network->required_operstate_for_online = s;
1244
1245 return 0;
1246}
7da377ef
SS
1247
1248DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1249 "Failed to parse KeepConfiguration= setting");
1250
1251static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1252 [KEEP_CONFIGURATION_NO] = "no",
1253 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1254 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1255 [KEEP_CONFIGURATION_STATIC] = "static",
1256 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1257};
1258
1259DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);