]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
zsh: remove _files prefixes
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
f579559b 2
a0b191b7 3#include <unistd.h>
69a93e7d 4
b5efdb8a 5#include "alloc-util.h"
baa3fadf 6#include "condition.h"
f579559b
TG
7#include "conf-files.h"
8#include "conf-parser.h"
88295a05 9#include "in-addr-util.h"
7e19cc54 10#include "net-condition.h"
c918b70a 11#include "netdev/macvlan.h"
baa3fadf 12#include "netif-sriov.h"
cd7d732d 13#include "network-util.h"
093e3533 14#include "networkd-address.h"
1cf40697 15#include "networkd-address-label.h"
9671ae9d 16#include "networkd-bridge-fdb.h"
ff9e0783 17#include "networkd-bridge-mdb.h"
22d37e5d 18#include "networkd-dhcp-common.h"
c517a49b 19#include "networkd-dhcp-server-static-lease.h"
14d9ab9d 20#include "networkd-ipv6-proxy-ndp.h"
23f53b99 21#include "networkd-manager.h"
3773eb54 22#include "networkd-ndisc.h"
1939ebeb 23#include "networkd-neighbor.h"
3ffd4af2 24#include "networkd-network.h"
75156ccb 25#include "networkd-nexthop.h"
b5ce4047 26#include "networkd-radv.h"
3b6a3bde 27#include "networkd-route.h"
ca183bf8 28#include "networkd-routing-policy-rule.h"
baa3fadf 29#include "ordered-set.h"
6bedfcbb 30#include "parse-util.h"
6b783209 31#include "path-util.h"
3a67b8bb 32#include "qdisc.h"
4f1ac4a3 33#include "radv-internal.h"
8a516214 34#include "set.h"
cebe1257 35#include "socket-util.h"
8fcde012 36#include "stat-util.h"
8b43440b 37#include "string-table.h"
07630cea 38#include "string-util.h"
700f1186 39#include "strv.h"
3a67b8bb 40#include "tclass.h"
f579559b 41
a85f73fa
YW
42DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
43 network_hash_ops,
44 char, string_hash_func, string_compare_func,
45 Network, network_unref);
46
919aeb66
YW
47DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
48 stacked_netdevs_hash_ops,
49 char, string_hash_func, string_compare_func,
50 NetDev, netdev_unref);
51
8f9bdeab 52static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret) {
cebe1257
YW
53 const char *kind_string;
54 NetDev *netdev;
55 int r;
56
96db6412
YW
57 /* For test-networkd-conf, the check must be earlier than the assertions. */
58 if (!name)
59 return 0;
60
cebe1257
YW
61 assert(network);
62 assert(network->manager);
63 assert(network->filename);
8f9bdeab 64 assert(ret);
cebe1257 65
cebe1257
YW
66 if (kind == _NETDEV_KIND_TUNNEL)
67 kind_string = "tunnel";
68 else {
69 kind_string = netdev_kind_to_string(kind);
70 if (!kind_string)
8f9bdeab
YW
71 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
72 "%s: Invalid NetDev kind of %s, ignoring assignment.",
73 network->filename, name);
cebe1257
YW
74 }
75
76 r = netdev_get(network->manager, name, &netdev);
77 if (r < 0)
8f9bdeab
YW
78 return log_warning_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
79 network->filename, name);
cebe1257
YW
80
81 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
82 IN_SET(netdev->kind,
bc945c2b 83 NETDEV_KIND_ERSPAN,
cebe1257
YW
84 NETDEV_KIND_GRE,
85 NETDEV_KIND_GRETAP,
86 NETDEV_KIND_IP6GRE,
87 NETDEV_KIND_IP6GRETAP,
9282f75b 88 NETDEV_KIND_IP6TNL,
bc945c2b
YW
89 NETDEV_KIND_IPIP,
90 NETDEV_KIND_SIT,
91 NETDEV_KIND_VTI,
92 NETDEV_KIND_VTI6)))
8f9bdeab
YW
93 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
94 "%s: NetDev %s is not a %s, ignoring assignment",
95 network->filename, name, kind_string);
cebe1257 96
8f9bdeab 97 *ret = netdev_ref(netdev);
cebe1257
YW
98 return 1;
99}
100
101static int network_resolve_stacked_netdevs(Network *network) {
102 void *name, *kind;
cebe1257
YW
103 int r;
104
105 assert(network);
106
90e74a66 107 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names) {
cebe1257
YW
108 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
109
8f9bdeab 110 if (network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev) <= 0)
cebe1257
YW
111 continue;
112
919aeb66 113 r = hashmap_ensure_put(&network->stacked_netdevs, &stacked_netdevs_hash_ops, netdev->ifname, netdev);
dcd46cc4 114 if (r == -ENOMEM)
cebe1257 115 return log_oom();
cebe1257 116 if (r < 0)
8f9bdeab
YW
117 log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
118 network->filename, (const char *) name);
cebe1257 119
919aeb66 120 TAKE_PTR(netdev);
cebe1257
YW
121 }
122
123 return 0;
124}
125
96db6412 126int network_verify(Network *network) {
50783f91
YW
127 int r;
128
0321cea7 129 assert(network);
ea853de5 130 assert(network->manager);
0321cea7
YW
131 assert(network->filename);
132
5722fb89 133 if (net_match_is_empty(&network->match) && !network->conditions)
dade7349
ZJS
134 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
135 "%s: No valid settings found in the [Match] section, ignoring file. "
136 "To match all interfaces, add Name=* in the [Match] section.",
137 network->filename);
84ea567e 138
cebe1257 139 /* skip out early if configuration does not match the environment */
a0b191b7 140 if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
cebe1257 141 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
142 "%s: Conditions in the file do not match the system environment, skipping.",
143 network->filename);
cebe1257 144
57aef9d7
YW
145 if (network->keep_master) {
146 if (network->batadv_name)
147 log_warning("%s: BatmanAdvanced= set with KeepMaster= enabled, ignoring BatmanAdvanced=.",
148 network->filename);
149 if (network->bond_name)
150 log_warning("%s: Bond= set with KeepMaster= enabled, ignoring Bond=.",
151 network->filename);
152 if (network->bridge_name)
153 log_warning("%s: Bridge= set with KeepMaster= enabled, ignoring Bridge=.",
154 network->filename);
155 if (network->vrf_name)
156 log_warning("%s: VRF= set with KeepMaster= enabled, ignoring VRF=.",
157 network->filename);
158
159 network->batadv_name = mfree(network->batadv_name);
160 network->bond_name = mfree(network->bond_name);
161 network->bridge_name = mfree(network->bridge_name);
162 network->vrf_name = mfree(network->vrf_name);
163 }
164
c0267a59 165 (void) network_resolve_netdev_one(network, network->batadv_name, NETDEV_KIND_BATADV, &network->batadv);
cebe1257
YW
166 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
167 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
168 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
8f9bdeab
YW
169 r = network_resolve_stacked_netdevs(network);
170 if (r < 0)
171 return r;
cebe1257
YW
172
173 /* Free unnecessary entries. */
c0267a59 174 network->batadv_name = mfree(network->batadv_name);
cebe1257
YW
175 network->bond_name = mfree(network->bond_name);
176 network->bridge_name = mfree(network->bridge_name);
177 network->vrf_name = mfree(network->vrf_name);
04b7949e 178 network->stacked_netdev_names = hashmap_free(network->stacked_netdev_names);
cebe1257 179
0321cea7
YW
180 if (network->bond) {
181 /* Bonding slave does not support addressing. */
0321cea7 182 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
183 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
184 network->filename);
0321cea7
YW
185 network->link_local = ADDRESS_FAMILY_NO;
186 }
9cd9fc8f 187 if (!ordered_hashmap_isempty(network->addresses_by_section))
ab24039f
ZJS
188 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
189 network->filename);
2a54a044 190 if (!hashmap_isempty(network->routes_by_section))
ab24039f
ZJS
191 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
192 network->filename);
9cd9fc8f 193
ebd96906 194 network->addresses_by_section = ordered_hashmap_free(network->addresses_by_section);
74c301b9 195 network->routes_by_section = hashmap_free(network->routes_by_section);
0321cea7
YW
196 }
197
c918b70a
TY
198 if (network->link_local < 0) {
199 network->link_local = ADDRESS_FAMILY_IPV6;
200
57aef9d7 201 if (network->keep_master || network->bridge)
c918b70a
TY
202 network->link_local = ADDRESS_FAMILY_NO;
203 else {
204 NetDev *netdev;
205
206 HASHMAP_FOREACH(netdev, network->stacked_netdevs) {
207 MacVlan *m;
208
209 if (netdev->kind == NETDEV_KIND_MACVLAN)
210 m = MACVLAN(netdev);
211 else if (netdev->kind == NETDEV_KIND_MACVTAP)
212 m = MACVTAP(netdev);
213 else
214 continue;
215
216 if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU)
217 network->link_local = ADDRESS_FAMILY_NO;
218
219 /* There won't be a passthru MACVLAN/MACVTAP if there's already one in another mode */
220 break;
221 }
222 }
223 }
224
75d5abd2
YW
225 if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE)
226 SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false);
8f191801 227
9e1432d5
YW
228 if (in6_addr_is_set(&network->ipv6ll_stable_secret) &&
229 network->ipv6ll_address_gen_mode < 0)
230 network->ipv6ll_address_gen_mode = IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
231
14d9ab9d 232 network_adjust_ipv6_proxy_ndp(network);
52672db3 233 network_adjust_ndisc(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 244 if (network->dhcp_critical >= 0) {
ea853de5
YW
245 if (network->keep_configuration >= 0) {
246 if (network->manager->keep_configuration < 0)
247 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
248 "Ignoring CriticalConnection=.", network->filename);
249 } else if (network->dhcp_critical)
7da377ef
SS
250 /* CriticalConnection=yes also preserve foreign static configurations. */
251 network->keep_configuration = KEEP_CONFIGURATION_YES;
252 else
80060352 253 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef
SS
254 }
255
61135582
DS
256 if (!strv_isempty(network->bind_carrier)) {
257 if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND))
258 log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. "
259 "Setting ActivationPolicy=bound.", network->filename);
260 network->activation_policy = ACTIVATION_POLICY_BOUND;
261 } else if (network->activation_policy == ACTIVATION_POLICY_BOUND) {
262 log_warning("%s: ActivationPolicy=bound requires BindCarrier=. "
263 "Ignoring ActivationPolicy=bound.", network->filename);
264 network->activation_policy = ACTIVATION_POLICY_UP;
265 }
266
267 if (network->activation_policy == _ACTIVATION_POLICY_INVALID)
268 network->activation_policy = ACTIVATION_POLICY_UP;
269
270 if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
6706ce2f
YW
271 if (network->ignore_carrier_loss_set && network->ignore_carrier_loss_usec < USEC_INFINITY)
272 log_warning("%s: IgnoreCarrierLoss=no or finite timespan conflicts with ActivationPolicy=always-up. "
273 "Setting IgnoreCarrierLoss=yes.", network->filename);
274 network->ignore_carrier_loss_set = true;
275 network->ignore_carrier_loss_usec = USEC_INFINITY;
61135582
DS
276 }
277
27438545 278 if (!network->ignore_carrier_loss_set) /* Set implied default. */
6706ce2f 279 network->ignore_carrier_loss_usec = network->configure_without_carrier ? USEC_INFINITY : 0;
61135582 280
7c644a69
DS
281 if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) {
282 if (network->required_for_online < 0 ||
283 (network->required_for_online == true && network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN)) {
284 log_debug("%s: Setting RequiredForOnline=no because ActivationPolicy=%s.", network->filename,
285 activation_policy_to_string(network->activation_policy));
286 network->required_for_online = false;
287 } else if (network->required_for_online == true)
288 log_warning("%s: RequiredForOnline=yes and ActivationPolicy=%s, "
289 "this may cause a delay at boot.", network->filename,
290 activation_policy_to_string(network->activation_policy));
291 }
292
293 if (network->required_for_online < 0)
294 network->required_for_online = true;
295
7da377ef 296 if (network->keep_configuration < 0)
80060352 297 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef 298
50783f91
YW
299 r = network_drop_invalid_addresses(network);
300 if (r < 0)
61ec7bea 301 return r; /* network_drop_invalid_addresses() logs internally. */
13ffa39f 302 network_drop_invalid_routes(network);
015b2432
YW
303 r = network_drop_invalid_nexthops(network);
304 if (r < 0)
305 return r;
9671ae9d 306 network_drop_invalid_bridge_fdb_entries(network);
ff9e0783 307 network_drop_invalid_bridge_mdb_entries(network);
aa9626ee
YW
308 r = network_drop_invalid_neighbors(network);
309 if (r < 0)
310 return r;
13ffa39f 311 network_drop_invalid_address_labels(network);
13ffa39f 312 network_drop_invalid_routing_policy_rules(network);
3a67b8bb
YW
313 network_drop_invalid_qdisc(network);
314 network_drop_invalid_tclass(network);
41ce9d76 315 r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section);
e217e22a 316 if (r < 0)
61ec7bea 317 return r; /* sr_iov_drop_invalid_sections() logs internally. */
c517a49b 318 network_drop_invalid_static_leases(network);
518cd6b5 319
0321cea7
YW
320 return 0;
321}
322
7f06b3e1 323int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
838b2f7a 324 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 325 _cleanup_(network_unrefp) Network *network = NULL;
047a0dac 326 const char *dropin_dirname;
838b2f7a 327 char *d;
f579559b
TG
328 int r;
329
bf1bc670
TA
330 assert(manager);
331 assert(filename);
332
4e54a17d 333 r = null_or_empty_path(filename);
4e54a17d 334 if (r < 0)
61ec7bea 335 return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
4e54a17d 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
6b783209
W
345 r = path_extract_filename(filename, &name);
346 if (r < 0)
347 return log_warning_errno(r, "Failed to extract file name of \"%s\": %m", filename);
838b2f7a
YW
348
349 d = strrchr(name, '.');
350 if (!d)
61ec7bea 351 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file name: %s", filename);
838b2f7a
YW
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,
3255bda6 369 .required_operstate_for_online = LINK_OPERSTATE_RANGE_INVALID,
61135582 370 .activation_policy = _ACTIVATION_POLICY_INVALID,
cee68339 371 .group = -1,
db5756f3
YW
372 .arp = -1,
373 .multicast = -1,
374 .allmulticast = -1,
937e305e 375 .promiscuous = -1,
db5756f3 376
ea853de5 377 .keep_configuration = manager->keep_configuration,
db5756f3 378
418f2dc7
YW
379 .use_domains = _USE_DOMAINS_INVALID,
380
7a169cb4 381 .compat_dhcp_use_domains = _USE_DOMAINS_INVALID,
9646ffe2 382 .compat_dhcp_use_dns = -1,
d12fb2bc 383 .compat_dhcp_use_ntp = -1,
7a169cb4 384
4e26a5ba 385 .dhcp_duid.type = _DUID_TYPE_INVALID,
7da377ef 386 .dhcp_critical = -1,
d12fb2bc 387 .dhcp_use_ntp = -1,
d7b04506 388 .dhcp_routes_to_ntp = true,
299d578f 389 .dhcp_use_sip = true,
edb88a72 390 .dhcp_use_captive_portal = true,
9646ffe2 391 .dhcp_use_dns = -1,
86938158 392 .dhcp_use_dnr = -1,
70570306 393 .dhcp_routes_to_dns = true,
7a169cb4 394 .dhcp_use_domains = _USE_DOMAINS_INVALID,
17f9c355
YW
395 .dhcp_use_hostname = true,
396 .dhcp_use_routes = true,
589397a2 397 .dhcp_use_gateway = -1,
17f9c355 398 .dhcp_send_hostname = true,
5f3b5f19 399 .dhcp_send_release = true,
17f9c355 400 .dhcp_route_metric = DHCP_ROUTE_METRIC,
cf289b14 401 .dhcp_use_rapid_commit = -1,
f90635f1 402 .dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
17f9c355 403 .dhcp_route_table = RT_TABLE_MAIN,
db5756f3 404 .dhcp_ip_service_type = -1,
e70eca9b 405 .dhcp_broadcast = -1,
fc35a9f8 406 .dhcp_ipv6_only_mode = -1,
a61869d4 407 .dhcp_6rd_prefix_route_type = RTN_UNREACHABLE,
17f9c355 408
1536b7b2 409 .dhcp6_use_address = true,
0f5ef9b6 410 .dhcp6_use_pd_prefix = true,
9646ffe2 411 .dhcp6_use_dns = -1,
c691f9d9 412 .dhcp6_use_dnr = -1,
7a169cb4 413 .dhcp6_use_domains = _USE_DOMAINS_INVALID,
38ba3da0 414 .dhcp6_use_hostname = true,
d12fb2bc 415 .dhcp6_use_ntp = -1,
a75feb55 416 .dhcp6_use_captive_portal = true,
50ee1fec 417 .dhcp6_use_rapid_commit = true,
b90480c8 418 .dhcp6_send_hostname = true,
4e26a5ba 419 .dhcp6_duid.type = _DUID_TYPE_INVALID,
0e45721e 420 .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
b895aa5f 421 .dhcp6_send_release = true,
a61869d4 422 .dhcp6_pd_prefix_route_type = RTN_UNREACHABLE,
caa8ca42 423
a27588d4
YW
424 .dhcp_pd = -1,
425 .dhcp_pd_announce = true,
426 .dhcp_pd_assign = true,
427 .dhcp_pd_manage_temporary_address = true,
428 .dhcp_pd_subnet_id = -1,
429 .dhcp_pd_route_metric = DHCP6PD_ROUTE_METRIC,
9efa8a3c 430
21b6b87e 431 .dhcp_server_bind_to_interface = true,
2a71d57f
LP
432 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
433 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
434 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
17f9c355
YW
435 .dhcp_server_emit_router = true,
436 .dhcp_server_emit_timezone = true,
1fa0a4ef 437 .dhcp_server_rapid_commit = true,
a145343b 438 .dhcp_server_persist_leases = _DHCP_SERVER_PERSIST_LEASES_INVALID,
17f9c355 439
4f1ac4a3 440 .router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
c9e2c2da 441 .router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
17f9c355
YW
442 .router_emit_dns = true,
443 .router_emit_domains = true,
444
445 .use_bpdu = -1,
446 .hairpin = -1,
97f27f8a 447 .isolated = -1,
17f9c355
YW
448 .fast_leave = -1,
449 .allow_port_to_be_root = -1,
450 .unicast_flood = -1,
7f15b714 451 .multicast_flood = -1,
d3aa8b49 452 .multicast_to_unicast = -1,
7f15b714
TJ
453 .neighbor_suppression = -1,
454 .learning = -1,
1087623b
SS
455 .bridge_proxy_arp = -1,
456 .bridge_proxy_arp_wifi = -1,
17f9c355 457 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 458 .multicast_router = _MULTICAST_ROUTER_INVALID,
a434de60 459 .bridge_locked = -1,
08a26ecc 460 .bridge_mac_authentication_bypass = -1,
c88adbc0 461 .bridge_vlan_tunnel = -1,
17f9c355 462
228693af 463 .bridge_vlan_pvid = BRIDGE_VLAN_KEEP_PVID,
0b8d501c 464
17f9c355 465 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
c01b9b87 466 .lldp_multicast_mode = _SD_LLDP_MULTICAST_MODE_INVALID,
17f9c355 467
7ece6f58 468 .dns_default_route = -1,
17f9c355
YW
469 .llmnr = RESOLVE_SUPPORT_YES,
470 .mdns = RESOLVE_SUPPORT_NO,
471 .dnssec_mode = _DNSSEC_MODE_INVALID,
472 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
473
0321cea7 474 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 475 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 476 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 477
3976c430 478 .ip_forwarding = { -1, -1, },
94d76d07 479 .ipv4_accept_local = -1,
d75bf6cf 480 .ipv4_route_localnet = -1,
932ef6ec 481 .ipv6_privacy_extensions = _IPV6_PRIVACY_EXTENSIONS_INVALID,
17f9c355 482 .ipv6_dad_transmits = -1,
17f9c355 483 .ipv6_proxy_ndp = -1,
17f9c355 484 .proxy_arp = -1,
b4959550 485 .proxy_arp_pvlan = -1,
9c72e8f8 486 .ipv4_rp_filter = _IP_REVERSE_PATH_FILTER_INVALID,
d865abf9 487 .ipv4_force_igmp_version = _IPV4_FORCE_IGMP_VERSION_INVALID,
10a76844 488 .mpls_input = -1,
db5756f3 489
52672db3 490 .ndisc = -1,
6df00594 491 .ndisc_use_redirect = true,
9646ffe2 492 .ndisc_use_dns = -1,
9c683c0e 493 .ndisc_use_dnr = -1,
52672db3
YW
494 .ndisc_use_gateway = true,
495 .ndisc_use_captive_portal = true,
496 .ndisc_use_route_prefix = true,
497 .ndisc_use_autonomous_prefix = true,
498 .ndisc_use_onlink_prefix = true,
499 .ndisc_use_mtu = true,
500 .ndisc_use_hop_limit = true,
501 .ndisc_use_reachable_time = true,
502 .ndisc_use_retransmission_time = true,
418f2dc7 503 .ndisc_use_domains = _USE_DOMAINS_INVALID,
52672db3
YW
504 .ndisc_route_table = RT_TABLE_MAIN,
505 .ndisc_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
506 .ndisc_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
507 .ndisc_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
508 .ndisc_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
c423be28 509
52aa38f1 510 .can_termination = -1,
72e65e6f
YW
511
512 .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
513 .ipoib_umcast = -1,
17f9c355 514 };
f579559b 515
4f9ff96a 516 r = config_parse_many(
947f59ba 517 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root = */ NULL,
4f9ff96a
LP
518 "Match\0"
519 "Link\0"
518cd6b5 520 "SR-IOV\0"
4f9ff96a
LP
521 "Network\0"
522 "Address\0"
523 "Neighbor\0"
524 "IPv6AddressLabel\0"
525 "RoutingPolicyRule\0"
526 "Route\0"
527 "NextHop\0"
528 "DHCP\0" /* compat */
529 "DHCPv4\0"
530 "DHCPv6\0"
a27588d4
YW
531 "DHCPv6PrefixDelegation\0" /* compat */
532 "DHCPPrefixDelegation\0"
4f9ff96a 533 "DHCPServer\0"
c517a49b 534 "DHCPServerStaticLease\0"
4f9ff96a
LP
535 "IPv6AcceptRA\0"
536 "IPv6NDPProxyAddress\0"
537 "Bridge\0"
538 "BridgeFDB\0"
3db468ea 539 "BridgeMDB\0"
4f9ff96a 540 "BridgeVLAN\0"
27ff0490 541 "IPv6SendRA\0"
4f9ff96a
LP
542 "IPv6PrefixDelegation\0"
543 "IPv6Prefix\0"
544 "IPv6RoutePrefix\0"
1925f829 545 "IPv6PREF64Prefix\0"
4f9ff96a
LP
546 "LLDP\0"
547 "TrafficControlQueueingDiscipline\0"
548 "CAN\0"
549 "QDisc\0"
550 "BFIFO\0"
551 "CAKE\0"
552 "ControlledDelay\0"
553 "DeficitRoundRobinScheduler\0"
554 "DeficitRoundRobinSchedulerClass\0"
d474aa51 555 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
556 "FairQueueing\0"
557 "FairQueueingControlledDelay\0"
8f6b6d70 558 "FlowQueuePIE\0"
4f9ff96a
LP
559 "GenericRandomEarlyDetection\0"
560 "HeavyHitterFilter\0"
561 "HierarchyTokenBucket\0"
562 "HierarchyTokenBucketClass\0"
2b9ced90 563 "ClassfulMultiQueueing\0"
3f14557c 564 "BandMultiQueueing\0"
4f9ff96a 565 "NetworkEmulator\0"
b12aaee5
SS
566 "PFIFO\0"
567 "PFIFOFast\0"
568 "PFIFOHeadDrop\0"
4f9ff96a 569 "PIE\0"
b12aaee5 570 "QuickFairQueueing\0"
4d7ddaf9 571 "QuickFairQueueingClass\0"
4f9ff96a
LP
572 "StochasticFairBlue\0"
573 "StochasticFairnessQueueing\0"
574 "TokenBucketFilter\0"
575 "TrivialLinkEqualizer\0",
576 config_item_perf_lookup, network_network_gperf_lookup,
577 CONFIG_PARSE_WARN,
578 network,
ead3a3fc 579 &network->stats_by_path,
a2640646 580 &network->dropins);
102bc043 581 if (r < 0)
61ec7bea 582 return r; /* config_parse_many() logs internally. */
f579559b 583
fa7cd711
YW
584 r = network_add_ipv4ll_route(network);
585 if (r < 0)
9202b567 586 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
fa7cd711 587
5d5003ab
YW
588 r = network_add_default_route_on_device(network);
589 if (r < 0)
9202b567
YW
590 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
591 network->filename);
5d5003ab 592
9202b567 593 r = network_verify(network);
9202b567 594 if (r < 0)
61ec7bea 595 return r; /* network_verify() logs internally. */
7f06b3e1 596
a85f73fa 597 r = ordered_hashmap_ensure_put(networks, &network_hash_ops, network->name, network);
dbffab87 598 if (r < 0)
61ec7bea 599 return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
dbffab87 600
b5b9b0e7 601 TAKE_PTR(network);
25da422b 602 log_syntax(/* unit = */ NULL, LOG_DEBUG, filename, /* config_line = */ 0, /* error = */ 0, "Successfully loaded.");
f579559b
TG
603 return 0;
604}
605
173c9f63 606int network_load(Manager *manager, OrderedHashmap **ret) {
477e73b5 607 _cleanup_strv_free_ char **files = NULL;
173c9f63 608 OrderedHashmap *networks = NULL;
f579559b
TG
609 int r;
610
611 assert(manager);
173c9f63 612 assert(ret);
f579559b 613
dc0d4078 614 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
615 if (r < 0)
616 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 617
036a8d50 618 STRV_FOREACH(f, files)
173c9f63 619 (void) network_load_one(manager, &networks, *f);
f579559b 620
173c9f63 621 *ret = TAKE_PTR(networks);
f579559b
TG
622 return 0;
623}
624
00c0a944
YW
625static bool network_netdev_equal(Network *a, Network *b) {
626 assert(a);
627 assert(b);
628
629 if (a->batadv != b->batadv ||
630 a->bridge != b->bridge ||
631 a->bond != b->bond ||
632 a->vrf != b->vrf ||
633 a->xfrm != b->xfrm)
634 return false;
635
636 if (hashmap_size(a->stacked_netdevs) != hashmap_size(b->stacked_netdevs))
637 return false;
638
639 NetDev *n;
640 HASHMAP_FOREACH(n, a->stacked_netdevs)
641 if (hashmap_get(b->stacked_netdevs, n->ifname) != n)
642 return false;
643
644 return true;
645}
646
7f06b3e1 647int network_reload(Manager *manager) {
a85f73fa 648 _cleanup_ordered_hashmap_free_ OrderedHashmap *new_networks = NULL;
7f06b3e1 649 Network *n, *old;
7f06b3e1
YW
650 int r;
651
652 assert(manager);
653
654 r = network_load(manager, &new_networks);
655 if (r < 0)
a85f73fa 656 return r;
7f06b3e1 657
90e74a66 658 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1 659 r = network_get_by_name(manager, n->name, &old);
8524db50 660 if (r < 0) {
00c0a944 661 log_debug("%s: Found new .network file.", n->filename);
8524db50
YW
662 continue;
663 }
7f06b3e1 664
8524db50 665 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
00c0a944
YW
666 log_debug("%s: Found updated .network file.", n->filename);
667 continue;
668 }
669
670 if (!network_netdev_equal(n, old)) {
671 log_debug("%s: Detected update of referenced .netdev file(s).", n->filename);
7f06b3e1 672 continue;
8524db50 673 }
7f06b3e1 674
00c0a944 675 /* Nothing updated, use the existing Network object, and drop the new one. */
7f06b3e1
YW
676 r = ordered_hashmap_replace(new_networks, old->name, old);
677 if (r < 0)
a85f73fa 678 return r;
7f06b3e1
YW
679
680 network_ref(old);
681 network_unref(n);
682 }
683
a85f73fa 684 ordered_hashmap_free_and_replace(manager->networks, new_networks);
7f06b3e1 685
fb126bb1
YW
686 r = manager_build_dhcp_pd_subnet_ids(manager);
687 if (r < 0)
688 return r;
689
690 r = manager_build_nexthop_ids(manager);
691 if (r < 0)
692 return r;
693
694 return 0;
7f06b3e1
YW
695}
696
a27588d4 697int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
1a4ca0e2
YW
698 Network *n;
699 int r;
700
701 assert(manager);
702
a27588d4 703 set_clear(manager->dhcp_pd_subnet_ids);
1a4ca0e2
YW
704
705 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
706 if (n->unmanaged)
707 continue;
708
a27588d4 709 if (!n->dhcp_pd)
1a4ca0e2
YW
710 continue;
711
a27588d4 712 if (n->dhcp_pd_subnet_id < 0)
1a4ca0e2
YW
713 continue;
714
a27588d4 715 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
1a4ca0e2
YW
716 if (r < 0)
717 return r;
718 }
719
720 return 0;
721}
722
35ac3b76 723static Network *network_free(Network *network) {
f579559b 724 if (!network)
35ac3b76 725 return NULL;
f579559b 726
54e0cfc4 727 free(network->name);
f579559b 728 free(network->filename);
54e0cfc4 729 free(network->description);
a2640646 730 strv_free(network->dropins);
8524db50 731 hashmap_free(network->stats_by_path);
f579559b 732
54e0cfc4 733 /* conditions */
5722fb89 734 net_match_clear(&network->match);
c4f58dea 735 condition_free_list(network->conditions);
f579559b 736
54e0cfc4
YW
737 /* link settings */
738 strv_free(network->bind_carrier);
739
740 /* NTP */
741 strv_free(network->ntp);
742
743 /* DNS */
744 for (unsigned i = 0; i < network->n_dns; i++)
745 in_addr_full_free(network->dns[i]);
746 free(network->dns);
747 ordered_set_free(network->search_domains);
748 ordered_set_free(network->route_domains);
25a9bd72 749 set_free(network->dnssec_negative_trust_anchors);
54e0cfc4
YW
750
751 /* DHCP server */
11c38d3e
YA
752 free(network->dhcp_server_relay_agent_circuit_id);
753 free(network->dhcp_server_relay_agent_remote_id);
6278e428
YW
754 free(network->dhcp_server_boot_server_name);
755 free(network->dhcp_server_boot_filename);
54e0cfc4
YW
756 free(network->dhcp_server_timezone);
757 free(network->dhcp_server_uplink_name);
758 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
759 free(network->dhcp_server_emit[t].addresses);
760 ordered_hashmap_free(network->dhcp_server_send_options);
761 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
11c38d3e 762
54e0cfc4 763 /* DHCP client */
edb85f0d 764 free(network->dhcp_vendor_class_identifier);
7b8d23a9 765 free(network->dhcp_mudurl);
27cb34f5 766 free(network->dhcp_hostname);
d419ef02 767 free(network->dhcp_label);
6b000af4 768 set_free(network->dhcp_deny_listed_ip);
98ebef62 769 set_free(network->dhcp_allow_listed_ip);
54e0cfc4 770 strv_free(network->dhcp_user_class);
5bc945be 771 set_free(network->dhcp_request_options);
54e0cfc4
YW
772 ordered_hashmap_free(network->dhcp_client_send_options);
773 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
4b3590c3 774 free(network->dhcp_netlabel);
fc289dd0 775 nft_set_context_clear(&network->dhcp_nft_set_context);
54e0cfc4
YW
776
777 /* DHCPv6 client */
3175a8c2 778 free(network->dhcp6_mudurl);
9968ca32 779 free(network->dhcp6_hostname);
f37f2a6b 780 strv_free(network->dhcp6_user_class);
ed0d1b2e 781 strv_free(network->dhcp6_vendor_class);
54e0cfc4
YW
782 set_free(network->dhcp6_request_options);
783 ordered_hashmap_free(network->dhcp6_client_send_options);
784 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
4b3590c3 785 free(network->dhcp6_netlabel);
fc289dd0 786 nft_set_context_clear(&network->dhcp6_nft_set_context);
c106cc36 787
54e0cfc4
YW
788 /* DHCP PD */
789 free(network->dhcp_pd_uplink_name);
790 set_free(network->dhcp_pd_tokens);
4b3590c3 791 free(network->dhcp_pd_netlabel);
fc289dd0 792 nft_set_context_clear(&network->dhcp_pd_nft_set_context);
cdd7812b 793
54e0cfc4 794 /* Router advertisement */
5e276772 795 ordered_set_free(network->router_search_domains);
cdd7812b 796 free(network->router_dns);
54e0cfc4
YW
797 free(network->router_uplink_name);
798
799 /* NDisc */
c995fa02
YW
800 set_free(network->ndisc_deny_listed_router);
801 set_free(network->ndisc_allow_listed_router);
802 set_free(network->ndisc_deny_listed_prefix);
803 set_free(network->ndisc_allow_listed_prefix);
804 set_free(network->ndisc_deny_listed_route_prefix);
805 set_free(network->ndisc_allow_listed_route_prefix);
54e0cfc4 806 set_free(network->ndisc_tokens);
4b3590c3 807 free(network->ndisc_netlabel);
fc289dd0 808 nft_set_context_clear(&network->ndisc_nft_set_context);
3bef724f 809
54e0cfc4
YW
810 /* LLDP */
811 free(network->lldp_mudurl);
812
813 /* netdev */
c0267a59 814 free(network->batadv_name);
cebe1257
YW
815 free(network->bridge_name);
816 free(network->bond_name);
817 free(network->vrf_name);
04b7949e 818 hashmap_free(network->stacked_netdev_names);
47e2dc31 819 netdev_unref(network->bridge);
47e2dc31 820 netdev_unref(network->bond);
6cb955c6 821 netdev_unref(network->vrf);
919aeb66 822 hashmap_free(network->stacked_netdevs);
326cb406 823
54e0cfc4 824 /* static configs */
6d1a69d0 825 set_free(network->ipv6_proxy_ndp_addresses);
ebd96906 826 ordered_hashmap_free(network->addresses_by_section);
74c301b9 827 hashmap_free(network->routes_by_section);
59ac53a6 828 ordered_hashmap_free(network->nexthops_by_section);
1b25b88f
YW
829 hashmap_free(network->bridge_fdb_entries_by_section);
830 hashmap_free(network->bridge_mdb_entries_by_section);
2a75f23b 831 ordered_hashmap_free(network->neighbors_by_section);
c95fa6ac 832 hashmap_free(network->address_labels_by_section);
10d78645
YW
833 hashmap_free(network->prefixes_by_section);
834 hashmap_free(network->route_prefixes_by_section);
835 hashmap_free(network->pref64_prefixes_by_section);
6c72e80a 836 hashmap_free(network->rules_by_section);
5c6e6f5a 837 hashmap_free(network->dhcp_static_leases_by_section);
d3af116a 838 ordered_hashmap_free(network->sr_iov_by_section);
9b294afa 839 hashmap_free(network->qdiscs_by_section);
541d0ed2 840 hashmap_free(network->tclasses_by_section);
6ae115c1 841
35ac3b76 842 return mfree(network);
f579559b
TG
843}
844
35ac3b76
YW
845DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
846
dbffab87
TG
847int network_get_by_name(Manager *manager, const char *name, Network **ret) {
848 Network *network;
849
850 assert(manager);
851 assert(name);
852 assert(ret);
853
715d398e 854 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
855 if (!network)
856 return -ENOENT;
857
858 *ret = network;
859
860 return 0;
861}
862
adfeee49 863bool network_has_static_ipv6_configurations(Network *network) {
439689c6 864 Address *address;
adfeee49 865 Route *route;
9671ae9d 866 BridgeFDB *fdb;
ff9e0783 867 BridgeMDB *mdb;
adfeee49 868 Neighbor *neighbor;
439689c6
SS
869
870 assert(network);
871
9cd9fc8f 872 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
439689c6
SS
873 if (address->family == AF_INET6)
874 return true;
adfeee49 875
2a54a044 876 HASHMAP_FOREACH(route, network->routes_by_section)
adfeee49
YW
877 if (route->family == AF_INET6)
878 return true;
879
9671ae9d 880 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
adfeee49
YW
881 if (fdb->family == AF_INET6)
882 return true;
883
ff9e0783 884 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
3db468ea
DM
885 if (mdb->family == AF_INET6)
886 return true;
887
aa9626ee 888 ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
3b5c5da7 889 if (neighbor->dst_addr.family == AF_INET6)
adfeee49
YW
890 return true;
891
d6a2a0f9 892 if (!hashmap_isempty(network->address_labels_by_section))
adfeee49
YW
893 return true;
894
ecb0e85e 895 if (!hashmap_isempty(network->prefixes_by_section))
adfeee49 896 return true;
d30081c2
YW
897
898 if (!hashmap_isempty(network->route_prefixes_by_section))
899 return true;
439689c6 900
1925f829
SS
901 if (!hashmap_isempty(network->pref64_prefixes_by_section))
902 return true;
903
439689c6
SS
904 return false;
905}
906
63481576
YW
907int config_parse_stacked_netdev(
908 const char *unit,
02b59d57
TG
909 const char *filename,
910 unsigned line,
911 const char *section,
912 unsigned section_line,
913 const char *lvalue,
914 int ltype,
915 const char *rvalue,
916 void *data,
917 void *userdata) {
63481576 918
95dba435
YW
919 _cleanup_free_ char *name = NULL;
920 NetDevKind kind = ltype;
99534007 921 Hashmap **h = ASSERT_PTR(data);
02b59d57
TG
922 int r;
923
924 assert(filename);
925 assert(lvalue);
926 assert(rvalue);
95dba435 927 assert(IN_SET(kind,
b90d0f83 928 NETDEV_KIND_IPOIB,
bc945c2b
YW
929 NETDEV_KIND_IPVLAN,
930 NETDEV_KIND_IPVTAP,
bc945c2b
YW
931 NETDEV_KIND_MACSEC,
932 NETDEV_KIND_MACVLAN,
933 NETDEV_KIND_MACVTAP,
934 NETDEV_KIND_VLAN,
935 NETDEV_KIND_VXLAN,
936 NETDEV_KIND_XFRM,
937 _NETDEV_KIND_TUNNEL));
54abf461 938
cebe1257 939 if (!ifname_valid(rvalue)) {
d96edb2c 940 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 941 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
942 return 0;
943 }
944
cebe1257
YW
945 name = strdup(rvalue);
946 if (!name)
947 return log_oom();
3e570042 948
04b7949e 949 r = hashmap_ensure_put(h, &string_hash_ops_free, name, INT_TO_PTR(kind));
6de530f2 950 if (r == -ENOMEM)
cebe1257 951 return log_oom();
83ec4592 952 if (r < 0)
d96edb2c 953 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
954 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
955 else if (r == 0)
956 log_syntax(unit, LOG_DEBUG, filename, line, r,
957 "NetDev '%s' specified twice, ignoring.", name);
958 else
0c7bd7ec 959 TAKE_PTR(name);
47e2dc31 960
fe6b2d55
TG
961 return 0;
962}
7951dea2 963
4ac77d63
YW
964int config_parse_required_for_online(
965 const char *unit,
966 const char *filename,
967 unsigned line,
968 const char *section,
969 unsigned section_line,
970 const char *lvalue,
971 int ltype,
972 const char *rvalue,
973 void *data,
974 void *userdata) {
975
99534007 976 Network *network = ASSERT_PTR(userdata);
4ac77d63
YW
977 int r;
978
5aafd5b1
YW
979 assert(filename);
980 assert(lvalue);
981 assert(rvalue);
5aafd5b1 982
4ac77d63 983 if (isempty(rvalue)) {
7c644a69 984 network->required_for_online = -1;
3255bda6 985 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_INVALID;
4ac77d63
YW
986 return 0;
987 }
988
ba04f957 989 r = parse_operational_state_range(rvalue, &network->required_operstate_for_online);
75cd4a5d 990 if (r < 0) {
4ac77d63
YW
991 r = parse_boolean(rvalue);
992 if (r < 0) {
d96edb2c 993 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
994 "Failed to parse %s= setting, ignoring assignment: %s",
995 lvalue, rvalue);
996 return 0;
997 }
998
ba04f957
YW
999 network->required_for_online = r;
1000 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1001 return 0;
4ac77d63
YW
1002 }
1003
ba04f957 1004 network->required_for_online = true;
4ac77d63
YW
1005 return 0;
1006}
7da377ef 1007
f0c09831
YW
1008int config_parse_link_group(
1009 const char *unit,
1010 const char *filename,
1011 unsigned line,
1012 const char *section,
1013 unsigned section_line,
1014 const char *lvalue,
1015 int ltype,
1016 const char *rvalue,
1017 void *data,
1018 void *userdata) {
1019
99534007 1020 Network *network = ASSERT_PTR(userdata);
f0c09831 1021 int r;
10af8bb2 1022 int32_t group;
f0c09831
YW
1023
1024 assert(filename);
1025 assert(lvalue);
1026 assert(rvalue);
f0c09831
YW
1027
1028 if (isempty(rvalue)) {
10af8bb2 1029 network->group = -1;
f0c09831
YW
1030 return 0;
1031 }
1032
10af8bb2 1033 r = safe_atoi32(rvalue, &group);
f0c09831
YW
1034 if (r < 0) {
1035 log_syntax(unit, LOG_WARNING, filename, line, r,
1036 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1037 return 0;
1038 }
1039
10af8bb2
SB
1040 if (group < 0) {
1041 log_syntax(unit, LOG_WARNING, filename, line, r,
1042 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1043 return 0;
1044 }
1045
1046 network->group = group;
f0c09831
YW
1047 return 0;
1048}
1049
6706ce2f
YW
1050int config_parse_ignore_carrier_loss(
1051 const char *unit,
1052 const char *filename,
1053 unsigned line,
1054 const char *section,
1055 unsigned section_line,
1056 const char *lvalue,
1057 int ltype,
1058 const char *rvalue,
1059 void *data,
1060 void *userdata) {
1061
99534007 1062 Network *network = ASSERT_PTR(userdata);
6706ce2f
YW
1063 usec_t usec;
1064 int r;
1065
1066 assert(filename);
1067 assert(lvalue);
1068 assert(rvalue);
6706ce2f
YW
1069
1070 if (isempty(rvalue)) {
1071 network->ignore_carrier_loss_set = false;
1072 return 0;
1073 }
1074
1075 r = parse_boolean(rvalue);
1076 if (r >= 0) {
1077 network->ignore_carrier_loss_set = true;
1078 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1079 return 0;
1080 }
1081
1082 r = parse_sec(rvalue, &usec);
1083 if (r < 0) {
1084 log_syntax(unit, LOG_WARNING, filename, line, r,
1085 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1086 return 0;
1087 }
1088
1089 network->ignore_carrier_loss_set = true;
1090 network->ignore_carrier_loss_usec = usec;
1091 return 0;
1092}
1093
80a89d1a
YW
1094int config_parse_keep_configuration(
1095 const char *unit,
1096 const char *filename,
1097 unsigned line,
1098 const char *section,
1099 unsigned section_line,
1100 const char *lvalue,
1101 int ltype,
1102 const char *rvalue,
1103 void *data,
1104 void *userdata) {
1105
1106 KeepConfiguration t, *k = ASSERT_PTR(data);
1107 Network *network = ASSERT_PTR(userdata);
1108
1109 if (isempty(rvalue)) {
1110 *k = ASSERT_PTR(network->manager)->keep_configuration;
1111 return 0;
1112 }
1113
1114 /* backward compatibility */
1115 if (streq(rvalue, "dhcp")) {
1116 *k = KEEP_CONFIGURATION_DYNAMIC;
1117 return 0;
1118 }
1119
1120 if (streq(rvalue, "dhcp-on-stop")) {
1121 *k = KEEP_CONFIGURATION_DYNAMIC_ON_STOP;
1122 return 0;
1123 }
1124
1125 t = keep_configuration_from_string(rvalue);
1126 if (t < 0)
1127 return log_syntax_parse_error(unit, filename, line, t, lvalue, rvalue);
1128
1129 *k = t;
1130 return 0;
1131}
1132
42efe5be 1133DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily);
7da377ef
SS
1134
1135static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
80a89d1a
YW
1136 [KEEP_CONFIGURATION_NO] = "no",
1137 [KEEP_CONFIGURATION_DYNAMIC_ON_STOP] = "dynamic-on-stop",
1138 [KEEP_CONFIGURATION_DYNAMIC] = "dynamic",
1139 [KEEP_CONFIGURATION_STATIC] = "static",
1140 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1141};
1142
1143DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9 1144
61135582 1145static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
b5a8440f
YW
1146 [ACTIVATION_POLICY_UP] = "up",
1147 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1148 [ACTIVATION_POLICY_MANUAL] = "manual",
61135582 1149 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
b5a8440f
YW
1150 [ACTIVATION_POLICY_DOWN] = "down",
1151 [ACTIVATION_POLICY_BOUND] = "bound",
61135582
DS
1152};
1153
1154DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
42efe5be 1155DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy);