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