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