1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 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/>.
22 #include <netinet/ether.h>
27 #include "link-config.h"
28 #include "ethtool-util.h"
30 #include "libudev-private.h"
35 #include "path-util.h"
36 #include "conf-parser.h"
37 #include "conf-files.h"
41 struct link_config_ctx {
42 LIST_HEAD(link_config, links);
49 usec_t link_dirs_ts_usec;
52 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
53 #define _cleanup_link_config_ctx_free_ _cleanup_(link_config_ctx_freep)
55 int link_config_ctx_new(link_config_ctx **ret) {
56 _cleanup_link_config_ctx_free_ link_config_ctx *ctx = NULL;
62 ctx = new0(link_config_ctx, 1);
66 r = ethtool_connect(&ctx->ethtool_fd);
70 r = sd_rtnl_open(0, &ctx->rtnl);
74 LIST_HEAD_INIT(ctx->links);
76 ctx->link_dirs = strv_new("/etc/systemd/network",
77 "/run/systemd/network",
78 "/usr/lib/systemd/network",
80 if (!ctx->link_dirs) {
81 log_error("failed to build link config directory array");
85 if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
86 log_error("failed to canonicalize link config directories\n");
96 static void link_configs_free(link_config_ctx *ctx) {
97 link_config *link, *link_next;
102 LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
103 free(link->filename);
104 free(link->match_path);
105 free(link->match_driver);
106 free(link->match_type);
107 free(link->description);
113 void link_config_ctx_free(link_config_ctx *ctx) {
117 if (ctx->ethtool_fd >= 0)
118 close_nointr_nofail(ctx->ethtool_fd);
120 sd_rtnl_unref(ctx->rtnl);
122 strv_free(ctx->link_dirs);
123 link_configs_free(ctx);
130 static int load_link(link_config_ctx *ctx, const char *filename) {
135 file = fopen(filename, "re");
143 link = new0(link_config, 1);
149 link->mac_policy = _MACPOLICY_INVALID;
150 link->wol = _WOL_INVALID;
151 link->duplex = _DUP_INVALID;
154 r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
155 (void*) link_config_gperf_lookup, false, false, link);
157 log_warning("Colud not parse config file %s: %s", filename, strerror(-r));
160 log_info("Parsed configuration file %s", filename);
162 link->filename = strdup(filename);
164 LIST_PREPEND(links, ctx->links, link);
173 int link_config_load(link_config_ctx *ctx) {
177 link_configs_free(ctx);
179 /* update timestamp */
180 paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, true);
182 r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
184 log_error("failed to enumerate link files: %s", strerror(-r));
188 STRV_FOREACH_BACKWARDS(f, files) {
189 r = load_link(ctx, *f);
197 bool link_config_should_reload(link_config_ctx *ctx) {
198 return paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, false);
201 static bool match_config(link_config *match, struct udev_device *device) {
202 const char *property;
204 if (match->match_mac) {
205 property = udev_device_get_sysattr_value(device, "address");
206 if (!property || memcmp(match->match_mac, ether_aton(property), ETH_ALEN)) {
207 log_debug("Device MAC address (%s) did not match MACAddress=%s",
208 property, ether_ntoa(match->match_mac));
213 if (match->match_path) {
214 property = udev_device_get_property_value(device, "ID_PATH");
215 if (!streq_ptr(match->match_path, property)) {
216 log_debug("Device's persistent path (%s) did not match Path=%s",
217 property, match->match_path);
222 if (match->match_driver) {
223 property = udev_device_get_driver(device);
224 if (!streq_ptr(match->match_driver, property)) {
225 log_debug("Device driver (%s) did not match Driver=%s",
226 property, match->match_driver);
231 if (match->match_type) {
232 property = udev_device_get_devtype(device);
233 if (!streq_ptr(match->match_type, property)) {
234 log_debug("Device type (%s) did not match Type=%s",
235 property, match->match_type);
243 int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
246 LIST_FOREACH(links, link, ctx->links) {
247 if (!match_config(link, device)) {
248 log_info("Config file %s does not apply to device %s", link->filename, udev_device_get_sysname(device));
250 log_info("Config file %s applies to device %s", link->filename, udev_device_get_sysname(device));
259 static int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, const struct ether_addr *mac, unsigned int mtu) {
260 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
261 bool need_update = false;
267 r = sd_rtnl_message_link_new(RTM_NEWLINK, ifindex, 0, 0, &message);
272 r = sd_rtnl_message_append(message, IFLA_IFNAME, name);
280 r = sd_rtnl_message_append(message, IFLA_ADDRESS, mac);
288 r = sd_rtnl_message_append(message, IFLA_MTU, &mtu);
296 r = sd_rtnl_send_with_reply_and_block(rtnl, message, 0, NULL);
304 static bool enable_name_policy(void) {
305 _cleanup_free_ char *line;
310 r = read_one_line_file("/proc/cmdline", &line);
312 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
313 return true; /* something is very wrong, let's not make it worse */
316 FOREACH_WORD_QUOTED(w, l, line, state)
317 if (strneq(w, "net.ifnames=0", l))
323 static bool mac_is_random(struct udev_device *device) {
328 s = udev_device_get_sysattr_value(device, "addr_assign_type");
330 return false; /* if we don't know, assume it is not random */
331 r = safe_atou(s, &type);
335 /* check for NET_ADDR_RANDOM */
339 static bool mac_is_permanent(struct udev_device *device) {
344 s = udev_device_get_sysattr_value(device, "addr_assign_type");
346 return true; /* if we don't know, assume it is permanent */
347 r = safe_atou(s, &type);
351 /* check for NET_ADDR_PERM */
355 static int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) {
364 char machineid_buf[33];
365 const char *seed_str;
367 /* fetch some persistent data unique (on this machine) to this device */
368 name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
370 name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
372 name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
377 /* fetch some persistent data unique to this machine */
378 r = sd_id128_get_machine(&machine);
382 /* combine the data */
383 seed_str = strappenda(name, sd_id128_to_string(machine, machineid_buf));
385 /* hash to get seed */
386 seed = string_hash_func(seed_str);
391 for(i = 0; i < ETH_ALEN; i++) {
392 mac->ether_addr_octet[i] = random();
395 /* see eth_random_addr in the kernel */
396 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
397 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
402 int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device) {
404 const char *new_name = NULL;
405 struct ether_addr generated_mac;
406 struct ether_addr *mac = NULL;
409 name = udev_device_get_sysname(device);
413 log_info("Configuring %s", name);
415 if (config->description) {
416 r = udev_device_set_sysattr_value(device, "ifalias",
417 config->description);
419 log_warning("Could not set description of %s to '%s': %s",
420 name, config->description, strerror(-r));
423 r = ethtool_set_speed(ctx->ethtool_fd, name, config->speed, config->duplex);
425 log_warning("Could not set speed or duplex of %s to %u Mbytes (%s): %s",
426 name, config->speed, duplex_to_string(config->duplex), strerror(-r));
428 r = ethtool_set_wol(ctx->ethtool_fd, name, config->wol);
430 log_warning("Could not set WakeOnLan of %s to %s: %s",
431 name, wol_to_string(config->wol), strerror(-r));
433 ifindex = udev_device_get_ifindex(device);
435 log_warning("Could not find ifindex");
439 if (config->name_policy && enable_name_policy()) {
442 for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
444 case NAMEPOLICY_ONBOARD:
445 new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
447 case NAMEPOLICY_SLOT:
448 new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
450 case NAMEPOLICY_PATH:
451 new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
454 new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
462 if (!new_name && config->name) {
463 new_name = config->name;
466 switch (config->mac_policy) {
467 case MACPOLICY_PERSISTENT:
468 if (!mac_is_permanent(device)) {
469 r = get_mac(device, false, &generated_mac);
472 mac = &generated_mac;
475 case MACPOLICY_RANDOM:
476 if (!mac_is_random(device)) {
477 r = get_mac(device, true, &generated_mac);
480 mac = &generated_mac;
487 r = rtnl_set_properties(ctx->rtnl, ifindex, new_name, mac, config->mtu);
489 log_warning("Could not set Name, MACAddress or MTU on %s: %s", name, strerror(-r));