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