]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
Merge pull request #13749 from keszybz/pyparsing-2.4
[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
80060352 271 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef
SS
272 }
273
274 if (network->keep_configuration < 0)
80060352 275 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef 276
4bec2f23 277 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
fcbf4cb7 278 if (address_section_verify(address) < 0)
4bec2f23 279 address_free(address);
4bec2f23 280
fcbf4cb7
YW
281 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
282 if (route_section_verify(route, network) < 0)
4bec2f23 283 route_free(route);
0321cea7 284
fcbf4cb7
YW
285 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
286 if (section_is_invalid(fdb->section))
287 fdb_entry_free(fdb);
288
289 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
044d4b40 290 if (neighbor_section_verify(neighbor) < 0)
fcbf4cb7
YW
291 neighbor_free(neighbor);
292
293 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
294 if (section_is_invalid(label->section))
295 address_label_free(label);
296
297 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
298 if (section_is_invalid(prefix->section))
299 prefix_free(prefix);
300
714a199e
YW
301 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_route_prefixes)
302 if (section_is_invalid(prefix->section))
303 prefix_free(prefix);
304
fcbf4cb7 305 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
0aabccc8 306 if (routing_policy_rule_section_verify(rule) < 0)
fcbf4cb7 307 routing_policy_rule_free(rule);
4912ab77 308
0321cea7
YW
309 return 0;
310}
311
212bd73c 312int network_load_one(Manager *manager, const char *filename) {
838b2f7a 313 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 314 _cleanup_(network_unrefp) Network *network = NULL;
f579559b 315 _cleanup_fclose_ FILE *file = NULL;
047a0dac 316 const char *dropin_dirname;
838b2f7a 317 char *d;
f579559b
TG
318 int r;
319
bf1bc670
TA
320 assert(manager);
321 assert(filename);
322
f579559b
TG
323 file = fopen(filename, "re");
324 if (!file) {
325 if (errno == ENOENT)
326 return 0;
1e7a0e21
LP
327
328 return -errno;
f579559b
TG
329 }
330
ed88bcfb
ZJS
331 if (null_or_empty_fd(fileno(file))) {
332 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
333 return 0;
334 }
335
838b2f7a
YW
336 fname = strdup(filename);
337 if (!fname)
338 return log_oom();
339
340 name = strdup(basename(filename));
341 if (!name)
342 return log_oom();
343
344 d = strrchr(name, '.');
345 if (!d)
346 return -EINVAL;
347
348 *d = '\0';
349
350 dropin_dirname = strjoina(name, ".network.d");
351
17f9c355 352 network = new(Network, 1);
f579559b
TG
353 if (!network)
354 return log_oom();
355
17f9c355 356 *network = (Network) {
838b2f7a
YW
357 .filename = TAKE_PTR(fname),
358 .name = TAKE_PTR(name),
17f9c355 359
715d398e 360 .manager = manager,
35ac3b76
YW
361 .n_ref = 1,
362
17f9c355 363 .required_for_online = true,
4ac77d63 364 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
17f9c355 365 .dhcp = ADDRESS_FAMILY_NO,
7da377ef 366 .dhcp_critical = -1,
17f9c355 367 .dhcp_use_ntp = true,
299d578f 368 .dhcp_use_sip = true,
17f9c355
YW
369 .dhcp_use_dns = true,
370 .dhcp_use_hostname = true,
371 .dhcp_use_routes = true,
5238e957 372 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355 373 .dhcp_send_hostname = true,
5f3b5f19 374 .dhcp_send_release = true,
17f9c355
YW
375 /* To enable/disable RFC7844 Anonymity Profiles */
376 .dhcp_anonymize = false,
377 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 378 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
379 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
380 .dhcp_route_table = RT_TABLE_MAIN,
381 .dhcp_route_table_set = false,
382 /* NOTE: from man: UseMTU=... Defaults to false*/
383 .dhcp_use_mtu = false,
384 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
385 .dhcp_use_timezone = false,
386 .rapid_commit = true,
387
caa8ca42
SS
388 .dhcp6_use_ntp = true,
389 .dhcp6_use_dns = true,
390
17f9c355
YW
391 .dhcp_server_emit_dns = true,
392 .dhcp_server_emit_ntp = true,
299d578f 393 .dhcp_server_emit_sip = true,
17f9c355
YW
394 .dhcp_server_emit_router = true,
395 .dhcp_server_emit_timezone = true,
396
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,
17f9c355
YW
424
425 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
426 .ipv6_accept_ra = -1,
427 .ipv6_dad_transmits = -1,
428 .ipv6_hop_limit = -1,
429 .ipv6_proxy_ndp = -1,
430 .duid.type = _DUID_TYPE_INVALID,
431 .proxy_arp = -1,
432 .arp = -1,
433 .multicast = -1,
434 .allmulticast = -1,
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,
c423be28 440
7da377ef
SS
441 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
442
c423be28 443 .can_triple_sampling = -1,
afe42aef 444 .ip_service_type = -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);