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