]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
stat-util: introduce path_is_network_fs()
[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);
41ce9d76 324 r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section);
e217e22a
YW
325 if (r < 0)
326 return r;
c517a49b 327 network_drop_invalid_static_leases(network);
518cd6b5 328
0017ba31
YW
329 network_adjust_dhcp_server(network);
330
0321cea7
YW
331 return 0;
332}
333
7f06b3e1 334int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
838b2f7a 335 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 336 _cleanup_(network_unrefp) Network *network = NULL;
047a0dac 337 const char *dropin_dirname;
838b2f7a 338 char *d;
f579559b
TG
339 int r;
340
bf1bc670
TA
341 assert(manager);
342 assert(filename);
343
4e54a17d
YW
344 r = null_or_empty_path(filename);
345 if (r == -ENOENT)
346 return 0;
347 if (r < 0)
348 return r;
349 if (r > 0) {
ed88bcfb 350 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
351 return 0;
352 }
353
838b2f7a
YW
354 fname = strdup(filename);
355 if (!fname)
356 return log_oom();
357
358 name = strdup(basename(filename));
359 if (!name)
360 return log_oom();
361
362 d = strrchr(name, '.');
363 if (!d)
364 return -EINVAL;
365
366 *d = '\0';
367
368 dropin_dirname = strjoina(name, ".network.d");
369
17f9c355 370 network = new(Network, 1);
f579559b
TG
371 if (!network)
372 return log_oom();
373
17f9c355 374 *network = (Network) {
838b2f7a
YW
375 .filename = TAKE_PTR(fname),
376 .name = TAKE_PTR(name),
17f9c355 377
715d398e 378 .manager = manager,
35ac3b76
YW
379 .n_ref = 1,
380
7c644a69 381 .required_for_online = -1,
75cd4a5d 382 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
61135582 383 .activation_policy = _ACTIVATION_POLICY_INVALID,
db5756f3
YW
384 .arp = -1,
385 .multicast = -1,
386 .allmulticast = -1,
937e305e 387 .promiscuous = -1,
db5756f3 388
db5756f3
YW
389 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
390
4e26a5ba 391 .dhcp_duid.type = _DUID_TYPE_INVALID,
7da377ef 392 .dhcp_critical = -1,
17f9c355 393 .dhcp_use_ntp = true,
d7b04506 394 .dhcp_routes_to_ntp = true,
299d578f 395 .dhcp_use_sip = true,
17f9c355 396 .dhcp_use_dns = true,
70570306 397 .dhcp_routes_to_dns = true,
17f9c355
YW
398 .dhcp_use_hostname = true,
399 .dhcp_use_routes = true,
589397a2 400 .dhcp_use_gateway = -1,
17f9c355 401 .dhcp_send_hostname = true,
5f3b5f19 402 .dhcp_send_release = true,
17f9c355 403 .dhcp_route_metric = DHCP_ROUTE_METRIC,
f90635f1 404 .dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
17f9c355 405 .dhcp_route_table = RT_TABLE_MAIN,
db5756f3 406 .dhcp_ip_service_type = -1,
e70eca9b 407 .dhcp_broadcast = -1,
17f9c355 408
1536b7b2 409 .dhcp6_use_address = true,
0f5ef9b6 410 .dhcp6_use_pd_prefix = true,
1536b7b2 411 .dhcp6_use_dns = true,
38ba3da0 412 .dhcp6_use_hostname = true,
1536b7b2 413 .dhcp6_use_ntp = true,
4e26a5ba 414 .dhcp6_duid.type = _DUID_TYPE_INVALID,
0e45721e 415 .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
caa8ca42 416
a27588d4
YW
417 .dhcp_pd = -1,
418 .dhcp_pd_announce = true,
419 .dhcp_pd_assign = true,
420 .dhcp_pd_manage_temporary_address = true,
421 .dhcp_pd_subnet_id = -1,
422 .dhcp_pd_route_metric = DHCP6PD_ROUTE_METRIC,
9efa8a3c 423
21b6b87e 424 .dhcp_server_bind_to_interface = true,
2a71d57f
LP
425 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
426 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
427 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
17f9c355
YW
428 .dhcp_server_emit_router = true,
429 .dhcp_server_emit_timezone = true,
430
4f1ac4a3 431 .router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
c9e2c2da 432 .router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
17f9c355
YW
433 .router_emit_dns = true,
434 .router_emit_domains = true,
435
436 .use_bpdu = -1,
437 .hairpin = -1,
438 .fast_leave = -1,
439 .allow_port_to_be_root = -1,
440 .unicast_flood = -1,
7f15b714 441 .multicast_flood = -1,
d3aa8b49 442 .multicast_to_unicast = -1,
7f15b714
TJ
443 .neighbor_suppression = -1,
444 .learning = -1,
1087623b
SS
445 .bridge_proxy_arp = -1,
446 .bridge_proxy_arp_wifi = -1,
17f9c355 447 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 448 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
449
450 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
c01b9b87 451 .lldp_multicast_mode = _SD_LLDP_MULTICAST_MODE_INVALID,
17f9c355 452
7ece6f58 453 .dns_default_route = -1,
17f9c355
YW
454 .llmnr = RESOLVE_SUPPORT_YES,
455 .mdns = RESOLVE_SUPPORT_NO,
456 .dnssec_mode = _DNSSEC_MODE_INVALID,
457 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
458
0321cea7 459 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 460 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 461 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 462
94d76d07 463 .ipv4_accept_local = -1,
d75bf6cf 464 .ipv4_route_localnet = -1,
17f9c355 465 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
17f9c355
YW
466 .ipv6_dad_transmits = -1,
467 .ipv6_hop_limit = -1,
468 .ipv6_proxy_ndp = -1,
17f9c355 469 .proxy_arp = -1,
db5756f3 470
7d93b92f 471 .ipv6_accept_ra = -1,
17f9c355 472 .ipv6_accept_ra_use_dns = true,
610c0db1
YW
473 .ipv6_accept_ra_use_gateway = true,
474 .ipv6_accept_ra_use_route_prefix = true,
062c2eea
SS
475 .ipv6_accept_ra_use_autonomous_prefix = true,
476 .ipv6_accept_ra_use_onlink_prefix = true,
7d93b92f 477 .ipv6_accept_ra_use_mtu = true,
17f9c355 478 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
8ebafba9 479 .ipv6_accept_ra_route_metric = DHCP_ROUTE_METRIC,
cabe5711 480 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
c423be28 481
52aa38f1 482 .can_termination = -1,
72e65e6f
YW
483
484 .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
485 .ipoib_umcast = -1,
17f9c355 486 };
f579559b 487
4f9ff96a 488 r = config_parse_many(
8b8024f1 489 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
4f9ff96a
LP
490 "Match\0"
491 "Link\0"
518cd6b5 492 "SR-IOV\0"
4f9ff96a
LP
493 "Network\0"
494 "Address\0"
495 "Neighbor\0"
496 "IPv6AddressLabel\0"
497 "RoutingPolicyRule\0"
498 "Route\0"
499 "NextHop\0"
500 "DHCP\0" /* compat */
501 "DHCPv4\0"
502 "DHCPv6\0"
a27588d4
YW
503 "DHCPv6PrefixDelegation\0" /* compat */
504 "DHCPPrefixDelegation\0"
4f9ff96a 505 "DHCPServer\0"
c517a49b 506 "DHCPServerStaticLease\0"
4f9ff96a
LP
507 "IPv6AcceptRA\0"
508 "IPv6NDPProxyAddress\0"
509 "Bridge\0"
510 "BridgeFDB\0"
3db468ea 511 "BridgeMDB\0"
4f9ff96a 512 "BridgeVLAN\0"
27ff0490 513 "IPv6SendRA\0"
4f9ff96a
LP
514 "IPv6PrefixDelegation\0"
515 "IPv6Prefix\0"
516 "IPv6RoutePrefix\0"
517 "LLDP\0"
518 "TrafficControlQueueingDiscipline\0"
519 "CAN\0"
520 "QDisc\0"
521 "BFIFO\0"
522 "CAKE\0"
523 "ControlledDelay\0"
524 "DeficitRoundRobinScheduler\0"
525 "DeficitRoundRobinSchedulerClass\0"
d474aa51 526 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
527 "FairQueueing\0"
528 "FairQueueingControlledDelay\0"
8f6b6d70 529 "FlowQueuePIE\0"
4f9ff96a
LP
530 "GenericRandomEarlyDetection\0"
531 "HeavyHitterFilter\0"
532 "HierarchyTokenBucket\0"
533 "HierarchyTokenBucketClass\0"
534 "NetworkEmulator\0"
b12aaee5
SS
535 "PFIFO\0"
536 "PFIFOFast\0"
537 "PFIFOHeadDrop\0"
4f9ff96a 538 "PIE\0"
b12aaee5 539 "QuickFairQueueing\0"
4d7ddaf9 540 "QuickFairQueueingClass\0"
4f9ff96a
LP
541 "StochasticFairBlue\0"
542 "StochasticFairnessQueueing\0"
543 "TokenBucketFilter\0"
544 "TrivialLinkEqualizer\0",
545 config_item_perf_lookup, network_network_gperf_lookup,
546 CONFIG_PARSE_WARN,
547 network,
8524db50 548 &network->stats_by_path);
102bc043 549 if (r < 0)
f579559b 550 return r;
f579559b 551
fa7cd711
YW
552 r = network_add_ipv4ll_route(network);
553 if (r < 0)
9202b567 554 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
fa7cd711 555
5d5003ab
YW
556 r = network_add_default_route_on_device(network);
557 if (r < 0)
9202b567
YW
558 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
559 network->filename);
5d5003ab 560
9202b567
YW
561 r = network_verify(network);
562 if (r == -ENOMEM)
563 return r;
564 if (r < 0)
7f06b3e1
YW
565 /* Ignore .network files that do not match the conditions. */
566 return 0;
567
9fa3e794 568 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
dbffab87
TG
569 if (r < 0)
570 return r;
571
b5b9b0e7 572 TAKE_PTR(network);
f579559b
TG
573 return 0;
574}
575
7f06b3e1 576int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
577 _cleanup_strv_free_ char **files = NULL;
578 char **f;
f579559b
TG
579 int r;
580
581 assert(manager);
582
7f06b3e1 583 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 584
dc0d4078 585 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
586 if (r < 0)
587 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 588
715d398e 589 STRV_FOREACH(f, files) {
7f06b3e1 590 r = network_load_one(manager, networks, *f);
f579559b 591 if (r < 0)
9202b567 592 return log_error_errno(r, "Failed to load %s: %m", *f);
f579559b
TG
593 }
594
f579559b
TG
595 return 0;
596}
597
8524db50
YW
598static bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
599 struct stat *st_a, *st_b;
600 const char *path;
601
602 assert(a);
603 assert(b);
604
605 if (hashmap_size(a) != hashmap_size(b))
606 return false;
607
608 HASHMAP_FOREACH_KEY(st_a, path, a) {
609 st_b = hashmap_get(b, path);
610 if (!st_b)
611 return false;
612
613 if (!stat_inode_unmodified(st_a, st_b))
614 return false;
615 }
616
617 return true;
618}
619
7f06b3e1
YW
620int network_reload(Manager *manager) {
621 OrderedHashmap *new_networks = NULL;
622 Network *n, *old;
7f06b3e1
YW
623 int r;
624
625 assert(manager);
626
627 r = network_load(manager, &new_networks);
628 if (r < 0)
629 goto failure;
630
90e74a66 631 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1 632 r = network_get_by_name(manager, n->name, &old);
8524db50
YW
633 if (r < 0) {
634 log_debug("Found new .network file: %s", n->filename);
635 continue;
636 }
7f06b3e1 637
8524db50
YW
638 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
639 log_debug("Found updated .network file: %s", n->filename);
7f06b3e1 640 continue;
8524db50 641 }
7f06b3e1
YW
642
643 r = ordered_hashmap_replace(new_networks, old->name, old);
644 if (r < 0)
645 goto failure;
646
647 network_ref(old);
648 network_unref(n);
649 }
650
651 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
652 manager->networks = new_networks;
653
a27588d4 654 return manager_build_dhcp_pd_subnet_ids(manager);
7f06b3e1
YW
655
656failure:
657 ordered_hashmap_free_with_destructor(new_networks, network_unref);
658
659 return r;
660}
661
a27588d4 662int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
1a4ca0e2
YW
663 Network *n;
664 int r;
665
666 assert(manager);
667
a27588d4 668 set_clear(manager->dhcp_pd_subnet_ids);
1a4ca0e2
YW
669
670 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
671 if (n->unmanaged)
672 continue;
673
a27588d4 674 if (!n->dhcp_pd)
1a4ca0e2
YW
675 continue;
676
a27588d4 677 if (n->dhcp_pd_subnet_id < 0)
1a4ca0e2
YW
678 continue;
679
a27588d4 680 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
1a4ca0e2
YW
681 if (r < 0)
682 return r;
683 }
684
685 return 0;
686}
687
35ac3b76 688static Network *network_free(Network *network) {
f579559b 689 if (!network)
35ac3b76 690 return NULL;
f579559b
TG
691
692 free(network->filename);
8524db50 693 hashmap_free(network->stats_by_path);
f579559b 694
5722fb89 695 net_match_clear(&network->match);
c4f58dea 696 condition_free_list(network->conditions);
f579559b 697
11c38d3e
YA
698 free(network->dhcp_server_relay_agent_circuit_id);
699 free(network->dhcp_server_relay_agent_remote_id);
700
f579559b 701 free(network->description);
edb85f0d 702 free(network->dhcp_vendor_class_identifier);
7b8d23a9 703 free(network->dhcp_mudurl);
af1c0de0 704 strv_free(network->dhcp_user_class);
27cb34f5 705 free(network->dhcp_hostname);
d419ef02 706 free(network->dhcp_label);
6b000af4 707 set_free(network->dhcp_deny_listed_ip);
98ebef62 708 set_free(network->dhcp_allow_listed_ip);
5bc945be 709 set_free(network->dhcp_request_options);
35f6a5cb 710 set_free(network->dhcp6_request_options);
3175a8c2 711 free(network->dhcp6_mudurl);
f37f2a6b 712 strv_free(network->dhcp6_user_class);
ed0d1b2e 713 strv_free(network->dhcp6_vendor_class);
c106cc36 714
b0e39c82 715 strv_free(network->ntp);
e77bd3fd
YW
716 for (unsigned i = 0; i < network->n_dns; i++)
717 in_addr_full_free(network->dns[i]);
5512a963 718 free(network->dns);
5e276772
YW
719 ordered_set_free(network->search_domains);
720 ordered_set_free(network->route_domains);
0d4ad91d 721 strv_free(network->bind_carrier);
cdd7812b 722
5e276772 723 ordered_set_free(network->router_search_domains);
cdd7812b 724 free(network->router_dns);
c995fa02
YW
725 set_free(network->ndisc_deny_listed_router);
726 set_free(network->ndisc_allow_listed_router);
727 set_free(network->ndisc_deny_listed_prefix);
728 set_free(network->ndisc_allow_listed_prefix);
729 set_free(network->ndisc_deny_listed_route_prefix);
730 set_free(network->ndisc_allow_listed_route_prefix);
3bef724f 731
c0267a59 732 free(network->batadv_name);
cebe1257
YW
733 free(network->bridge_name);
734 free(network->bond_name);
735 free(network->vrf_name);
736 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 737 netdev_unref(network->bridge);
47e2dc31 738 netdev_unref(network->bond);
6cb955c6 739 netdev_unref(network->vrf);
fa6f1e54 740 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 741
d349f502 742 set_free_free(network->ipv6_proxy_ndp_addresses);
9cd9fc8f 743 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
2a54a044 744 hashmap_free_with_destructor(network->routes_by_section, route_free);
b82663dd 745 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
9671ae9d 746 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
ff9e0783 747 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
b0ba6938 748 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
d6a2a0f9 749 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
ecb0e85e
YW
750 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
751 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
ca183bf8 752 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
c517a49b 753 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
518cd6b5 754 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
34658df2 755 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 756
dbffab87 757 free(network->name);
f579559b 758
8eb9058d 759 free(network->dhcp_server_timezone);
165d7c5c 760 free(network->dhcp_server_uplink_name);
63295b42 761 free(network->router_uplink_name);
a27588d4 762 free(network->dhcp_pd_uplink_name);
2a71d57f 763
2324fd3a 764 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
2a71d57f 765 free(network->dhcp_server_emit[t].addresses);
8eb9058d 766
8a516214
LP
767 set_free_free(network->dnssec_negative_trust_anchors);
768
c01b9b87 769 free(network->lldp_mudurl);
e9a8c550 770
0e96961d 771 ordered_hashmap_free(network->dhcp_client_send_options);
7354900d 772 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
0e96961d 773 ordered_hashmap_free(network->dhcp_server_send_options);
7354900d 774 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
1c3ec1cd 775 ordered_hashmap_free(network->dhcp6_client_send_options);
b4ccc5de 776 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
a27588d4 777 set_free(network->dhcp_pd_tokens);
3bac5fe6 778 set_free(network->ndisc_tokens);
cb29c156 779
35ac3b76 780 return mfree(network);
f579559b
TG
781}
782
35ac3b76
YW
783DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
784
dbffab87
TG
785int network_get_by_name(Manager *manager, const char *name, Network **ret) {
786 Network *network;
787
788 assert(manager);
789 assert(name);
790 assert(ret);
791
715d398e 792 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
793 if (!network)
794 return -ENOENT;
795
796 *ret = network;
797
798 return 0;
799}
800
adfeee49 801bool network_has_static_ipv6_configurations(Network *network) {
439689c6 802 Address *address;
adfeee49 803 Route *route;
9671ae9d 804 BridgeFDB *fdb;
ff9e0783 805 BridgeMDB *mdb;
adfeee49 806 Neighbor *neighbor;
439689c6
SS
807
808 assert(network);
809
9cd9fc8f 810 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
811 if (address->family == AF_INET6)
812 return true;
adfeee49 813
2a54a044 814 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
815 if (route->family == AF_INET6)
816 return true;
817
9671ae9d 818 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
adfeee49
YW
819 if (fdb->family == AF_INET6)
820 return true;
821
ff9e0783 822 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
3db468ea
DM
823 if (mdb->family == AF_INET6)
824 return true;
825
b0ba6938 826 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
adfeee49
YW
827 if (neighbor->family == AF_INET6)
828 return true;
829
d6a2a0f9 830 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
831 return true;
832
ecb0e85e 833 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 834 return true;
d30081c2
YW
835
836 if (!hashmap_isempty(network->route_prefixes_by_section))
837 return true;
439689c6
SS
838
839 return false;
840}
841
63481576
YW
842int config_parse_stacked_netdev(
843 const char *unit,
02b59d57
TG
844 const char *filename,
845 unsigned line,
846 const char *section,
847 unsigned section_line,
848 const char *lvalue,
849 int ltype,
850 const char *rvalue,
851 void *data,
852 void *userdata) {
63481576 853
95dba435
YW
854 _cleanup_free_ char *name = NULL;
855 NetDevKind kind = ltype;
cebe1257 856 Hashmap **h = data;
02b59d57
TG
857 int r;
858
859 assert(filename);
860 assert(lvalue);
861 assert(rvalue);
862 assert(data);
95dba435 863 assert(IN_SET(kind,
b90d0f83 864 NETDEV_KIND_IPOIB,
bc945c2b
YW
865 NETDEV_KIND_IPVLAN,
866 NETDEV_KIND_IPVTAP,
867 NETDEV_KIND_L2TP,
868 NETDEV_KIND_MACSEC,
869 NETDEV_KIND_MACVLAN,
870 NETDEV_KIND_MACVTAP,
871 NETDEV_KIND_VLAN,
872 NETDEV_KIND_VXLAN,
873 NETDEV_KIND_XFRM,
874 _NETDEV_KIND_TUNNEL));
54abf461 875
cebe1257 876 if (!ifname_valid(rvalue)) {
d96edb2c 877 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 878 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
879 return 0;
880 }
881
cebe1257
YW
882 name = strdup(rvalue);
883 if (!name)
884 return log_oom();
3e570042 885
6de530f2
SS
886 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
887 if (r == -ENOMEM)
cebe1257 888 return log_oom();
83ec4592 889 if (r < 0)
d96edb2c 890 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
891 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
892 else if (r == 0)
893 log_syntax(unit, LOG_DEBUG, filename, line, r,
894 "NetDev '%s' specified twice, ignoring.", name);
895 else
0c7bd7ec 896 TAKE_PTR(name);
47e2dc31 897
fe6b2d55
TG
898 return 0;
899}
7951dea2 900
3df9bec5
LP
901int config_parse_domains(
902 const char *unit,
903 const char *filename,
904 unsigned line,
905 const char *section,
906 unsigned section_line,
907 const char *lvalue,
908 int ltype,
909 const char *rvalue,
910 void *data,
911 void *userdata) {
912
5aafd5b1 913 Network *n = userdata;
6192b846
TG
914 int r;
915
5aafd5b1 916 assert(filename);
3df9bec5
LP
917 assert(lvalue);
918 assert(rvalue);
5aafd5b1 919 assert(n);
6192b846 920
3df9bec5 921 if (isempty(rvalue)) {
5e276772
YW
922 n->search_domains = ordered_set_free(n->search_domains);
923 n->route_domains = ordered_set_free(n->route_domains);
3df9bec5
LP
924 return 0;
925 }
67272d15 926
d96edb2c 927 for (const char *p = rvalue;;) {
3df9bec5
LP
928 _cleanup_free_ char *w = NULL, *normalized = NULL;
929 const char *domain;
930 bool is_route;
931
932 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
933 if (r == -ENOMEM)
934 return log_oom();
3df9bec5 935 if (r < 0) {
d96edb2c 936 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 937 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 938 return 0;
3df9bec5
LP
939 }
940 if (r == 0)
d96edb2c 941 return 0;
3df9bec5
LP
942
943 is_route = w[0] == '~';
944 domain = is_route ? w + 1 : w;
945
946 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
947 /* If the root domain appears as is, or the special token "*" is found, we'll
948 * consider this as routing domain, unconditionally. */
3df9bec5 949 is_route = true;
ab24039f
ZJS
950 domain = "."; /* make sure we don't allow empty strings, thus write the root
951 * domain as "." */
3df9bec5 952 } else {
7470cc4c 953 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 954 if (r < 0) {
d96edb2c 955 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 956 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
957 continue;
958 }
959
960 domain = normalized;
961
962 if (is_localhost(domain)) {
d96edb2c 963 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
964 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
965 domain);
37de2509 966 continue;
3df9bec5 967 }
37de2509 968 }
40274ed6 969
5e2a51d5 970 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
cf453507
YW
971 r = ordered_set_put_strdup(set, domain);
972 if (r == -EEXIST)
973 continue;
09451975
LP
974 if (r < 0)
975 return log_oom();
40274ed6 976 }
6192b846
TG
977}
978
1ac608c9
LP
979int config_parse_hostname(
980 const char *unit,
981 const char *filename,
982 unsigned line,
983 const char *section,
984 unsigned section_line,
985 const char *lvalue,
986 int ltype,
987 const char *rvalue,
988 void *data,
989 void *userdata) {
990
6528693a 991 char **hostname = data;
a7d0ef44
SS
992 int r;
993
994 assert(filename);
995 assert(lvalue);
996 assert(rvalue);
b40b8b06 997 assert(data);
a7d0ef44 998
b40b8b06
YW
999 if (isempty(rvalue)) {
1000 *hostname = mfree(*hostname);
1001 return 0;
1002 }
a7d0ef44 1003
b40b8b06 1004 if (!hostname_is_valid(rvalue, 0)) {
d96edb2c 1005 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1006 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1007 return 0;
1008 }
1009
b40b8b06 1010 r = dns_name_is_valid(rvalue);
6528693a 1011 if (r < 0) {
d96edb2c 1012 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1013 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1014 return 0;
1015 }
1016 if (r == 0) {
d96edb2c 1017 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1018 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1019 return 0;
1020 }
1021
b40b8b06 1022 return free_and_strdup_warn(hostname, rvalue);
a7d0ef44 1023}
8eb9058d
LP
1024
1025int config_parse_timezone(
1026 const char *unit,
1027 const char *filename,
1028 unsigned line,
1029 const char *section,
1030 unsigned section_line,
1031 const char *lvalue,
1032 int ltype,
1033 const char *rvalue,
1034 void *data,
1035 void *userdata) {
1036
b40b8b06 1037 char **tz = data;
8eb9058d
LP
1038 int r;
1039
1040 assert(filename);
1041 assert(lvalue);
1042 assert(rvalue);
b40b8b06 1043 assert(data);
8eb9058d 1044
b40b8b06
YW
1045 if (isempty(rvalue)) {
1046 *tz = mfree(*tz);
1047 return 0;
1048 }
8eb9058d 1049
b40b8b06
YW
1050 r = verify_timezone(rvalue, LOG_WARNING);
1051 if (r < 0) {
1052 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1053 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1054 return 0;
1055 }
1056
b40b8b06 1057 return free_and_strdup_warn(tz, rvalue);
8eb9058d 1058}
1a04db0f 1059
53253824
SS
1060int config_parse_dns(
1061 const char *unit,
1062 const char *filename,
1063 unsigned line,
1064 const char *section,
1065 unsigned section_line,
1066 const char *lvalue,
1067 int ltype,
1068 const char *rvalue,
1069 void *data,
1070 void *userdata) {
1071
1072 Network *n = userdata;
1073 int r;
1074
1075 assert(filename);
1076 assert(lvalue);
1077 assert(rvalue);
5aafd5b1 1078 assert(n);
53253824 1079
d96edb2c 1080 if (isempty(rvalue)) {
e77bd3fd
YW
1081 for (unsigned i = 0; i < n->n_dns; i++)
1082 in_addr_full_free(n->dns[i]);
d96edb2c
YW
1083 n->dns = mfree(n->dns);
1084 n->n_dns = 0;
1085 return 0;
1086 }
1087
1088 for (const char *p = rvalue;;) {
e77bd3fd 1089 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 1090 _cleanup_free_ char *w = NULL;
e77bd3fd 1091 struct in_addr_full **m;
53253824 1092
d96edb2c 1093 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
1094 if (r == -ENOMEM)
1095 return log_oom();
1096 if (r < 0) {
d96edb2c 1097 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1098 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 1099 return 0;
53253824 1100 }
5512a963 1101 if (r == 0)
d96edb2c 1102 return 0;
53253824 1103
e77bd3fd 1104 r = in_addr_full_new_from_string(w, &dns);
53253824 1105 if (r < 0) {
d96edb2c 1106 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1107 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1108 continue;
1109 }
1110
e77bd3fd
YW
1111 if (IN_SET(dns->port, 53, 853))
1112 dns->port = 0;
1113
1114 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 1115 if (!m)
53253824
SS
1116 return log_oom();
1117
e77bd3fd 1118 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 1119 n->dns = m;
53253824 1120 }
53253824
SS
1121}
1122
8a516214
LP
1123int config_parse_dnssec_negative_trust_anchors(
1124 const char *unit,
1125 const char *filename,
1126 unsigned line,
1127 const char *section,
1128 unsigned section_line,
1129 const char *lvalue,
1130 int ltype,
1131 const char *rvalue,
1132 void *data,
1133 void *userdata) {
1134
5aafd5b1 1135 Set **nta = data;
8a516214
LP
1136 int r;
1137
5aafd5b1 1138 assert(filename);
8a516214
LP
1139 assert(lvalue);
1140 assert(rvalue);
5aafd5b1 1141 assert(nta);
8a516214
LP
1142
1143 if (isempty(rvalue)) {
5aafd5b1 1144 *nta = set_free_free(*nta);
8a516214
LP
1145 return 0;
1146 }
1147
d96edb2c 1148 for (const char *p = rvalue;;) {
8a516214
LP
1149 _cleanup_free_ char *w = NULL;
1150
1151 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1152 if (r == -ENOMEM)
1153 return log_oom();
8a516214 1154 if (r < 0) {
d96edb2c 1155 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1156 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1157 return 0;
8a516214
LP
1158 }
1159 if (r == 0)
d96edb2c 1160 return 0;
8a516214
LP
1161
1162 r = dns_name_is_valid(w);
1163 if (r <= 0) {
d96edb2c 1164 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1165 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1166 continue;
1167 }
1168
5aafd5b1 1169 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1170 if (r < 0)
1171 return log_oom();
8a516214 1172 }
8a516214 1173}
b2a81c0b 1174
26575990
LP
1175int config_parse_ntp(
1176 const char *unit,
1177 const char *filename,
1178 unsigned line,
1179 const char *section,
1180 unsigned section_line,
1181 const char *lvalue,
1182 int ltype,
1183 const char *rvalue,
1184 void *data,
1185 void *userdata) {
1186
1187 char ***l = data;
1188 int r;
1189
5aafd5b1 1190 assert(filename);
26575990
LP
1191 assert(lvalue);
1192 assert(rvalue);
5aafd5b1 1193 assert(l);
26575990
LP
1194
1195 if (isempty(rvalue)) {
1196 *l = strv_free(*l);
1197 return 0;
1198 }
1199
d96edb2c 1200 for (const char *p = rvalue;;) {
26575990
LP
1201 _cleanup_free_ char *w = NULL;
1202
d96edb2c 1203 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1204 if (r == -ENOMEM)
1205 return log_oom();
1206 if (r < 0) {
d96edb2c 1207 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1208 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1209 return 0;
26575990
LP
1210 }
1211 if (r == 0)
d96edb2c 1212 return 0;
26575990
LP
1213
1214 r = dns_name_is_valid_or_address(w);
1215 if (r <= 0) {
d96edb2c 1216 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1217 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1218 continue;
af1c0de0
SS
1219 }
1220
c448459d
ZJS
1221 if (strv_length(*l) > MAX_NTP_SERVERS) {
1222 log_syntax(unit, LOG_WARNING, filename, line, 0,
1223 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1224 MAX_NTP_SERVERS, w);
d96edb2c 1225 return 0;
c448459d
ZJS
1226 }
1227
1228 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1229 if (r < 0)
1230 return log_oom();
af1c0de0 1231 }
af1c0de0
SS
1232}
1233
4ac77d63
YW
1234int config_parse_required_for_online(
1235 const char *unit,
1236 const char *filename,
1237 unsigned line,
1238 const char *section,
1239 unsigned section_line,
1240 const char *lvalue,
1241 int ltype,
1242 const char *rvalue,
1243 void *data,
1244 void *userdata) {
1245
5aafd5b1 1246 Network *network = userdata;
75cd4a5d 1247 LinkOperationalStateRange range;
4ac77d63
YW
1248 bool required = true;
1249 int r;
1250
5aafd5b1
YW
1251 assert(filename);
1252 assert(lvalue);
1253 assert(rvalue);
1254 assert(network);
1255
4ac77d63 1256 if (isempty(rvalue)) {
7c644a69 1257 network->required_for_online = -1;
75cd4a5d 1258 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1259 return 0;
1260 }
1261
75cd4a5d
DDM
1262 r = parse_operational_state_range(rvalue, &range);
1263 if (r < 0) {
4ac77d63
YW
1264 r = parse_boolean(rvalue);
1265 if (r < 0) {
d96edb2c 1266 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1267 "Failed to parse %s= setting, ignoring assignment: %s",
1268 lvalue, rvalue);
1269 return 0;
1270 }
1271
1272 required = r;
75cd4a5d 1273 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1274 }
1275
1276 network->required_for_online = required;
75cd4a5d 1277 network->required_operstate_for_online = range;
4ac77d63
YW
1278
1279 return 0;
1280}
7da377ef 1281
f0c09831
YW
1282int config_parse_link_group(
1283 const char *unit,
1284 const char *filename,
1285 unsigned line,
1286 const char *section,
1287 unsigned section_line,
1288 const char *lvalue,
1289 int ltype,
1290 const char *rvalue,
1291 void *data,
1292 void *userdata) {
1293
1294 Network *network = userdata;
1295 int r;
10af8bb2 1296 int32_t group;
f0c09831
YW
1297
1298 assert(filename);
1299 assert(lvalue);
1300 assert(rvalue);
1301 assert(network);
1302
1303 if (isempty(rvalue)) {
10af8bb2 1304 network->group = -1;
f0c09831
YW
1305 return 0;
1306 }
1307
10af8bb2 1308 r = safe_atoi32(rvalue, &group);
f0c09831
YW
1309 if (r < 0) {
1310 log_syntax(unit, LOG_WARNING, filename, line, r,
1311 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1312 return 0;
1313 }
1314
10af8bb2
SB
1315 if (group < 0) {
1316 log_syntax(unit, LOG_WARNING, filename, line, r,
1317 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1318 return 0;
1319 }
1320
1321 network->group = group;
f0c09831
YW
1322 return 0;
1323}
1324
6706ce2f
YW
1325int config_parse_ignore_carrier_loss(
1326 const char *unit,
1327 const char *filename,
1328 unsigned line,
1329 const char *section,
1330 unsigned section_line,
1331 const char *lvalue,
1332 int ltype,
1333 const char *rvalue,
1334 void *data,
1335 void *userdata) {
1336
1337 Network *network = userdata;
1338 usec_t usec;
1339 int r;
1340
1341 assert(filename);
1342 assert(lvalue);
1343 assert(rvalue);
1344 assert(network);
1345
1346 if (isempty(rvalue)) {
1347 network->ignore_carrier_loss_set = false;
1348 return 0;
1349 }
1350
1351 r = parse_boolean(rvalue);
1352 if (r >= 0) {
1353 network->ignore_carrier_loss_set = true;
1354 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1355 return 0;
1356 }
1357
1358 r = parse_sec(rvalue, &usec);
1359 if (r < 0) {
1360 log_syntax(unit, LOG_WARNING, filename, line, r,
1361 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1362 return 0;
1363 }
1364
1365 network->ignore_carrier_loss_set = true;
1366 network->ignore_carrier_loss_usec = usec;
1367 return 0;
1368}
1369
8430841b
L
1370DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1371 "Failed to parse RequiredFamilyForOnline= setting");
1372
7da377ef
SS
1373DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1374 "Failed to parse KeepConfiguration= setting");
1375
1376static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1377 [KEEP_CONFIGURATION_NO] = "no",
1378 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1379 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1380 [KEEP_CONFIGURATION_STATIC] = "static",
1381 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1382};
1383
1384DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9
YW
1385
1386static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1387 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1388 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1389 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1390 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1391};
1392
1393DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1394DEFINE_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
1395
1396static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1397 [ACTIVATION_POLICY_UP] = "up",
1398 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1399 [ACTIVATION_POLICY_MANUAL] = "manual",
1400 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1401 [ACTIVATION_POLICY_DOWN] = "down",
1402 [ACTIVATION_POLICY_BOUND] = "bound",
1403};
1404
1405DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1406DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");