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