]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/net/link-config.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / udev / net / link-config.c
index ac66ffd047464a4bf1da0e8871f9b4e371d9d4ec..f1d36ccac0b6e10d583c84189701a93cb4d2b660 100644 (file)
@@ -8,12 +8,14 @@
 #include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "def.h"
 #include "device-util.h"
 #include "ethtool-util.h"
 #include "fd-util.h"
 #include "link-config.h"
 #include "log.h"
 #include "missing_network.h"
+#include "naming-scheme.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "parse-util.h"
@@ -35,18 +37,9 @@ struct link_config_ctx {
 
         sd_netlink *rtnl;
 
-        usec_t link_dirs_ts_usec;
+        usec_t network_dirs_ts_usec;
 };
 
-static const char* const link_dirs[] = {
-        "/etc/systemd/network",
-        "/run/systemd/network",
-        "/usr/lib/systemd/network",
-#if HAVE_SPLIT_USR
-        "/lib/systemd/network",
-#endif
-        NULL};
-
 static void link_config_free(link_config *link) {
         if (!link)
                 return;
@@ -57,12 +50,13 @@ static void link_config_free(link_config *link) {
         strv_free(link->match_path);
         strv_free(link->match_driver);
         strv_free(link->match_type);
-        free(link->match_name);
-        free(link->match_host);
-        free(link->match_virt);
-        free(link->match_kernel_cmdline);
-        free(link->match_kernel_version);
-        free(link->match_arch);
+        strv_free(link->match_name);
+
+        condition_free_list(link->match_host);
+        condition_free_list(link->match_virt);
+        condition_free_list(link->match_kernel_cmdline);
+        condition_free_list(link->match_kernel_version);
+        condition_free_list(link->match_arch);
 
         free(link->description);
         free(link->mac);
@@ -100,8 +94,6 @@ void link_config_ctx_free(link_config_ctx *ctx) {
         return;
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
-
 int link_config_ctx_new(link_config_ctx **ret) {
         _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
 
@@ -123,56 +115,64 @@ int link_config_ctx_new(link_config_ctx **ret) {
         return 0;
 }
 
-static int load_link(link_config_ctx *ctx, const char *filename) {
+int link_load_one(link_config_ctx *ctx, const char *filename) {
         _cleanup_(link_config_freep) link_config *link = NULL;
         _cleanup_fclose_ FILE *file = NULL;
-        int i;
+        _cleanup_free_ char *name = NULL;
+        size_t i;
         int r;
 
         assert(ctx);
         assert(filename);
 
         file = fopen(filename, "re");
-        if (!file) {
-                if (errno == ENOENT)
-                        return 0;
-                else
-                        return -errno;
-        }
+        if (!file)
+                return errno == ENOENT ? 0 : -errno;
 
         if (null_or_empty_fd(fileno(file))) {
                 log_debug("Skipping empty file: %s", filename);
                 return 0;
         }
 
-        link = new0(link_config, 1);
+        name = strdup(filename);
+        if (!name)
+                return -ENOMEM;
+
+        link = new(link_config, 1);
         if (!link)
-                return log_oom();
+                return -ENOMEM;
 
-        link->mac_policy = _MACPOLICY_INVALID;
-        link->wol = _WOL_INVALID;
-        link->duplex = _DUP_INVALID;
-        link->port = _NET_DEV_PORT_INVALID;
-        link->autonegotiation = -1;
+        *link = (link_config) {
+                .filename = TAKE_PTR(name),
+                .mac_policy = _MACPOLICY_INVALID,
+                .wol = _WOL_INVALID,
+                .duplex = _DUP_INVALID,
+                .port = _NET_DEV_PORT_INVALID,
+                .autonegotiation = -1,
+        };
 
-        for (i = 0; i < (int)ELEMENTSOF(link->features); i++)
+        for (i = 0; i < ELEMENTSOF(link->features); i++)
                 link->features[i] = -1;
 
         r = config_parse(NULL, filename, file,
-                         "Match\0Link\0Ethernet\0",
+                         "Match\0Link\0",
                          config_item_perf_lookup, link_config_gperf_lookup,
                          CONFIG_PARSE_WARN, link);
         if (r < 0)
                 return r;
-        else
-                log_debug("Parsed configuration file %s", filename);
 
         if (link->speed > UINT_MAX)
                 return -ERANGE;
 
-        link->filename = strdup(filename);
-        if (!link->filename)
-                return log_oom();
+        if (!net_match_config(NULL, NULL, NULL, NULL, NULL,
+                              link->match_host, link->match_virt, link->match_kernel_cmdline,
+                              link->match_kernel_version, link->match_arch,
+                              NULL, NULL, NULL, NULL, NULL)) {
+                log_debug("%s: Conditions do not match the system environment, skipping.", filename);
+                return 0;
+        }
+
+        log_debug("Parsed configuration file %s", filename);
 
         LIST_PREPEND(links, ctx->links, link);
         link = NULL;
@@ -186,6 +186,22 @@ static bool enable_name_policy(void) {
         return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
 }
 
+static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
+        const char *s;
+        int r;
+
+        r = sd_device_get_sysattr_value(device, attr, &s);
+        if (r < 0)
+                return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
+
+        r = safe_atou(s, type);
+        if (r < 0)
+                return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
+
+        log_device_debug(device, "Device has %s=%u", attr, *type);
+        return 0;
+}
+
 int link_config_load(link_config_ctx *ctx) {
         _cleanup_strv_free_ char **files;
         char **f;
@@ -199,23 +215,23 @@ int link_config_load(link_config_ctx *ctx) {
         }
 
         /* update timestamp */
-        paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
+        paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
 
-        r = conf_files_list_strv(&files, ".link", NULL, 0, link_dirs);
+        r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
         if (r < 0)
                 return log_error_errno(r, "failed to enumerate link files: %m");
 
         STRV_FOREACH_BACKWARDS(f, files) {
-                r = load_link(ctx, *f);
+                r = link_load_one(ctx, *f);
                 if (r < 0)
-                        return r;
+                        log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
         }
 
         return 0;
 }
 
 bool link_config_should_reload(link_config_ctx *ctx) {
-        return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
+        return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
 }
 
 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
@@ -226,13 +242,10 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
         assert(ret);
 
         LIST_FOREACH(links, link, ctx->links) {
-                const char *address = NULL, *id_path = NULL, *parent_driver = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
-                sd_device *parent;
+                const char *address = NULL, *id_path = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
 
                 (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);
@@ -243,26 +256,23 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
                                      link->match_kernel_version, link->match_arch,
                                      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;
+                                unsigned name_assign_type = NET_NAME_UNKNOWN;
 
-                                if (sd_device_get_sysattr_value(device, "name_assign_type", &attr_value) >= 0)
-                                        (void) safe_atou8(attr_value, &name_assign_type);
+                                (void) link_unsigned_attribute(device, "name_assign_type", &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, sysname);
+                                                    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, sysname);
+                                                    link->filename, sysname);
 
                                         continue;
                                 }
@@ -272,69 +282,49 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
                                   link->filename, sysname);
 
                         *ret = link;
-
                         return 0;
                 }
         }
 
         *ret = NULL;
-
         return -ENOENT;
 }
 
-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 */
-        if (sd_device_get_sysattr_value(device, "addr_assign_type", &s) < 0)
-                return false;
-
-        r = safe_atou(s, &type);
-        if (r < 0)
-                return false;
-
-        return type == NET_ADDR_RANDOM;
-}
-
-static bool should_rename(sd_device *device, bool respect_predictable) {
-        const char *s;
-        unsigned type;
+static int get_mac(sd_device *device, MACPolicy policy, struct ether_addr *mac) {
+        unsigned addr_type;
+        bool want_random = policy == MACPOLICY_RANDOM;
         int r;
 
-        /* if we can't get the assgin type, assume we should rename */
-        if (sd_device_get_sysattr_value(device, "name_assign_type", &s) < 0)
-                return true;
+        assert(IN_SET(policy, MACPOLICY_RANDOM, MACPOLICY_PERSISTENT));
 
-        r = safe_atou(s, &type);
+        r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
         if (r < 0)
-                return true;
-
-        switch (type) {
-        case NET_NAME_PREDICTABLE:
-                /* the kernel claims to have given a predictable name */
-                if (respect_predictable)
-                        return false;
-                _fallthrough_;
+                return r;
+        switch (addr_type) {
+        case NET_ADDR_SET:
+                return log_device_debug(device, "MAC on the device already set by userspace");
+        case NET_ADDR_STOLEN:
+                return log_device_debug(device, "MAC on the device already set based on another device");
+        case NET_ADDR_RANDOM:
+        case NET_ADDR_PERM:
+                break;
         default:
-                /* the name is known to be bad, or of an unknown type */
-                return true;
+                return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
         }
-}
 
-static int get_mac(sd_device *device, bool want_random,
-                   struct ether_addr *mac) {
-        int r;
+        if (want_random == (addr_type == NET_ADDR_RANDOM))
+                return log_device_debug(device, "MAC on the device already matches policy *%s*",
+                                        mac_policy_to_string(policy));
 
-        if (want_random)
+        if (want_random) {
+                log_device_debug(device, "Using random bytes to generate MAC");
                 random_bytes(mac->ether_addr_octet, ETH_ALEN);
-        else {
+        else {
                 uint64_t result;
 
                 r = net_get_unique_predictable_data(device, &result);
                 if (r < 0)
-                        return r;
+                        return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
 
                 assert_cc(ETH_ALEN <= sizeof(result));
                 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
@@ -343,18 +333,17 @@ static int get_mac(sd_device *device, bool want_random,
         /* see eth_random_addr in the kernel */
         mac->ether_addr_octet[0] &= 0xfe;  /* clear multicast bit */
         mac->ether_addr_octet[0] |= 0x02;  /* set local assignment bit (IEEE802) */
-
-        return 0;
+        return 1;
 }
 
 int link_config_apply(link_config_ctx *ctx, link_config *config,
                       sd_device *device, const char **name) {
-        bool respect_predictable = false;
         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);
@@ -407,66 +396,69 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
         if (r < 0)
                 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
 
-        if (ctx->enable_name_policy && config->name_policy) {
-                NamePolicy *policy;
-
-                for (policy = config->name_policy;
-                     !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
-                        switch (*policy) {
-                                case NAMEPOLICY_KERNEL:
-                                        respect_predictable = true;
-                                        break;
-                                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:
-                                        break;
+
+        (void) link_unsigned_attribute(device, "name_assign_type", &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)
+                for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
+                        policy = *p;
+
+                        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 (!new_name && should_rename(device, respect_predictable))
+        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
+                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) {
-                                        log_warning_errno(r, "Could not generate persistent MAC address for %s: %m", old_name);
-                                        break;
-                                } else if (r < 0)
-                                        return r;
-                                mac = &generated_mac;
-                        }
-                        break;
-                case MACPOLICY_RANDOM:
-                        if (!mac_is_random(device)) {
-                                r = get_mac(device, true, &generated_mac);
-                                if (r == -ENOENT) {
-                                        log_warning_errno(r, "Could not generate random MAC address for %s: %m", old_name);
-                                        break;
-                                } else if (r < 0)
-                                        return r;
-                                mac = &generated_mac;
-                        }
-                        break;
-                case MACPOLICY_NONE:
-                default:
-                        mac = config->mac;
-        }
+        if (IN_SET(config->mac_policy, MACPOLICY_PERSISTENT, MACPOLICY_RANDOM)) {
+                if (get_mac(device, config->mac_policy, &generated_mac) > 0)
+                        mac = &generated_mac;
+        } else
+                mac = config->mac;
 
         r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
         if (r < 0)
@@ -497,7 +489,7 @@ int link_get_driver(link_config_ctx *ctx, sd_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);
@@ -506,11 +498,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);