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