LCOV - code coverage report
Current view: top level - udev/net - link-config.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 2 264 0.8 %
Date: 2019-08-22 15:41:25 Functions: 4 20 20.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <linux/netdevice.h>
       4             : #include <netinet/ether.h>
       5             : 
       6             : #include "sd-device.h"
       7             : #include "sd-netlink.h"
       8             : 
       9             : #include "alloc-util.h"
      10             : #include "conf-files.h"
      11             : #include "conf-parser.h"
      12             : #include "def.h"
      13             : #include "device-util.h"
      14             : #include "ethtool-util.h"
      15             : #include "fd-util.h"
      16             : #include "link-config.h"
      17             : #include "log.h"
      18             : #include "memory-util.h"
      19             : #include "naming-scheme.h"
      20             : #include "netlink-util.h"
      21             : #include "network-internal.h"
      22             : #include "parse-util.h"
      23             : #include "path-util.h"
      24             : #include "proc-cmdline.h"
      25             : #include "random-util.h"
      26             : #include "stat-util.h"
      27             : #include "string-table.h"
      28             : #include "string-util.h"
      29             : #include "strv.h"
      30             : 
      31             : struct link_config_ctx {
      32             :         LIST_HEAD(link_config, links);
      33             : 
      34             :         int ethtool_fd;
      35             : 
      36             :         bool enable_name_policy;
      37             : 
      38             :         sd_netlink *rtnl;
      39             : 
      40             :         usec_t network_dirs_ts_usec;
      41             : };
      42             : 
      43           0 : static void link_config_free(link_config *link) {
      44           0 :         if (!link)
      45           0 :                 return;
      46             : 
      47           0 :         free(link->filename);
      48             : 
      49           0 :         set_free_free(link->match_mac);
      50           0 :         strv_free(link->match_path);
      51           0 :         strv_free(link->match_driver);
      52           0 :         strv_free(link->match_type);
      53           0 :         strv_free(link->match_name);
      54           0 :         strv_free(link->match_property);
      55           0 :         condition_free_list(link->conditions);
      56             : 
      57           0 :         free(link->description);
      58           0 :         free(link->mac);
      59           0 :         free(link->name_policy);
      60           0 :         free(link->name);
      61           0 :         free(link->alias);
      62             : 
      63           0 :         free(link);
      64             : }
      65             : 
      66           0 : DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
      67             : 
      68           0 : static void link_configs_free(link_config_ctx *ctx) {
      69             :         link_config *link, *link_next;
      70             : 
      71           0 :         if (!ctx)
      72           0 :                 return;
      73             : 
      74           0 :         LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
      75           0 :                 link_config_free(link);
      76             : }
      77             : 
      78           0 : void link_config_ctx_free(link_config_ctx *ctx) {
      79           0 :         if (!ctx)
      80           0 :                 return;
      81             : 
      82           0 :         safe_close(ctx->ethtool_fd);
      83             : 
      84           0 :         sd_netlink_unref(ctx->rtnl);
      85             : 
      86           0 :         link_configs_free(ctx);
      87             : 
      88           0 :         free(ctx);
      89             : 
      90           0 :         return;
      91             : }
      92             : 
      93           0 : int link_config_ctx_new(link_config_ctx **ret) {
      94           0 :         _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
      95             : 
      96           0 :         if (!ret)
      97           0 :                 return -EINVAL;
      98             : 
      99           0 :         ctx = new0(link_config_ctx, 1);
     100           0 :         if (!ctx)
     101           0 :                 return -ENOMEM;
     102             : 
     103           0 :         LIST_HEAD_INIT(ctx->links);
     104             : 
     105           0 :         ctx->ethtool_fd = -1;
     106             : 
     107           0 :         ctx->enable_name_policy = true;
     108             : 
     109           0 :         *ret = TAKE_PTR(ctx);
     110             : 
     111           0 :         return 0;
     112             : }
     113             : 
     114           0 : int link_load_one(link_config_ctx *ctx, const char *filename) {
     115           0 :         _cleanup_(link_config_freep) link_config *link = NULL;
     116           0 :         _cleanup_fclose_ FILE *file = NULL;
     117           0 :         _cleanup_free_ char *name = NULL;
     118             :         size_t i;
     119             :         int r;
     120             : 
     121           0 :         assert(ctx);
     122           0 :         assert(filename);
     123             : 
     124           0 :         file = fopen(filename, "re");
     125           0 :         if (!file)
     126           0 :                 return errno == ENOENT ? 0 : -errno;
     127             : 
     128           0 :         if (null_or_empty_fd(fileno(file))) {
     129           0 :                 log_debug("Skipping empty file: %s", filename);
     130           0 :                 return 0;
     131             :         }
     132             : 
     133           0 :         name = strdup(filename);
     134           0 :         if (!name)
     135           0 :                 return -ENOMEM;
     136             : 
     137           0 :         link = new(link_config, 1);
     138           0 :         if (!link)
     139           0 :                 return -ENOMEM;
     140             : 
     141           0 :         *link = (link_config) {
     142           0 :                 .filename = TAKE_PTR(name),
     143             :                 .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
     144             :                 .wol = _WOL_INVALID,
     145             :                 .duplex = _DUP_INVALID,
     146             :                 .port = _NET_DEV_PORT_INVALID,
     147             :                 .autonegotiation = -1,
     148             :         };
     149             : 
     150           0 :         for (i = 0; i < ELEMENTSOF(link->features); i++)
     151           0 :                 link->features[i] = -1;
     152             : 
     153           0 :         r = config_parse(NULL, filename, file,
     154             :                          "Match\0Link\0",
     155             :                          config_item_perf_lookup, link_config_gperf_lookup,
     156             :                          CONFIG_PARSE_WARN, link);
     157           0 :         if (r < 0)
     158           0 :                 return r;
     159             : 
     160           0 :         if (link->speed > UINT_MAX)
     161           0 :                 return -ERANGE;
     162             : 
     163           0 :         if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
     164           0 :             strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
     165           0 :             strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions)
     166           0 :                 log_warning("%s: No valid settings found in the [Match] section. "
     167             :                             "The file will match all interfaces. "
     168             :                             "If that is intended, please add OriginalName=* in the [Match] section.",
     169             :                             filename);
     170             : 
     171           0 :         if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
     172           0 :                 log_debug("%s: Conditions do not match the system environment, skipping.", filename);
     173           0 :                 return 0;
     174             :         }
     175             : 
     176           0 :         log_debug("Parsed configuration file %s", filename);
     177             : 
     178           0 :         LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
     179           0 :         return 0;
     180             : }
     181             : 
     182           0 : static bool enable_name_policy(void) {
     183             :         bool b;
     184             : 
     185           0 :         return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
     186             : }
     187             : 
     188           0 : static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
     189             :         const char *s;
     190             :         int r;
     191             : 
     192           0 :         r = sd_device_get_sysattr_value(device, attr, &s);
     193           0 :         if (r < 0)
     194           0 :                 return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
     195             : 
     196           0 :         r = safe_atou(s, type);
     197           0 :         if (r < 0)
     198           0 :                 return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
     199             : 
     200           0 :         log_device_debug(device, "Device has %s=%u", attr, *type);
     201           0 :         return 0;
     202             : }
     203             : 
     204           0 : int link_config_load(link_config_ctx *ctx) {
     205           0 :         _cleanup_strv_free_ char **files;
     206             :         char **f;
     207             :         int r;
     208             : 
     209           0 :         link_configs_free(ctx);
     210             : 
     211           0 :         if (!enable_name_policy()) {
     212           0 :                 ctx->enable_name_policy = false;
     213           0 :                 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
     214             :         }
     215             : 
     216             :         /* update timestamp */
     217           0 :         paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
     218             : 
     219           0 :         r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
     220           0 :         if (r < 0)
     221           0 :                 return log_error_errno(r, "failed to enumerate link files: %m");
     222             : 
     223           0 :         STRV_FOREACH_BACKWARDS(f, files) {
     224           0 :                 r = link_load_one(ctx, *f);
     225           0 :                 if (r < 0)
     226           0 :                         log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
     227             :         }
     228             : 
     229           0 :         return 0;
     230             : }
     231             : 
     232           0 : bool link_config_should_reload(link_config_ctx *ctx) {
     233           0 :         return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
     234             : }
     235             : 
     236           0 : int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
     237             :         link_config *link;
     238             : 
     239           0 :         assert(ctx);
     240           0 :         assert(device);
     241           0 :         assert(ret);
     242             : 
     243           0 :         LIST_FOREACH(links, link, ctx->links) {
     244           0 :                 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
     245           0 :                                      link->match_type, link->match_name, link->match_property,
     246             :                                      device, NULL, NULL)) {
     247           0 :                         if (link->match_name && !strv_contains(link->match_name, "*")) {
     248           0 :                                 unsigned name_assign_type = NET_NAME_UNKNOWN;
     249             : 
     250           0 :                                 (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
     251             : 
     252           0 :                                 if (name_assign_type == NET_NAME_ENUM) {
     253           0 :                                         log_device_warning(device, "Config file %s applies to device based on potentially unpredictable interface name",
     254             :                                                            link->filename);
     255           0 :                                         *ret = link;
     256             : 
     257           0 :                                         return 0;
     258           0 :                                 } else if (name_assign_type == NET_NAME_RENAMED) {
     259           0 :                                         log_device_warning(device, "Config file %s matches device based on renamed interface name, ignoring",
     260             :                                                            link->filename);
     261             : 
     262           0 :                                         continue;
     263             :                                 }
     264             :                         }
     265             : 
     266           0 :                         log_device_debug(device, "Config file %s is applied", link->filename);
     267             : 
     268           0 :                         *ret = link;
     269           0 :                         return 0;
     270             :                 }
     271             :         }
     272             : 
     273           0 :         *ret = NULL;
     274           0 :         return -ENOENT;
     275             : }
     276             : 
     277           0 : static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
     278             :         unsigned addr_type;
     279           0 :         bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
     280             :         int r;
     281             : 
     282           0 :         assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
     283             : 
     284           0 :         r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
     285           0 :         if (r < 0)
     286           0 :                 return r;
     287           0 :         switch (addr_type) {
     288           0 :         case NET_ADDR_SET:
     289           0 :                 return log_device_debug(device, "MAC on the device already set by userspace");
     290           0 :         case NET_ADDR_STOLEN:
     291           0 :                 return log_device_debug(device, "MAC on the device already set based on another device");
     292           0 :         case NET_ADDR_RANDOM:
     293             :         case NET_ADDR_PERM:
     294           0 :                 break;
     295           0 :         default:
     296           0 :                 return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
     297             :         }
     298             : 
     299           0 :         if (want_random == (addr_type == NET_ADDR_RANDOM))
     300           0 :                 return log_device_debug(device, "MAC on the device already matches policy *%s*",
     301             :                                         mac_address_policy_to_string(policy));
     302             : 
     303           0 :         if (want_random) {
     304           0 :                 log_device_debug(device, "Using random bytes to generate MAC");
     305           0 :                 random_bytes(mac->ether_addr_octet, ETH_ALEN);
     306             :         } else {
     307             :                 uint64_t result;
     308             : 
     309           0 :                 r = net_get_unique_predictable_data(device,
     310           0 :                                                     naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
     311             :                                                     &result);
     312           0 :                 if (r < 0)
     313           0 :                         return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
     314             : 
     315           0 :                 log_device_debug(device, "Using generated persistent MAC address");
     316             :                 assert_cc(ETH_ALEN <= sizeof(result));
     317           0 :                 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
     318             :         }
     319             : 
     320             :         /* see eth_random_addr in the kernel */
     321           0 :         mac->ether_addr_octet[0] &= 0xfe;  /* clear multicast bit */
     322           0 :         mac->ether_addr_octet[0] |= 0x02;  /* set local assignment bit (IEEE802) */
     323           0 :         return 1;
     324             : }
     325             : 
     326           0 : int link_config_apply(link_config_ctx *ctx, link_config *config,
     327             :                       sd_device *device, const char **name) {
     328             :         struct ether_addr generated_mac;
     329           0 :         struct ether_addr *mac = NULL;
     330           0 :         const char *new_name = NULL;
     331             :         const char *old_name;
     332           0 :         unsigned speed, name_type = NET_NAME_UNKNOWN;
     333             :         NamePolicy policy;
     334             :         int r, ifindex;
     335             : 
     336           0 :         assert(ctx);
     337           0 :         assert(config);
     338           0 :         assert(device);
     339           0 :         assert(name);
     340             : 
     341           0 :         r = sd_device_get_sysname(device, &old_name);
     342           0 :         if (r < 0)
     343           0 :                 return r;
     344             : 
     345           0 :         r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name,
     346           0 :                                       config->autonegotiation, config->advertise,
     347             :                                       config->speed, config->duplex, config->port);
     348           0 :         if (r < 0) {
     349             : 
     350           0 :                 if (config->port != _NET_DEV_PORT_INVALID)
     351           0 :                         log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
     352             : 
     353           0 :                 if (!eqzero(config->advertise))
     354           0 :                         log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
     355             : 
     356           0 :                 if (config->speed) {
     357           0 :                         speed = DIV_ROUND_UP(config->speed, 1000000);
     358           0 :                         if (r == -EOPNOTSUPP) {
     359           0 :                                 r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
     360           0 :                                 if (r < 0)
     361           0 :                                         log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
     362             :                         }
     363             :                 }
     364             : 
     365           0 :                 if (config->duplex !=_DUP_INVALID)
     366           0 :                         log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
     367             :         }
     368             : 
     369           0 :         r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
     370           0 :         if (r < 0)
     371           0 :                 log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
     372             :                                   old_name, wol_to_string(config->wol));
     373             : 
     374           0 :         r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
     375           0 :         if (r < 0)
     376           0 :                 log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
     377             : 
     378           0 :         if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
     379           0 :                 r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
     380           0 :                 if (r < 0)
     381           0 :                         log_warning_errno(r, "Could not set channels of %s: %m", old_name);
     382             :         }
     383             : 
     384           0 :         r = sd_device_get_ifindex(device, &ifindex);
     385           0 :         if (r < 0)
     386           0 :                 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
     387             : 
     388           0 :         (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
     389             : 
     390           0 :         if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
     391           0 :             && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
     392           0 :                 log_device_debug(device, "Device already has a name given by userspace, not renaming.");
     393           0 :                 goto no_rename;
     394             :         }
     395             : 
     396           0 :         if (ctx->enable_name_policy && config->name_policy)
     397           0 :                 for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
     398           0 :                         policy = *p;
     399             : 
     400           0 :                         switch (policy) {
     401           0 :                         case NAMEPOLICY_KERNEL:
     402           0 :                                 if (name_type != NET_NAME_PREDICTABLE)
     403           0 :                                         continue;
     404             : 
     405             :                                 /* The kernel claims to have given a predictable name, keep it. */
     406           0 :                                 log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
     407             :                                                  name_policy_to_string(policy));
     408           0 :                                 goto no_rename;
     409           0 :                         case NAMEPOLICY_KEEP:
     410           0 :                                 if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
     411           0 :                                         continue;
     412             : 
     413           0 :                                 log_device_debug(device, "Policy *%s*: keeping existing userspace name",
     414             :                                                  name_policy_to_string(policy));
     415           0 :                                 goto no_rename;
     416           0 :                         case NAMEPOLICY_DATABASE:
     417           0 :                                 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
     418           0 :                                 break;
     419           0 :                         case NAMEPOLICY_ONBOARD:
     420           0 :                                 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
     421           0 :                                 break;
     422           0 :                         case NAMEPOLICY_SLOT:
     423           0 :                                 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
     424           0 :                                 break;
     425           0 :                         case NAMEPOLICY_PATH:
     426           0 :                                 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
     427           0 :                                 break;
     428           0 :                         case NAMEPOLICY_MAC:
     429           0 :                                 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
     430           0 :                                 break;
     431           0 :                         default:
     432           0 :                                 assert_not_reached("invalid policy");
     433             :                         }
     434             :                 }
     435             : 
     436           0 :         if (new_name)
     437           0 :                 log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
     438           0 :         else if (config->name) {
     439           0 :                 new_name = config->name;
     440           0 :                 log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
     441             :         } else
     442           0 :                 log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
     443           0 :  no_rename:
     444             : 
     445           0 :         if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
     446           0 :                 if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
     447           0 :                         mac = &generated_mac;
     448             :         } else
     449           0 :                 mac = config->mac;
     450             : 
     451           0 :         r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
     452           0 :         if (r < 0)
     453           0 :                 return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
     454             : 
     455           0 :         *name = new_name;
     456             : 
     457           0 :         return 0;
     458             : }
     459             : 
     460           0 : int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
     461             :         const char *name;
     462           0 :         char *driver = NULL;
     463             :         int r;
     464             : 
     465           0 :         r = sd_device_get_sysname(device, &name);
     466           0 :         if (r < 0)
     467           0 :                 return r;
     468             : 
     469           0 :         r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
     470           0 :         if (r < 0)
     471           0 :                 return r;
     472             : 
     473           0 :         *ret = driver;
     474           0 :         return 0;
     475             : }
     476             : 
     477             : static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
     478             :         [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
     479             :         [MAC_ADDRESS_POLICY_RANDOM] = "random",
     480             :         [MAC_ADDRESS_POLICY_NONE] = "none",
     481             : };
     482             : 
     483          10 : DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
     484           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_address_policy, mac_address_policy, MACAddressPolicy,
     485             :                          "Failed to parse MAC address policy");
     486             : 
     487             : static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
     488             :         [NAMEPOLICY_KERNEL] = "kernel",
     489             :         [NAMEPOLICY_KEEP] = "keep",
     490             :         [NAMEPOLICY_DATABASE] = "database",
     491             :         [NAMEPOLICY_ONBOARD] = "onboard",
     492             :         [NAMEPOLICY_SLOT] = "slot",
     493             :         [NAMEPOLICY_PATH] = "path",
     494             :         [NAMEPOLICY_MAC] = "mac",
     495             : };
     496             : 
     497          18 : DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
     498           0 : DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
     499             :                           _NAMEPOLICY_INVALID,
     500             :                           "Failed to parse interface name policy");

Generated by: LCOV version 1.14