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