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