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