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