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