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;
45 file = fopen(filename, "re");
53 if (null_or_empty_fd(fileno(file))) {
54 log_debug("Skipping empty file: %s", filename);
58 network = new0(Network, 1);
62 network->manager = manager;
64 LIST_HEAD_INIT(network->static_addresses);
65 LIST_HEAD_INIT(network->static_routes);
66 LIST_HEAD_INIT(network->static_fdb_entries);
68 network->stacked_netdevs = hashmap_new(&string_hash_ops);
69 if (!network->stacked_netdevs)
72 network->addresses_by_section = hashmap_new(NULL);
73 if (!network->addresses_by_section)
76 network->routes_by_section = hashmap_new(NULL);
77 if (!network->routes_by_section)
80 network->fdb_entries_by_section = hashmap_new(NULL);
81 if (!network->fdb_entries_by_section)
84 network->filename = strdup(filename);
85 if (!network->filename)
88 network->name = strdup(basename(filename));
92 d = strrchr(network->name, '.');
96 assert(streq(d, ".network"));
100 network->dhcp = ADDRESS_FAMILY_NO;
101 network->dhcp_ntp = true;
102 network->dhcp_dns = true;
103 network->dhcp_hostname = true;
104 network->dhcp_routes = true;
105 network->dhcp_sendhost = true;
106 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
108 network->llmnr = LLMNR_SUPPORT_YES;
110 r = config_parse(NULL, filename, file,
120 config_item_perf_lookup, network_network_gperf_lookup,
121 false, false, true, network);
125 /* IPMasquerade=yes implies IPForward=yes */
126 if (network->ip_masquerade)
127 network->ip_forward |= ADDRESS_FAMILY_IPV4;
129 LIST_PREPEND(networks, manager->networks, network);
131 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
135 r = hashmap_put(manager->networks_by_name, network->name, network);
139 LIST_FOREACH(routes, route, network->static_routes) {
140 if (!route->family) {
141 log_warning("Route section without Gateway field configured in %s. "
142 "Ignoring", filename);
147 LIST_FOREACH(addresses, address, network->static_addresses) {
148 if (!address->family) {
149 log_warning("Address section without Address field configured in %s. "
150 "Ignoring", filename);
160 int network_load(Manager *manager) {
162 _cleanup_strv_free_ char **files = NULL;
168 while ((network = manager->networks))
169 network_free(network);
171 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
173 return log_error_errno(r, "Failed to enumerate network files: %m");
175 STRV_FOREACH_BACKWARDS(f, files) {
176 r = network_load_one(manager, *f);
184 void network_free(Network *network) {
194 free(network->filename);
196 free(network->match_mac);
197 free(network->match_path);
198 free(network->match_driver);
199 free(network->match_type);
200 free(network->match_name);
202 free(network->description);
203 free(network->dhcp_vendor_class_identifier);
207 strv_free(network->ntp);
208 strv_free(network->dns);
209 strv_free(network->domains);
211 netdev_unref(network->bridge);
213 netdev_unref(network->bond);
215 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
216 hashmap_remove(network->stacked_netdevs, netdev->ifname);
217 netdev_unref(netdev);
219 hashmap_free(network->stacked_netdevs);
221 while ((route = network->static_routes))
224 while ((address = network->static_addresses))
225 address_free(address);
227 while ((fdb_entry = network->static_fdb_entries))
228 fdb_entry_free(fdb_entry);
230 hashmap_free(network->addresses_by_section);
231 hashmap_free(network->routes_by_section);
232 hashmap_free(network->fdb_entries_by_section);
234 if (network->manager) {
235 if (network->manager->networks)
236 LIST_REMOVE(networks, network->manager->networks, network);
238 if (network->manager->networks_by_name)
239 hashmap_remove(network->manager->networks_by_name, network->name);
244 condition_free_list(network->match_host);
245 condition_free_list(network->match_virt);
246 condition_free_list(network->match_kernel);
247 condition_free_list(network->match_arch);
252 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
259 network = hashmap_get(manager->networks_by_name, name);
268 int network_get(Manager *manager, struct udev_device *device,
269 const char *ifname, const struct ether_addr *address,
276 LIST_FOREACH(networks, network, manager->networks) {
277 if (net_match_config(network->match_mac, network->match_path,
278 network->match_driver, network->match_type,
279 network->match_name, network->match_host,
280 network->match_virt, network->match_kernel,
283 udev_device_get_property_value(device, "ID_PATH"),
284 udev_device_get_driver(udev_device_get_parent(device)),
285 udev_device_get_property_value(device, "ID_NET_DRIVER"),
286 udev_device_get_devtype(device),
288 if (network->match_name) {
290 uint8_t name_assign_type = NET_NAME_UNKNOWN;
292 attr = udev_device_get_sysattr_value(device, "name_assign_type");
294 (void)safe_atou8(attr, &name_assign_type);
296 if (name_assign_type == NET_NAME_ENUM)
297 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
298 IFNAMSIZ, ifname, network->filename);
300 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
302 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
314 int network_apply(Manager *manager, Network *network, Link *link) {
317 link->network = network;
319 if (network->ipv4ll_route) {
322 r = route_new_static(network, 0, &route);
326 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
332 route->family = AF_INET;
333 route->dst_prefixlen = 16;
334 route->scope = RT_SCOPE_LINK;
335 route->metrics = IPV4LL_ROUTE_METRIC;
336 route->protocol = RTPROT_STATIC;
339 if (network->dns || network->ntp) {
348 int config_parse_netdev(const char *unit,
349 const char *filename,
352 unsigned section_line,
358 Network *network = userdata;
359 _cleanup_free_ char *kind_string = NULL;
370 kind_string = strdup(lvalue);
374 /* the keys are CamelCase versions of the kind */
375 for (p = kind_string; *p; p++)
378 kind = netdev_kind_from_string(kind_string);
379 if (kind == _NETDEV_KIND_INVALID) {
380 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
381 "Invalid NetDev kind: %s", lvalue);
385 r = netdev_get(network->manager, rvalue, &netdev);
387 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
388 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
392 if (netdev->kind != kind) {
393 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
394 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
399 case NETDEV_KIND_BRIDGE:
400 network->bridge = netdev;
403 case NETDEV_KIND_BOND:
404 network->bond = netdev;
407 case NETDEV_KIND_VLAN:
408 case NETDEV_KIND_MACVLAN:
409 case NETDEV_KIND_IPVLAN:
410 case NETDEV_KIND_VXLAN:
411 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
413 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
414 "Can not add VLAN '%s' to network: %s",
415 rvalue, strerror(-r));
421 assert_not_reached("Can not parse NetDev");
429 int config_parse_domains(const char *unit,
430 const char *filename,
433 unsigned section_line,
439 Network *network = userdata;
440 char ***domains = data;
444 r = config_parse_strv(unit, filename, line, section, section_line,
445 lvalue, ltype, rvalue, domains, userdata);
450 network->wildcard_domain = !!strv_find(*domains, "*");
452 STRV_FOREACH(domain, *domains) {
453 if (is_localhost(*domain))
454 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
455 else if (!hostname_is_valid(*domain)) {
456 if (!streq(*domain, "*"))
457 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
461 strv_remove(*domains, *domain);
463 /* We removed one entry, make sure we don't skip the next one */
470 int config_parse_tunnel(const char *unit,
471 const char *filename,
474 unsigned section_line,
480 Network *network = userdata;
489 r = netdev_get(network->manager, rvalue, &netdev);
491 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
492 "Tunnel is invalid, ignoring assignment: %s", rvalue);
496 if (netdev->kind != NETDEV_KIND_IPIP &&
497 netdev->kind != NETDEV_KIND_SIT &&
498 netdev->kind != NETDEV_KIND_GRE &&
499 netdev->kind != NETDEV_KIND_GRETAP &&
500 netdev->kind != NETDEV_KIND_IP6GRE &&
501 netdev->kind != NETDEV_KIND_IP6GRETAP &&
502 netdev->kind != NETDEV_KIND_VTI &&
503 netdev->kind != NETDEV_KIND_IP6TNL
505 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
506 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
510 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
513 "Can not add VLAN '%s' to network: %s",
514 rvalue, strerror(-r));
523 int config_parse_dhcp(
525 const char *filename,
528 unsigned section_line,
535 AddressFamilyBoolean *dhcp = data, s;
542 /* Note that this is mostly like
543 * config_parse_address_family_boolean(), except that it
544 * understands some old names for the enum values */
546 s = address_family_boolean_from_string(rvalue);
549 /* Previously, we had a slightly different enum here,
550 * support its values for compatbility. */
552 if (streq(rvalue, "none"))
553 s = ADDRESS_FAMILY_NO;
554 else if (streq(rvalue, "v4"))
555 s = ADDRESS_FAMILY_IPV4;
556 else if (streq(rvalue, "v6"))
557 s = ADDRESS_FAMILY_IPV6;
558 else if (streq(rvalue, "both"))
559 s = ADDRESS_FAMILY_YES;
561 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
570 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
571 [LLMNR_SUPPORT_NO] = "no",
572 [LLMNR_SUPPORT_YES] = "yes",
573 [LLMNR_SUPPORT_RESOLVE] = "resolve",
576 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
578 int config_parse_llmnr(
580 const char *filename,
583 unsigned section_line,
590 LLMNRSupport *llmnr = data;
598 /* Our enum shall be a superset of booleans, hence first try
599 * to parse as boolean, and then as enum */
601 k = parse_boolean(rvalue);
603 *llmnr = LLMNR_SUPPORT_YES;
605 *llmnr = LLMNR_SUPPORT_NO;
609 s = llmnr_support_from_string(rvalue);
611 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);