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