]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/net/link-config.c
udev,networkd: use the interface name as fallback basis for MAC and IPv4LL seed
[thirdparty/systemd.git] / src / udev / net / link-config.c
index 1a397ece8c4754c2c57476d2a753fc760bdab07f..0fda4d16b9a02c9b98abe082a5abd0b50222c613 100644 (file)
@@ -2,17 +2,19 @@
 
 #include <netinet/ether.h>
 
+#include "sd-device.h"
 #include "sd-netlink.h"
 
 #include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "device-util.h"
 #include "ethtool-util.h"
 #include "fd-util.h"
-#include "libudev-private.h"
 #include "link-config.h"
 #include "log.h"
-#include "missing.h"
+#include "missing_network.h"
+#include "naming-scheme.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "parse-util.h"
@@ -185,6 +187,22 @@ static bool enable_name_policy(void) {
         return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
 }
 
+static int link_name_type(sd_device *device, unsigned *type) {
+        const char *s;
+        int r;
+
+        r = sd_device_get_sysattr_value(device, "name_assign_type", &s);
+        if (r < 0)
+                return log_device_debug_errno(device, r, "Failed to query name_assign_type: %m");
+
+        r = safe_atou(s, type);
+        if (r < 0)
+                return log_device_warning_errno(device, r, "Failed to parse name_assign_type \"%s\": %m", s);
+
+        log_device_debug(device, "Device has name_assign_type=%d", *type);
+        return 0;
+}
+
 int link_config_load(link_config_ctx *ctx) {
         _cleanup_strv_free_ char **files;
         char **f;
@@ -217,8 +235,7 @@ bool link_config_should_reload(link_config_ctx *ctx) {
         return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
 }
 
-int link_config_get(link_config_ctx *ctx, struct udev_device *device,
-                    link_config **ret) {
+int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
         link_config *link;
 
         assert(ctx);
@@ -226,63 +243,67 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device,
         assert(ret);
 
         LIST_FOREACH(links, link, ctx->links) {
-                const char* attr_value;
+                const char *address = NULL, *id_path = NULL, *parent_driver = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
+                sd_device *parent;
 
-                attr_value = udev_device_get_sysattr_value(device, "address");
+                (void) sd_device_get_sysattr_value(device, "address", &address);
+                (void) sd_device_get_property_value(device, "ID_PATH", &id_path);
+                if (sd_device_get_parent(device, &parent) >= 0)
+                        (void) sd_device_get_driver(parent, &parent_driver);
+                (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver);
+                (void) sd_device_get_devtype(device, &devtype);
+                (void) sd_device_get_sysname(device, &sysname);
 
                 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
                                      link->match_type, link->match_name, link->match_host,
                                      link->match_virt, link->match_kernel_cmdline,
                                      link->match_kernel_version, link->match_arch,
-                                     attr_value ? ether_aton(attr_value) : NULL,
-                                     udev_device_get_property_value(device, "ID_PATH"),
-                                     udev_device_get_driver(udev_device_get_parent(device)),
-                                     udev_device_get_property_value(device, "ID_NET_DRIVER"),
-                                     udev_device_get_devtype(device),
-                                     udev_device_get_sysname(device))) {
+                                     address ? ether_aton(address) : NULL,
+                                     id_path,
+                                     parent_driver,
+                                     id_net_driver,
+                                     devtype,
+                                     sysname)) {
                         if (link->match_name) {
                                 unsigned char name_assign_type = NET_NAME_UNKNOWN;
+                                const char *attr_value;
 
-                                attr_value = udev_device_get_sysattr_value(device, "name_assign_type");
-                                if (attr_value)
+                                if (sd_device_get_sysattr_value(device, "name_assign_type", &attr_value) >= 0)
                                         (void) safe_atou8(attr_value, &name_assign_type);
 
                                 if (name_assign_type == NET_NAME_ENUM) {
                                         log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
-                                                  link->filename, udev_device_get_sysname(device));
+                                                    link->filename, sysname);
                                         *ret = link;
 
                                         return 0;
                                 } else if (name_assign_type == NET_NAME_RENAMED) {
                                         log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
-                                                  link->filename, udev_device_get_sysname(device));
+                                                    link->filename, sysname);
 
                                         continue;
                                 }
                         }
 
                         log_debug("Config file %s applies to device %s",
-                                  link->filename,  udev_device_get_sysname(device));
+                                  link->filename, sysname);
 
                         *ret = link;
-
                         return 0;
                 }
         }
 
         *ret = NULL;
-
         return -ENOENT;
 }
 
-static bool mac_is_random(struct udev_device *device) {
+static bool mac_is_random(sd_device *device) {
         const char *s;
         unsigned type;
         int r;
 
         /* if we can't get the assign type, assume it is not random */
-        s = udev_device_get_sysattr_value(device, "addr_assign_type");
-        if (!s)
+        if (sd_device_get_sysattr_value(device, "addr_assign_type", &s) < 0)
                 return false;
 
         r = safe_atou(s, &type);
@@ -292,39 +313,7 @@ static bool mac_is_random(struct udev_device *device) {
         return type == NET_ADDR_RANDOM;
 }
 
-static bool should_rename(struct udev_device *device, bool respect_predictable) {
-        const char *s;
-        unsigned type;
-        int r;
-
-        /* if we can't get the assgin type, assume we should rename */
-        s = udev_device_get_sysattr_value(device, "name_assign_type");
-        if (!s)
-                return true;
-
-        r = safe_atou(s, &type);
-        if (r < 0)
-                return true;
-
-        switch (type) {
-        case NET_NAME_USER:
-        case NET_NAME_RENAMED:
-                /* these were already named by userspace, do not touch again */
-                return false;
-        case NET_NAME_PREDICTABLE:
-                /* the kernel claims to have given a predictable name */
-                if (respect_predictable)
-                        return false;
-                _fallthrough_;
-        case NET_NAME_ENUM:
-        default:
-                /* the name is known to be bad, or of an unknown type */
-                return true;
-        }
-}
-
-static int get_mac(struct udev_device *device, bool want_random,
-                   struct ether_addr *mac) {
+static int get_mac(sd_device *device, bool want_random, struct ether_addr *mac) {
         int r;
 
         if (want_random)
@@ -348,13 +337,13 @@ static int get_mac(struct udev_device *device, bool want_random,
 }
 
 int link_config_apply(link_config_ctx *ctx, link_config *config,
-                      struct udev_device *device, const char **name) {
-        bool respect_predictable = false;
+                      sd_device *device, const char **name) {
         struct ether_addr generated_mac;
         struct ether_addr *mac = NULL;
         const char *new_name = NULL;
         const char *old_name;
-        unsigned speed;
+        unsigned speed, name_type = NET_NAME_UNKNOWN;
+        NamePolicy policy;
         int r, ifindex;
 
         assert(ctx);
@@ -362,23 +351,30 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
         assert(device);
         assert(name);
 
-        old_name = udev_device_get_sysname(device);
-        if (!old_name)
-                return -EINVAL;
+        r = sd_device_get_sysname(device, &old_name);
+        if (r < 0)
+                return r;
 
         r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name, config);
         if (r < 0) {
 
                 if (config->port != _NET_DEV_PORT_INVALID)
-                        log_warning_errno(r,  "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
+                        log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
 
-                speed = DIV_ROUND_UP(config->speed, 1000000);
-                if (r == -EOPNOTSUPP)
-                        r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
+                if (!eqzero(config->advertise))
+                        log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
 
-                if (r < 0)
-                        log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
-                                          old_name, speed, duplex_to_string(config->duplex));
+                if (config->speed) {
+                        speed = DIV_ROUND_UP(config->speed, 1000000);
+                        if (r == -EOPNOTSUPP) {
+                                r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
+                                if (r < 0)
+                                        log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
+                        }
+                }
+
+                if (config->duplex !=_DUP_INVALID)
+                        log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
         }
 
         r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
@@ -396,54 +392,73 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                         log_warning_errno(r, "Could not set channels of %s: %m", old_name);
         }
 
-        ifindex = udev_device_get_ifindex(device);
-        if (ifindex <= 0) {
-                log_warning("Could not find ifindex");
-                return -ENODEV;
+        r = sd_device_get_ifindex(device, &ifindex);
+        if (r < 0)
+                return log_device_warning_errno(device, r, "Could not find ifindex: %m");
+
+
+        (void) link_name_type(device, &name_type);
+
+        if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
+            && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
+                log_device_debug(device, "Device already has a name given by userspace, not renaming.");
+                goto no_rename;
         }
 
-        if (ctx->enable_name_policy && config->name_policy) {
-                NamePolicy *policy;
+        if (ctx->enable_name_policy && config->name_policy)
+                for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
+                        policy = *p;
 
-                for (policy = config->name_policy;
-                     !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
-                        switch (*policy) {
-                                case NAMEPOLICY_KERNEL:
-                                        respect_predictable = true;
-                                        break;
-                                case NAMEPOLICY_DATABASE:
-                                        new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
-                                        break;
-                                case NAMEPOLICY_ONBOARD:
-                                        new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
-                                        break;
-                                case NAMEPOLICY_SLOT:
-                                        new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
-                                        break;
-                                case NAMEPOLICY_PATH:
-                                        new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
-                                        break;
-                                case NAMEPOLICY_MAC:
-                                        new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
-                                        break;
-                                default:
-                                        break;
+                        switch (policy) {
+                        case NAMEPOLICY_KERNEL:
+                                if (name_type != NET_NAME_PREDICTABLE)
+                                        continue;
+
+                                /* The kernel claims to have given a predictable name, keep it. */
+                                log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
+                                                 name_policy_to_string(policy));
+                                goto no_rename;
+                        case NAMEPOLICY_KEEP:
+                                if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
+                                        continue;
+
+                                log_device_debug(device, "Policy *%s*: keeping existing userspace name",
+                                                 name_policy_to_string(policy));
+                                goto no_rename;
+                        case NAMEPOLICY_DATABASE:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
+                                break;
+                        case NAMEPOLICY_ONBOARD:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
+                                break;
+                        case NAMEPOLICY_SLOT:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
+                                break;
+                        case NAMEPOLICY_PATH:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
+                                break;
+                        case NAMEPOLICY_MAC:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
+                                break;
+                        default:
+                                assert_not_reached("invalid policy");
                         }
                 }
-        }
 
-        if (should_rename(device, respect_predictable)) {
-                /* if not set by policy, fall back manually set name */
-                if (!new_name)
-                        new_name = config->name;
+        if (new_name)
+                log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
+        else if (config->name) {
+                new_name = config->name;
+                log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
         } else
-                new_name = NULL;
+                log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
+ no_rename:
 
         switch (config->mac_policy) {
                 case MACPOLICY_PERSISTENT:
                         if (mac_is_random(device)) {
                                 r = get_mac(device, false, &generated_mac);
-                                if (r == -ENOENT) {
+                                if (r == -ENODATA) {
                                         log_warning_errno(r, "Could not generate persistent MAC address for %s: %m", old_name);
                                         break;
                                 } else if (r < 0)
@@ -454,7 +469,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                 case MACPOLICY_RANDOM:
                         if (!mac_is_random(device)) {
                                 r = get_mac(device, true, &generated_mac);
-                                if (r == -ENOENT) {
+                                if (r == -ENODATA) {
                                         log_warning_errno(r, "Could not generate random MAC address for %s: %m", old_name);
                                         break;
                                 } else if (r < 0)
@@ -476,14 +491,14 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
         return 0;
 }
 
-int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
+int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
         const char *name;
         char *driver = NULL;
         int r;
 
-        name = udev_device_get_sysname(device);
-        if (!name)
-                return -EINVAL;
+        r = sd_device_get_sysname(device, &name);
+        if (r < 0)
+                return r;
 
         r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
         if (r < 0)
@@ -496,7 +511,7 @@ int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret
 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
         [MACPOLICY_PERSISTENT] = "persistent",
         [MACPOLICY_RANDOM] = "random",
-        [MACPOLICY_NONE] = "none"
+        [MACPOLICY_NONE] = "none",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
@@ -505,11 +520,12 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
 
 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
         [NAMEPOLICY_KERNEL] = "kernel",
+        [NAMEPOLICY_KEEP] = "keep",
         [NAMEPOLICY_DATABASE] = "database",
         [NAMEPOLICY_ONBOARD] = "onboard",
         [NAMEPOLICY_SLOT] = "slot",
         [NAMEPOLICY_PATH] = "path",
-        [NAMEPOLICY_MAC] = "mac"
+        [NAMEPOLICY_MAC] = "mac",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);