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