1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "path-util.h"
26 #include "conf-files.h"
27 #include "conf-parser.h"
30 #include "networkd-netdev.h"
31 #include "networkd-link.h"
32 #include "network-internal.h"
34 static int network_load_one(Manager *manager, const char *filename) {
35 _cleanup_network_free_ Network *network = NULL;
36 _cleanup_fclose_ FILE *file = NULL;
44 file = fopen(filename, "re");
52 if (null_or_empty_fd(fileno(file))) {
53 log_debug("Skipping empty file: %s", filename);
57 network = new0(Network, 1);
61 network->manager = manager;
63 LIST_HEAD_INIT(network->static_addresses);
64 LIST_HEAD_INIT(network->static_routes);
65 LIST_HEAD_INIT(network->static_fdb_entries);
67 network->stacked_netdevs = hashmap_new(&string_hash_ops);
68 if (!network->stacked_netdevs)
71 network->addresses_by_section = hashmap_new(NULL);
72 if (!network->addresses_by_section)
75 network->routes_by_section = hashmap_new(NULL);
76 if (!network->routes_by_section)
79 network->fdb_entries_by_section = hashmap_new(NULL);
80 if (!network->fdb_entries_by_section)
83 network->filename = strdup(filename);
84 if (!network->filename)
87 network->dhcp = ADDRESS_FAMILY_NO;
88 network->dhcp_ntp = true;
89 network->dhcp_dns = true;
90 network->dhcp_hostname = true;
91 network->dhcp_routes = true;
92 network->dhcp_sendhost = true;
93 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
95 network->llmnr = LLMNR_SUPPORT_YES;
97 r = config_parse(NULL, filename, file,
107 config_item_perf_lookup, network_network_gperf_lookup,
108 false, false, true, network);
112 /* IPMasquerade=yes implies IPForward=yes */
113 if (network->ip_masquerade)
114 network->ip_forward |= ADDRESS_FAMILY_IPV4;
116 LIST_PREPEND(networks, manager->networks, network);
118 LIST_FOREACH(routes, route, network->static_routes) {
119 if (!route->family) {
120 log_warning("Route section without Gateway field configured in %s. "
121 "Ignoring", filename);
126 LIST_FOREACH(addresses, address, network->static_addresses) {
127 if (!address->family) {
128 log_warning("Address section without Address field configured in %s. "
129 "Ignoring", filename);
139 int network_load(Manager *manager) {
141 _cleanup_strv_free_ char **files = NULL;
147 while ((network = manager->networks))
148 network_free(network);
150 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
152 return log_error_errno(r, "Failed to enumerate network files: %m");
154 STRV_FOREACH_BACKWARDS(f, files) {
155 r = network_load_one(manager, *f);
163 void network_free(Network *network) {
173 free(network->filename);
175 free(network->match_mac);
176 free(network->match_path);
177 free(network->match_driver);
178 free(network->match_type);
179 free(network->match_name);
181 free(network->description);
182 free(network->dhcp_vendor_class_identifier);
186 strv_free(network->ntp);
187 strv_free(network->dns);
188 strv_free(network->domains);
190 netdev_unref(network->bridge);
192 netdev_unref(network->bond);
194 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
195 hashmap_remove(network->stacked_netdevs, netdev->ifname);
196 netdev_unref(netdev);
198 hashmap_free(network->stacked_netdevs);
200 while ((route = network->static_routes))
203 while ((address = network->static_addresses))
204 address_free(address);
206 while ((fdb_entry = network->static_fdb_entries))
207 fdb_entry_free(fdb_entry);
209 hashmap_free(network->addresses_by_section);
210 hashmap_free(network->routes_by_section);
211 hashmap_free(network->fdb_entries_by_section);
213 if (network->manager && network->manager->networks)
214 LIST_REMOVE(networks, network->manager->networks, network);
216 condition_free_list(network->match_host);
217 condition_free_list(network->match_virt);
218 condition_free_list(network->match_kernel);
219 condition_free_list(network->match_arch);
224 int network_get(Manager *manager, struct udev_device *device,
225 const char *ifname, const struct ether_addr *address,
232 LIST_FOREACH(networks, network, manager->networks) {
233 if (net_match_config(network->match_mac, network->match_path,
234 network->match_driver, network->match_type,
235 network->match_name, network->match_host,
236 network->match_virt, network->match_kernel,
239 udev_device_get_property_value(device, "ID_PATH"),
240 udev_device_get_driver(udev_device_get_parent(device)),
241 udev_device_get_property_value(device, "ID_NET_DRIVER"),
242 udev_device_get_devtype(device),
244 if (network->match_name) {
246 uint8_t name_assign_type = NET_NAME_UNKNOWN;
248 attr = udev_device_get_sysattr_value(device, "name_assign_type");
250 (void)safe_atou8(attr, &name_assign_type);
252 if (name_assign_type == NET_NAME_ENUM)
253 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
254 IFNAMSIZ, ifname, network->filename);
256 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
258 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
270 int network_apply(Manager *manager, Network *network, Link *link) {
273 link->network = network;
275 if (network->ipv4ll_route) {
278 r = route_new_static(network, 0, &route);
282 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
288 route->family = AF_INET;
289 route->dst_prefixlen = 16;
290 route->scope = RT_SCOPE_LINK;
291 route->metrics = IPV4LL_ROUTE_METRIC;
292 route->protocol = RTPROT_STATIC;
295 if (network->dns || network->ntp) {
304 int config_parse_netdev(const char *unit,
305 const char *filename,
308 unsigned section_line,
314 Network *network = userdata;
315 _cleanup_free_ char *kind_string = NULL;
326 kind_string = strdup(lvalue);
330 /* the keys are CamelCase versions of the kind */
331 for (p = kind_string; *p; p++)
334 kind = netdev_kind_from_string(kind_string);
335 if (kind == _NETDEV_KIND_INVALID) {
336 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
337 "Invalid NetDev kind: %s", lvalue);
341 r = netdev_get(network->manager, rvalue, &netdev);
343 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
344 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
348 if (netdev->kind != kind) {
349 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
350 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
355 case NETDEV_KIND_BRIDGE:
356 network->bridge = netdev;
359 case NETDEV_KIND_BOND:
360 network->bond = netdev;
363 case NETDEV_KIND_VLAN:
364 case NETDEV_KIND_MACVLAN:
365 case NETDEV_KIND_IPVLAN:
366 case NETDEV_KIND_VXLAN:
367 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
369 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
370 "Can not add VLAN '%s' to network: %s",
371 rvalue, strerror(-r));
377 assert_not_reached("Can not parse NetDev");
385 int config_parse_domains(const char *unit,
386 const char *filename,
389 unsigned section_line,
395 Network *network = userdata;
396 char ***domains = data;
400 r = config_parse_strv(unit, filename, line, section, section_line,
401 lvalue, ltype, rvalue, domains, userdata);
406 network->wildcard_domain = !!strv_find(*domains, "*");
408 STRV_FOREACH(domain, *domains) {
409 if (is_localhost(*domain))
410 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
411 else if (!hostname_is_valid(*domain)) {
412 if (!streq(*domain, "*"))
413 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
417 strv_remove(*domains, *domain);
419 /* We removed one entry, make sure we don't skip the next one */
426 int config_parse_tunnel(const char *unit,
427 const char *filename,
430 unsigned section_line,
436 Network *network = userdata;
445 r = netdev_get(network->manager, rvalue, &netdev);
447 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
448 "Tunnel is invalid, ignoring assignment: %s", rvalue);
452 if (netdev->kind != NETDEV_KIND_IPIP &&
453 netdev->kind != NETDEV_KIND_SIT &&
454 netdev->kind != NETDEV_KIND_GRE &&
455 netdev->kind != NETDEV_KIND_VTI) {
456 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
457 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
461 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
463 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
464 "Can not add VLAN '%s' to network: %s",
465 rvalue, strerror(-r));
474 int config_parse_dhcp(
476 const char *filename,
479 unsigned section_line,
486 AddressFamilyBoolean *dhcp = data, s;
493 /* Note that this is mostly like
494 * config_parse_address_family_boolean(), except that it
495 * understands some old names for the enum values */
497 s = address_family_boolean_from_string(rvalue);
500 /* Previously, we had a slightly different enum here,
501 * support its values for compatbility. */
503 if (streq(rvalue, "none"))
504 s = ADDRESS_FAMILY_NO;
505 else if (streq(rvalue, "v4"))
506 s = ADDRESS_FAMILY_IPV4;
507 else if (streq(rvalue, "v6"))
508 s = ADDRESS_FAMILY_IPV6;
509 else if (streq(rvalue, "both"))
510 s = ADDRESS_FAMILY_YES;
512 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
521 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
522 [LLMNR_SUPPORT_NO] = "no",
523 [LLMNR_SUPPORT_YES] = "yes",
524 [LLMNR_SUPPORT_RESOLVE] = "resolve",
527 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
529 int config_parse_llmnr(
531 const char *filename,
534 unsigned section_line,
541 LLMNRSupport *llmnr = data;
549 /* Our enum shall be a superset of booleans, hence first try
550 * to parse as boolean, and then as enum */
552 k = parse_boolean(rvalue);
554 *llmnr = LLMNR_SUPPORT_YES;
556 *llmnr = LLMNR_SUPPORT_NO;
560 s = llmnr_support_from_string(rvalue);
562 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);