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