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