]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
Merge pull request #18385 from kinvolk/mauricio/restrict-network-interfaces
[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 415
52aa38f1 416 .can_termination = -1,
17f9c355 417 };
f579559b 418
4f9ff96a 419 r = config_parse_many(
8b8024f1 420 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
4f9ff96a
LP
421 "Match\0"
422 "Link\0"
518cd6b5 423 "SR-IOV\0"
4f9ff96a
LP
424 "Network\0"
425 "Address\0"
426 "Neighbor\0"
427 "IPv6AddressLabel\0"
428 "RoutingPolicyRule\0"
429 "Route\0"
430 "NextHop\0"
431 "DHCP\0" /* compat */
432 "DHCPv4\0"
433 "DHCPv6\0"
b209cff2 434 "DHCPv6PrefixDelegation\0"
4f9ff96a 435 "DHCPServer\0"
c517a49b 436 "DHCPServerStaticLease\0"
4f9ff96a
LP
437 "IPv6AcceptRA\0"
438 "IPv6NDPProxyAddress\0"
439 "Bridge\0"
440 "BridgeFDB\0"
3db468ea 441 "BridgeMDB\0"
4f9ff96a 442 "BridgeVLAN\0"
27ff0490 443 "IPv6SendRA\0"
4f9ff96a
LP
444 "IPv6PrefixDelegation\0"
445 "IPv6Prefix\0"
446 "IPv6RoutePrefix\0"
447 "LLDP\0"
448 "TrafficControlQueueingDiscipline\0"
449 "CAN\0"
450 "QDisc\0"
451 "BFIFO\0"
452 "CAKE\0"
453 "ControlledDelay\0"
454 "DeficitRoundRobinScheduler\0"
455 "DeficitRoundRobinSchedulerClass\0"
d474aa51 456 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
457 "FairQueueing\0"
458 "FairQueueingControlledDelay\0"
8f6b6d70 459 "FlowQueuePIE\0"
4f9ff96a
LP
460 "GenericRandomEarlyDetection\0"
461 "HeavyHitterFilter\0"
462 "HierarchyTokenBucket\0"
463 "HierarchyTokenBucketClass\0"
464 "NetworkEmulator\0"
b12aaee5
SS
465 "PFIFO\0"
466 "PFIFOFast\0"
467 "PFIFOHeadDrop\0"
4f9ff96a 468 "PIE\0"
b12aaee5 469 "QuickFairQueueing\0"
4d7ddaf9 470 "QuickFairQueueingClass\0"
4f9ff96a
LP
471 "StochasticFairBlue\0"
472 "StochasticFairnessQueueing\0"
473 "TokenBucketFilter\0"
474 "TrivialLinkEqualizer\0",
475 config_item_perf_lookup, network_network_gperf_lookup,
476 CONFIG_PARSE_WARN,
477 network,
478 &network->timestamp);
102bc043 479 if (r < 0)
f579559b 480 return r;
f579559b 481
fa7cd711
YW
482 r = network_add_ipv4ll_route(network);
483 if (r < 0)
484 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
485
5d5003ab
YW
486 r = network_add_default_route_on_device(network);
487 if (r < 0)
488 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
489 network->filename);
490
7f06b3e1
YW
491 if (network_verify(network) < 0)
492 /* Ignore .network files that do not match the conditions. */
493 return 0;
494
9fa3e794 495 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
dbffab87
TG
496 if (r < 0)
497 return r;
498
b5b9b0e7 499 TAKE_PTR(network);
f579559b
TG
500 return 0;
501}
502
7f06b3e1 503int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
504 _cleanup_strv_free_ char **files = NULL;
505 char **f;
f579559b
TG
506 int r;
507
508 assert(manager);
509
7f06b3e1 510 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 511
dc0d4078 512 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
513 if (r < 0)
514 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 515
715d398e 516 STRV_FOREACH(f, files) {
7f06b3e1 517 r = network_load_one(manager, networks, *f);
f579559b 518 if (r < 0)
be711082 519 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
520 }
521
f579559b
TG
522 return 0;
523}
524
7f06b3e1
YW
525int network_reload(Manager *manager) {
526 OrderedHashmap *new_networks = NULL;
527 Network *n, *old;
7f06b3e1
YW
528 int r;
529
530 assert(manager);
531
532 r = network_load(manager, &new_networks);
533 if (r < 0)
534 goto failure;
535
90e74a66 536 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1
YW
537 r = network_get_by_name(manager, n->name, &old);
538 if (r < 0)
539 continue; /* The .network file is new. */
540
541 if (n->timestamp != old->timestamp)
542 continue; /* The .network file is modified. */
543
544 if (!streq(n->filename, old->filename))
545 continue;
546
547 r = ordered_hashmap_replace(new_networks, old->name, old);
548 if (r < 0)
549 goto failure;
550
551 network_ref(old);
552 network_unref(n);
553 }
554
555 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
556 manager->networks = new_networks;
557
558 return 0;
559
560failure:
561 ordered_hashmap_free_with_destructor(new_networks, network_unref);
562
563 return r;
564}
565
35ac3b76 566static Network *network_free(Network *network) {
f579559b 567 if (!network)
35ac3b76 568 return NULL;
f579559b
TG
569
570 free(network->filename);
571
5722fb89 572 net_match_clear(&network->match);
c4f58dea 573 condition_free_list(network->conditions);
f579559b 574
11c38d3e
YA
575 free(network->dhcp_server_relay_agent_circuit_id);
576 free(network->dhcp_server_relay_agent_remote_id);
577
f579559b 578 free(network->description);
edb85f0d 579 free(network->dhcp_vendor_class_identifier);
7b8d23a9 580 free(network->dhcp_mudurl);
af1c0de0 581 strv_free(network->dhcp_user_class);
27cb34f5 582 free(network->dhcp_hostname);
d419ef02 583 free(network->dhcp_label);
6b000af4 584 set_free(network->dhcp_deny_listed_ip);
98ebef62 585 set_free(network->dhcp_allow_listed_ip);
5bc945be 586 set_free(network->dhcp_request_options);
35f6a5cb 587 set_free(network->dhcp6_request_options);
c106cc36 588 free(network->mac);
3175a8c2 589 free(network->dhcp6_mudurl);
f37f2a6b 590 strv_free(network->dhcp6_user_class);
ed0d1b2e 591 strv_free(network->dhcp6_vendor_class);
c106cc36 592
b0e39c82 593 strv_free(network->ntp);
e77bd3fd
YW
594 for (unsigned i = 0; i < network->n_dns; i++)
595 in_addr_full_free(network->dns[i]);
5512a963 596 free(network->dns);
5e276772
YW
597 ordered_set_free(network->search_domains);
598 ordered_set_free(network->route_domains);
0d4ad91d 599 strv_free(network->bind_carrier);
cdd7812b 600
5e276772 601 ordered_set_free(network->router_search_domains);
cdd7812b 602 free(network->router_dns);
75d26411
YW
603 set_free_free(network->ndisc_deny_listed_router);
604 set_free_free(network->ndisc_allow_listed_router);
6b000af4 605 set_free_free(network->ndisc_deny_listed_prefix);
de6b6ff8 606 set_free_free(network->ndisc_allow_listed_prefix);
16c89e64 607 set_free_free(network->ndisc_deny_listed_route_prefix);
de6b6ff8 608 set_free_free(network->ndisc_allow_listed_route_prefix);
3bef724f 609
c0267a59 610 free(network->batadv_name);
cebe1257
YW
611 free(network->bridge_name);
612 free(network->bond_name);
613 free(network->vrf_name);
614 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 615 netdev_unref(network->bridge);
47e2dc31 616 netdev_unref(network->bond);
6cb955c6 617 netdev_unref(network->vrf);
fa6f1e54 618 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 619
d349f502 620 set_free_free(network->ipv6_proxy_ndp_addresses);
9cd9fc8f 621 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 622 hashmap_free_with_destructor(network->routes_by_section, route_free);
b82663dd 623 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
9671ae9d 624 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
ff9e0783 625 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
b0ba6938 626 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
d6a2a0f9 627 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
ecb0e85e
YW
628 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
629 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
ca183bf8 630 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
c517a49b 631 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
518cd6b5 632 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
34658df2 633 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 634
dbffab87 635 free(network->name);
f579559b 636
8eb9058d 637 free(network->dhcp_server_timezone);
165d7c5c 638 free(network->dhcp_server_uplink_name);
63295b42 639 free(network->router_uplink_name);
2a71d57f 640
2324fd3a 641 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
2a71d57f 642 free(network->dhcp_server_emit[t].addresses);
8eb9058d 643
8a516214
LP
644 set_free_free(network->dnssec_negative_trust_anchors);
645
e9a8c550
SS
646 free(network->lldp_mud);
647
0e96961d 648 ordered_hashmap_free(network->dhcp_client_send_options);
7354900d 649 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
0e96961d 650 ordered_hashmap_free(network->dhcp_server_send_options);
7354900d 651 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
2c621495 652 ordered_set_free(network->ipv6_tokens);
1c3ec1cd 653 ordered_hashmap_free(network->dhcp6_client_send_options);
b4ccc5de 654 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
cb29c156 655
35ac3b76 656 return mfree(network);
f579559b
TG
657}
658
35ac3b76
YW
659DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
660
dbffab87
TG
661int network_get_by_name(Manager *manager, const char *name, Network **ret) {
662 Network *network;
663
664 assert(manager);
665 assert(name);
666 assert(ret);
667
715d398e 668 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
669 if (!network)
670 return -ENOENT;
671
672 *ret = network;
673
674 return 0;
675}
676
adfeee49 677bool network_has_static_ipv6_configurations(Network *network) {
439689c6 678 Address *address;
adfeee49 679 Route *route;
9671ae9d 680 BridgeFDB *fdb;
ff9e0783 681 BridgeMDB *mdb;
adfeee49 682 Neighbor *neighbor;
439689c6
SS
683
684 assert(network);
685
9cd9fc8f 686 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
687 if (address->family == AF_INET6)
688 return true;
adfeee49 689
2a54a044 690 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
691 if (route->family == AF_INET6)
692 return true;
693
9671ae9d 694 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
adfeee49
YW
695 if (fdb->family == AF_INET6)
696 return true;
697
ff9e0783 698 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
3db468ea
DM
699 if (mdb->family == AF_INET6)
700 return true;
701
b0ba6938 702 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
adfeee49
YW
703 if (neighbor->family == AF_INET6)
704 return true;
705
d6a2a0f9 706 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
707 return true;
708
ecb0e85e 709 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 710 return true;
d30081c2
YW
711
712 if (!hashmap_isempty(network->route_prefixes_by_section))
713 return true;
439689c6
SS
714
715 return false;
716}
717
63481576
YW
718int config_parse_stacked_netdev(
719 const char *unit,
02b59d57
TG
720 const char *filename,
721 unsigned line,
722 const char *section,
723 unsigned section_line,
724 const char *lvalue,
725 int ltype,
726 const char *rvalue,
727 void *data,
728 void *userdata) {
63481576 729
95dba435
YW
730 _cleanup_free_ char *name = NULL;
731 NetDevKind kind = ltype;
cebe1257 732 Hashmap **h = data;
02b59d57
TG
733 int r;
734
735 assert(filename);
736 assert(lvalue);
737 assert(rvalue);
738 assert(data);
95dba435
YW
739 assert(IN_SET(kind,
740 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 741 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 742 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
743 NETDEV_KIND_XFRM));
54abf461 744
cebe1257 745 if (!ifname_valid(rvalue)) {
d96edb2c 746 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 747 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
748 return 0;
749 }
750
cebe1257
YW
751 name = strdup(rvalue);
752 if (!name)
753 return log_oom();
3e570042 754
6de530f2
SS
755 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
756 if (r == -ENOMEM)
cebe1257 757 return log_oom();
83ec4592 758 if (r < 0)
d96edb2c 759 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
760 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
761 else if (r == 0)
762 log_syntax(unit, LOG_DEBUG, filename, line, r,
763 "NetDev '%s' specified twice, ignoring.", name);
764 else
0c7bd7ec 765 TAKE_PTR(name);
47e2dc31 766
fe6b2d55
TG
767 return 0;
768}
7951dea2 769
3df9bec5
LP
770int config_parse_domains(
771 const char *unit,
772 const char *filename,
773 unsigned line,
774 const char *section,
775 unsigned section_line,
776 const char *lvalue,
777 int ltype,
778 const char *rvalue,
779 void *data,
780 void *userdata) {
781
5aafd5b1 782 Network *n = userdata;
6192b846
TG
783 int r;
784
5aafd5b1 785 assert(filename);
3df9bec5
LP
786 assert(lvalue);
787 assert(rvalue);
5aafd5b1 788 assert(n);
6192b846 789
3df9bec5 790 if (isempty(rvalue)) {
5e276772
YW
791 n->search_domains = ordered_set_free(n->search_domains);
792 n->route_domains = ordered_set_free(n->route_domains);
3df9bec5
LP
793 return 0;
794 }
67272d15 795
d96edb2c 796 for (const char *p = rvalue;;) {
3df9bec5
LP
797 _cleanup_free_ char *w = NULL, *normalized = NULL;
798 const char *domain;
799 bool is_route;
800
801 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
802 if (r == -ENOMEM)
803 return log_oom();
3df9bec5 804 if (r < 0) {
d96edb2c 805 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 806 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 807 return 0;
3df9bec5
LP
808 }
809 if (r == 0)
d96edb2c 810 return 0;
3df9bec5
LP
811
812 is_route = w[0] == '~';
813 domain = is_route ? w + 1 : w;
814
815 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
816 /* If the root domain appears as is, or the special token "*" is found, we'll
817 * consider this as routing domain, unconditionally. */
3df9bec5 818 is_route = true;
ab24039f
ZJS
819 domain = "."; /* make sure we don't allow empty strings, thus write the root
820 * domain as "." */
3df9bec5 821 } else {
7470cc4c 822 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 823 if (r < 0) {
d96edb2c 824 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 825 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
826 continue;
827 }
828
829 domain = normalized;
830
831 if (is_localhost(domain)) {
d96edb2c 832 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
833 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
834 domain);
37de2509 835 continue;
3df9bec5 836 }
37de2509 837 }
40274ed6 838
5e2a51d5 839 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
cf453507
YW
840 r = ordered_set_put_strdup(set, domain);
841 if (r == -EEXIST)
842 continue;
09451975
LP
843 if (r < 0)
844 return log_oom();
40274ed6 845 }
6192b846
TG
846}
847
1ac608c9
LP
848int config_parse_hostname(
849 const char *unit,
850 const char *filename,
851 unsigned line,
852 const char *section,
853 unsigned section_line,
854 const char *lvalue,
855 int ltype,
856 const char *rvalue,
857 void *data,
858 void *userdata) {
859
6528693a 860 char **hostname = data;
a7d0ef44
SS
861 int r;
862
863 assert(filename);
864 assert(lvalue);
865 assert(rvalue);
b40b8b06 866 assert(data);
a7d0ef44 867
b40b8b06
YW
868 if (isempty(rvalue)) {
869 *hostname = mfree(*hostname);
870 return 0;
871 }
a7d0ef44 872
b40b8b06 873 if (!hostname_is_valid(rvalue, 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
b40b8b06 879 r = dns_name_is_valid(rvalue);
6528693a 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
b40b8b06 891 return free_and_strdup_warn(hostname, rvalue);
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
b40b8b06 906 char **tz = data;
8eb9058d
LP
907 int r;
908
909 assert(filename);
910 assert(lvalue);
911 assert(rvalue);
b40b8b06 912 assert(data);
8eb9058d 913
b40b8b06
YW
914 if (isempty(rvalue)) {
915 *tz = mfree(*tz);
916 return 0;
917 }
8eb9058d 918
b40b8b06
YW
919 r = verify_timezone(rvalue, LOG_WARNING);
920 if (r < 0) {
921 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 922 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
923 return 0;
924 }
925
b40b8b06 926 return free_and_strdup_warn(tz, rvalue);
8eb9058d 927}
1a04db0f 928
53253824
SS
929int config_parse_dns(
930 const char *unit,
931 const char *filename,
932 unsigned line,
933 const char *section,
934 unsigned section_line,
935 const char *lvalue,
936 int ltype,
937 const char *rvalue,
938 void *data,
939 void *userdata) {
940
941 Network *n = userdata;
942 int r;
943
944 assert(filename);
945 assert(lvalue);
946 assert(rvalue);
5aafd5b1 947 assert(n);
53253824 948
d96edb2c 949 if (isempty(rvalue)) {
e77bd3fd
YW
950 for (unsigned i = 0; i < n->n_dns; i++)
951 in_addr_full_free(n->dns[i]);
d96edb2c
YW
952 n->dns = mfree(n->dns);
953 n->n_dns = 0;
954 return 0;
955 }
956
957 for (const char *p = rvalue;;) {
e77bd3fd 958 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 959 _cleanup_free_ char *w = NULL;
e77bd3fd 960 struct in_addr_full **m;
53253824 961
d96edb2c 962 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
963 if (r == -ENOMEM)
964 return log_oom();
965 if (r < 0) {
d96edb2c 966 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 967 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 968 return 0;
53253824 969 }
5512a963 970 if (r == 0)
d96edb2c 971 return 0;
53253824 972
e77bd3fd 973 r = in_addr_full_new_from_string(w, &dns);
53253824 974 if (r < 0) {
d96edb2c 975 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 976 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
977 continue;
978 }
979
e77bd3fd
YW
980 if (IN_SET(dns->port, 53, 853))
981 dns->port = 0;
982
983 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 984 if (!m)
53253824
SS
985 return log_oom();
986
e77bd3fd 987 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 988 n->dns = m;
53253824 989 }
53253824
SS
990}
991
8a516214
LP
992int config_parse_dnssec_negative_trust_anchors(
993 const char *unit,
994 const char *filename,
995 unsigned line,
996 const char *section,
997 unsigned section_line,
998 const char *lvalue,
999 int ltype,
1000 const char *rvalue,
1001 void *data,
1002 void *userdata) {
1003
5aafd5b1 1004 Set **nta = data;
8a516214
LP
1005 int r;
1006
5aafd5b1 1007 assert(filename);
8a516214
LP
1008 assert(lvalue);
1009 assert(rvalue);
5aafd5b1 1010 assert(nta);
8a516214
LP
1011
1012 if (isempty(rvalue)) {
5aafd5b1 1013 *nta = set_free_free(*nta);
8a516214
LP
1014 return 0;
1015 }
1016
d96edb2c 1017 for (const char *p = rvalue;;) {
8a516214
LP
1018 _cleanup_free_ char *w = NULL;
1019
1020 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1021 if (r == -ENOMEM)
1022 return log_oom();
8a516214 1023 if (r < 0) {
d96edb2c 1024 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1025 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1026 return 0;
8a516214
LP
1027 }
1028 if (r == 0)
d96edb2c 1029 return 0;
8a516214
LP
1030
1031 r = dns_name_is_valid(w);
1032 if (r <= 0) {
d96edb2c 1033 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1034 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1035 continue;
1036 }
1037
5aafd5b1 1038 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1039 if (r < 0)
1040 return log_oom();
8a516214 1041 }
8a516214 1042}
b2a81c0b 1043
26575990
LP
1044int config_parse_ntp(
1045 const char *unit,
1046 const char *filename,
1047 unsigned line,
1048 const char *section,
1049 unsigned section_line,
1050 const char *lvalue,
1051 int ltype,
1052 const char *rvalue,
1053 void *data,
1054 void *userdata) {
1055
1056 char ***l = data;
1057 int r;
1058
5aafd5b1 1059 assert(filename);
26575990
LP
1060 assert(lvalue);
1061 assert(rvalue);
5aafd5b1 1062 assert(l);
26575990
LP
1063
1064 if (isempty(rvalue)) {
1065 *l = strv_free(*l);
1066 return 0;
1067 }
1068
d96edb2c 1069 for (const char *p = rvalue;;) {
26575990
LP
1070 _cleanup_free_ char *w = NULL;
1071
d96edb2c 1072 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1073 if (r == -ENOMEM)
1074 return log_oom();
1075 if (r < 0) {
d96edb2c 1076 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1077 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1078 return 0;
26575990
LP
1079 }
1080 if (r == 0)
d96edb2c 1081 return 0;
26575990
LP
1082
1083 r = dns_name_is_valid_or_address(w);
1084 if (r <= 0) {
d96edb2c 1085 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1086 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1087 continue;
af1c0de0
SS
1088 }
1089
c448459d
ZJS
1090 if (strv_length(*l) > MAX_NTP_SERVERS) {
1091 log_syntax(unit, LOG_WARNING, filename, line, 0,
1092 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1093 MAX_NTP_SERVERS, w);
d96edb2c 1094 return 0;
c448459d
ZJS
1095 }
1096
1097 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1098 if (r < 0)
1099 return log_oom();
af1c0de0 1100 }
af1c0de0
SS
1101}
1102
4ac77d63
YW
1103int config_parse_required_for_online(
1104 const char *unit,
1105 const char *filename,
1106 unsigned line,
1107 const char *section,
1108 unsigned section_line,
1109 const char *lvalue,
1110 int ltype,
1111 const char *rvalue,
1112 void *data,
1113 void *userdata) {
1114
5aafd5b1 1115 Network *network = userdata;
75cd4a5d 1116 LinkOperationalStateRange range;
4ac77d63
YW
1117 bool required = true;
1118 int r;
1119
5aafd5b1
YW
1120 assert(filename);
1121 assert(lvalue);
1122 assert(rvalue);
1123 assert(network);
1124
4ac77d63 1125 if (isempty(rvalue)) {
7c644a69 1126 network->required_for_online = -1;
75cd4a5d 1127 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1128 return 0;
1129 }
1130
75cd4a5d
DDM
1131 r = parse_operational_state_range(rvalue, &range);
1132 if (r < 0) {
4ac77d63
YW
1133 r = parse_boolean(rvalue);
1134 if (r < 0) {
d96edb2c 1135 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1136 "Failed to parse %s= setting, ignoring assignment: %s",
1137 lvalue, rvalue);
1138 return 0;
1139 }
1140
1141 required = r;
75cd4a5d 1142 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1143 }
1144
1145 network->required_for_online = required;
75cd4a5d 1146 network->required_operstate_for_online = range;
4ac77d63
YW
1147
1148 return 0;
1149}
7da377ef 1150
f0c09831
YW
1151int config_parse_link_group(
1152 const char *unit,
1153 const char *filename,
1154 unsigned line,
1155 const char *section,
1156 unsigned section_line,
1157 const char *lvalue,
1158 int ltype,
1159 const char *rvalue,
1160 void *data,
1161 void *userdata) {
1162
1163 Network *network = userdata;
1164 int r;
1165
1166 assert(filename);
1167 assert(lvalue);
1168 assert(rvalue);
1169 assert(network);
1170
1171 if (isempty(rvalue)) {
1172 network->group = 0;
1173 network->group_set = false;
1174 return 0;
1175 }
1176
1177 r = safe_atou32(rvalue, &network->group);
1178 if (r < 0) {
1179 log_syntax(unit, LOG_WARNING, filename, line, r,
1180 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1181 return 0;
1182 }
1183
1184 network->group_set = true;
1185 return 0;
1186}
1187
63295b42
YW
1188
1189int config_parse_uplink(
1190 const char *unit,
1191 const char *filename,
1192 unsigned line,
1193 const char *section,
1194 unsigned section_line,
1195 const char *lvalue,
1196 int ltype,
1197 const char *rvalue,
1198 void *data,
1199 void *userdata) {
1200
1201 Network *network = userdata;
1202 int *index, r;
1203 char **name;
1204
1205 assert(filename);
1206 assert(section);
1207 assert(lvalue);
1208 assert(rvalue);
1209
1210 if (streq(section, "DHCPServer")) {
1211 index = &network->dhcp_server_uplink_index;
1212 name = &network->dhcp_server_uplink_name;
1213 } else if (streq(section, "IPv6SendRA")) {
1214 index = &network->router_uplink_index;
1215 name = &network->router_uplink_name;
1216 } else
1217 assert_not_reached();
1218
1219 if (isempty(rvalue) || streq(rvalue, ":auto")) {
1220 *index = UPLINK_INDEX_AUTO;
1221 *name = mfree(*name);
1222 return 0;
1223 }
1224
1225 if (streq(rvalue, ":none")) {
1226 *index = UPLINK_INDEX_NONE;
1227 *name = mfree(*name);
1228 return 0;
1229 }
1230
1231 r = parse_ifindex(rvalue);
1232 if (r > 0) {
1233 *index = r;
1234 *name = mfree(*name);
1235 return 0;
1236 }
1237
1238 if (!ifname_valid_full(rvalue, IFNAME_VALID_ALTERNATIVE)) {
1239 log_syntax(unit, LOG_WARNING, filename, line, 0,
1240 "Invalid interface name in %s=, ignoring assignment: %s", lvalue, rvalue);
1241 return 0;
1242 }
1243
1244 /* The interface name will be resolved later. */
1245 r = free_and_strdup_warn(name, rvalue);
1246 if (r < 0)
1247 return r;
1248
1249 /* Note, if uplink_name is set, then uplink_index will be ignored. So, the below does not mean
1250 * an uplink interface will be selected automatically. */
1251 *index = UPLINK_INDEX_AUTO;
1252 return 0;
1253}
1254
8430841b
L
1255DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1256 "Failed to parse RequiredFamilyForOnline= setting");
1257
7da377ef
SS
1258DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1259 "Failed to parse KeepConfiguration= setting");
1260
1261static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1262 [KEEP_CONFIGURATION_NO] = "no",
1263 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1264 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1265 [KEEP_CONFIGURATION_STATIC] = "static",
1266 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1267};
1268
1269DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9
YW
1270
1271static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1272 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1273 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1274 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1275 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1276};
1277
1278DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1279DEFINE_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
1280
1281static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1282 [ACTIVATION_POLICY_UP] = "up",
1283 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1284 [ACTIVATION_POLICY_MANUAL] = "manual",
1285 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1286 [ACTIVATION_POLICY_DOWN] = "down",
1287 [ACTIVATION_POLICY_BOUND] = "bound",
1288};
1289
1290DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1291DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");