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