]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #11373 from tomty89/auto
authorLennart Poettering <lennart@poettering.net>
Fri, 15 Feb 2019 10:31:55 +0000 (11:31 +0100)
committerGitHub <noreply@github.com>
Fri, 15 Feb 2019 10:31:55 +0000 (11:31 +0100)
mount/generators: do not make unit wanted by its device unit

NEWS
README.md
rules/60-block.rules
src/basic/missing_network.h
src/core/unit.c
src/libsystemd-network/network-internal.c
src/login/logind-dbus.c
src/test/test-libudev.c
src/udev/net/link-config.c
test/test-network/conf/25-bind-carrier.network [new file with mode: 0644]
test/test-network/systemd-networkd-tests.py

diff --git a/NEWS b/NEWS
index cd81d9ca35b76b7570565b400777c0b72bf90dea..f61262fd570c6c2777663b0f412a0afee2c5ee91 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -83,6 +83,9 @@ CHANGES WITH 241:
         * udevadm control learnt a new option for --ping for testing whether a
           systemd-udevd instance is running and reacting.
 
+        * udevadm trigger learnt a new option for --wait-daemon for waiting
+          systemd-udevd daemon to be initialized.
+
         Contributions from: Aaron Plattner, Alberts Muktupāvels, Alex Mayer,
         Ayman Bagabas, Beniamino Galvani, Burt P, Chris Down, Chris Lamb, Chris
         Morin, Christian Hesse, Claudius Ellsel, dana, Daniel Axtens, Daniele
@@ -101,7 +104,7 @@ CHANGES WITH 241:
         Miettinen, YiFei Zhu, YmrDtnJu, YunQiang Su, Yu Watanabe, Zbigniew
         Jędrzejewski-Szmek, zsergeant77, Дамјан Георгиевски
 
-        — Berlin, 2018-02-14
+        — Berlin, 2019-02-14
 
 CHANGES WITH 240:
 
index 31d530733aa88ce282e1ced58574735f16f8a5bd..72484f620c1acfeff010b18ed80bab2f9e5dce0e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
 <a href="https://in.waw.pl/systemd-github-state/systemd-systemd-issues.svg"><img align="right" src="https://in.waw.pl/systemd-github-state/systemd-systemd-issues-small.svg" alt="Count of open issues over time"></a>
 <a href="https://in.waw.pl/systemd-github-state/systemd-systemd-pull-requests.svg"><img align="right" src="https://in.waw.pl/systemd-github-state/systemd-systemd-pull-requests-small.svg" alt="Count of open pull requests over time"></a>
 [![Semaphore CI Build Status](https://semaphoreci.com/api/v1/projects/28a5a3ca-3c56-4078-8b5e-7ed6ef912e14/443470/shields_badge.svg)](https://semaphoreci.com/systemd/systemd)<br/>
+[![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/>
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
 [![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
 [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>
index a1458e91887f7efbf4ad1bf58a66e8177af34be3..491081f0b2bd7a4a8e58558fd137557552f130fa 100644 (file)
@@ -8,4 +8,4 @@ ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_
 ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
 
 # watch metadata changes, caused by tools closing the device node which was opened for writing
-ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*|xvd*|pmem*|mmcblk*|dasd*", OPTIONS+="watch"
+ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*|xvd*|pmem*|mmcblk*|dasd*|nbd*", OPTIONS+="watch"
index 59a8cd2c60892f43b5791f781b0f3f96955053da..80ef13fd3ea0f7f450b6262c9352971ed54c5485 100644 (file)
 #endif
 
 /* netdevice.h */
+#ifndef NET_ADDR_PERM
+#define NET_ADDR_PERM 0
+#endif
+
 #ifndef NET_ADDR_RANDOM
 #define NET_ADDR_RANDOM 1
 #endif
 
+#ifndef NET_ADDR_STOLEN
+#define NET_ADDR_STOLEN 2
+#endif
+
+#ifndef NET_ADDR_SET
+#define NET_ADDR_SET 3
+#endif
+
 #ifndef NET_NAME_UNKNOWN
 #define NET_NAME_UNKNOWN 0
 #endif
index 24b14fbcd63759791cebea6882e3f1d1df1cbd10..f4888ff45016392090628d8b90e08819ad3c0c68 100644 (file)
@@ -1895,7 +1895,7 @@ int unit_reload(Unit *u) {
 
         state = unit_active_state(u);
         if (state == UNIT_RELOADING)
-                return -EALREADY;
+                return -EAGAIN;
 
         if (state != UNIT_ACTIVE) {
                 log_unit_warning(u, "Unit cannot be reloaded because it is inactive.");
index 0348e7fa9dabe93ce39f2bddc8c5f1c5300afa8b..a0209caf3a8163417e3eb2f04bf930a77cd09863 100644 (file)
@@ -10,6 +10,7 @@
 #include "alloc-util.h"
 #include "condition.h"
 #include "conf-parser.h"
+#include "device-util.h"
 #include "dhcp-lease-internal.h"
 #include "ether-addr-util.h"
 #include "hexdecoct.h"
@@ -40,31 +41,35 @@ const char *net_get_name(sd_device *device) {
 
 int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
         size_t l, sz = 0;
-        const char *name = NULL;
+        const char *name;
         int r;
         uint8_t *v;
 
         assert(device);
 
+        /* net_get_name() will return one of the device names based on stable information about the
+         * device. If this is not available, we fall back to using the device name. */
         name = net_get_name(device);
         if (!name)
-                return -ENOENT;
+                (void) sd_device_get_sysname(device, &name);
+        if (!name)
+                return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
+                                              "No stable identifying information found");
 
+        log_device_debug(device, "Using \"%s\" as stable identifying information", name);
         l = strlen(name);
         sz = sizeof(sd_id128_t) + l;
         v = newa(uint8_t, sz);
 
-        /* fetch some persistent data unique to this machine */
+        /* Fetch some persistent data unique to this machine */
         r = sd_id128_get_machine((sd_id128_t*) v);
         if (r < 0)
                  return r;
         memcpy(v + sizeof(sd_id128_t), name, l);
 
-        /* Let's hash the machine ID plus the device name. We
-        * use a fixed, but originally randomly created hash
-        * key here. */
+        /* Let's hash the machine ID plus the device name. We use
+         * a fixed, but originally randomly created hash key here. */
         *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
-
         return 0;
 }
 
index 8ab498fdc297af7e0c022b9fa332f71eb1f78540..b9ea370ec009ab9ccdf95c4440ddc2a8b9e93d9e 100644 (file)
@@ -790,7 +790,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                 goto fail;
 
         session_set_user(session, user);
-        session_set_leader(session, leader);
+        r = session_set_leader(session, leader);
+        if (r < 0)
+                goto fail;
 
         session->type = t;
         session->class = c;
index 15c0f8853d43478a5e91a3bd348821415ea63d16..f634ca28dbdf29e49c899390e3ad849024bbe036 100644 (file)
 #include "libudev-list-internal.h"
 #include "libudev-util.h"
 #include "log.h"
+#include "main-func.h"
 #include "stdio-util.h"
 #include "string-util.h"
+#include "tests.h"
+
+static bool arg_monitor = false;
 
 static void print_device(struct udev_device *device) {
         const char *str;
@@ -23,7 +27,7 @@ static void print_device(struct udev_device *device) {
 
         log_info("*** device: %p ***", device);
         str = udev_device_get_action(device);
-        if (str != NULL)
+        if (str)
                 log_info("action:    '%s'", str);
 
         str = udev_device_get_syspath(device);
@@ -33,26 +37,26 @@ static void print_device(struct udev_device *device) {
         log_info("sysname:   '%s'", str);
 
         str = udev_device_get_sysnum(device);
-        if (str != NULL)
+        if (str)
                 log_info("sysnum:    '%s'", str);
 
         str = udev_device_get_devpath(device);
         log_info("devpath:   '%s'", str);
 
         str = udev_device_get_subsystem(device);
-        if (str != NULL)
+        if (str)
                 log_info("subsystem: '%s'", str);
 
         str = udev_device_get_devtype(device);
-        if (str != NULL)
+        if (str)
                 log_info("devtype:   '%s'", str);
 
         str = udev_device_get_driver(device);
-        if (str != NULL)
+        if (str)
                 log_info("driver:    '%s'", str);
 
         str = udev_device_get_devnode(device);
-        if (str != NULL)
+        if (str)
                 log_info("devname:   '%s'", str);
 
         devnum = udev_device_get_devnum(device);
@@ -78,30 +82,30 @@ static void print_device(struct udev_device *device) {
                 log_info("found %i properties", count);
 
         str = udev_device_get_property_value(device, "MAJOR");
-        if (str != NULL)
+        if (str)
                 log_info("MAJOR: '%s'", str);
 
         str = udev_device_get_sysattr_value(device, "dev");
-        if (str != NULL)
+        if (str)
                 log_info("attr{dev}: '%s'", str);
 }
 
 static void test_device(struct udev *udev, const char *syspath) {
         _cleanup_(udev_device_unrefp) struct udev_device *device;
 
-        log_info("looking at device: %s", syspath);
+        log_info("/* %s, device %s */", __func__, syspath);
         device = udev_device_new_from_syspath(udev, syspath);
-        if (device == NULL)
-                log_warning_errno(errno, "udev_device_new_from_syspath: %m");
-        else
+        if (device)
                 print_device(device);
+        else
+                log_warning_errno(errno, "udev_device_new_from_syspath: %m");
 }
 
 static void test_device_parents(struct udev *udev, const char *syspath) {
         _cleanup_(udev_device_unrefp) struct udev_device *device;
         struct udev_device *device_parent;
 
-        log_info("looking at device: %s", syspath);
+        log_info("/* %s, device %s */", __func__, syspath);
         device = udev_device_new_from_syspath(udev, syspath);
         if (device == NULL)
                 return;
@@ -125,12 +129,13 @@ static void test_device_devnum(struct udev *udev) {
         dev_t devnum = makedev(1, 3);
         _cleanup_(udev_device_unrefp) struct udev_device *device;
 
-        log_info("looking up device: %u:%u", major(devnum), minor(devnum));
+        log_info("/* %s, device %d:%d */", __func__, major(devnum), minor(devnum));
+
         device = udev_device_new_from_devnum(udev, 'c', devnum);
-        if (device == NULL)
-                log_warning_errno(errno, "udev_device_new_from_devnum: %m");
-        else
+        if (device)
                 print_device(device);
+        else
+                log_warning_errno(errno, "udev_device_new_from_devnum: %m");
 }
 
 static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) {
@@ -144,7 +149,7 @@ static void test_device_subsys_name(struct udev *udev, const char *subsys, const
                 print_device(device);
 }
 
-static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
+static int enumerate_print_list(struct udev_enumerate *enumerate) {
         struct udev_list_entry *list_entry;
         int count = 0;
 
@@ -176,6 +181,8 @@ static void test_monitor(struct udev *udev) {
                 .data.fd = STDIN_FILENO,
         };
 
+        log_info("/* %s */", __func__);
+
         fd_ep = epoll_create1(EPOLL_CLOEXEC);
         assert_se(fd_ep >= 0);
 
@@ -225,8 +232,9 @@ static void test_queue(struct udev *udev) {
         struct udev_queue *udev_queue;
         bool empty;
 
-        udev_queue = udev_queue_new(udev);
-        assert_se(udev_queue);
+        log_info("/* %s */", __func__);
+
+        assert_se(udev_queue = udev_queue_new(udev));
 
         empty = udev_queue_get_queue_is_empty(udev_queue);
         log_info("queue is %s", empty ? "empty" : "not empty");
@@ -237,13 +245,15 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         struct udev_enumerate *udev_enumerate;
         int r;
 
+        log_info("/* %s */", __func__);
+
         log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem);
         udev_enumerate = udev_enumerate_new(udev);
         if (udev_enumerate == NULL)
                 return -1;
         udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'net' + duplicated scan + null + zero");
@@ -263,7 +273,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
         udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'block'");
@@ -277,7 +287,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
                 return r;
         }
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'not block'");
@@ -286,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
                 return -1;
         udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'pci, mem, vc'");
@@ -297,7 +307,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
         udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'subsystem'");
@@ -305,7 +315,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         if (udev_enumerate == NULL)
                 return -1;
         udev_enumerate_scan_subsystems(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'property IF_FS_*=filesystem'");
@@ -314,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
                 return -1;
         udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
         return 0;
 }
@@ -323,7 +333,11 @@ static void test_hwdb(struct udev *udev, const char *modalias) {
         struct udev_hwdb *hwdb;
         struct udev_list_entry *entry;
 
+        log_info("/* %s */", __func__);
+
         hwdb = udev_hwdb_new(udev);
+        if (!hwdb)
+                log_warning_errno(errno, "Failed to open hwdb: %m");
 
         udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
                 log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
@@ -348,6 +362,8 @@ static void test_util_replace_whitespace_one(const char *str, const char *expect
 }
 
 static void test_util_replace_whitespace(void) {
+        log_info("/* %s */", __func__);
+
         test_util_replace_whitespace_one("hogehoge", "hogehoge");
         test_util_replace_whitespace_one("hoge  hoge", "hoge_hoge");
         test_util_replace_whitespace_one("  hoge  hoge  ", "hoge_hoge");
@@ -385,16 +401,19 @@ static void test_util_replace_whitespace(void) {
 }
 
 static void test_util_resolve_subsys_kernel_one(const char *str, bool read_value, int retval, const char *expected) {
-        char result[UTIL_PATH_SIZE];
+        char result[UTIL_PATH_SIZE] = "";
         int r;
 
         r = util_resolve_subsys_kernel(str, result, sizeof(result), read_value);
+        log_info("\"%s\" → expect: \"%s\", %d, actual: \"%s\", %d", str, strnull(expected), retval, result, r);
         assert_se(r == retval);
         if (r >= 0)
                 assert_se(streq(result, expected));
 }
 
 static void test_util_resolve_subsys_kernel(void) {
+        log_info("/* %s */", __func__);
+
         test_util_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL);
         test_util_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL);
         test_util_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL);
@@ -471,9 +490,7 @@ static void test_list(void) {
         udev_list_cleanup(&list);
 }
 
-int main(int argc, char *argv[]) {
-        _cleanup_(udev_unrefp) struct udev *udev = NULL;
-        bool arg_monitor = false;
+static int parse_args(int argc, char *argv[], const char **syspath, const char **subsystem) {
         static const struct option options[] = {
                 { "syspath",   required_argument, NULL, 'p' },
                 { "subsystem", required_argument, NULL, 's' },
@@ -483,52 +500,59 @@ int main(int argc, char *argv[]) {
                 { "monitor",   no_argument,       NULL, 'm' },
                 {}
         };
-        const char *syspath = "/devices/virtual/mem/null";
-        const char *subsystem = NULL;
         int c;
 
-        udev = udev_new();
-        log_info("context: %p", udev);
-        if (udev == NULL) {
-                log_info("no context");
-                return 1;
-        }
-
         while ((c = getopt_long(argc, argv, "p:s:dhVm", options, NULL)) >= 0)
                 switch (c) {
-
                 case 'p':
-                        syspath = optarg;
+                        *syspath = optarg;
                         break;
 
                 case 's':
-                        subsystem = optarg;
+                        *subsystem = optarg;
                         break;
 
                 case 'd':
-                        if (log_get_max_level() < LOG_INFO)
-                                log_set_max_level(LOG_INFO);
+                        log_set_max_level(LOG_DEBUG);
                         break;
 
                 case 'h':
                         printf("--debug --syspath= --subsystem= --help\n");
-                        return EXIT_SUCCESS;
+                        return 0;
 
                 case 'V':
                         printf("%s\n", GIT_VERSION);
-                        return EXIT_SUCCESS;
+                        return 0;
 
                 case 'm':
                         arg_monitor = true;
                         break;
 
                 case '?':
-                        return EXIT_FAILURE;
+                        return -EINVAL;
 
                 default:
                         assert_not_reached("Unhandled option code.");
                 }
 
+        return 1;
+}
+
+static int run(int argc, char *argv[]) {
+        _cleanup_(udev_unrefp) struct udev *udev = NULL;
+
+        const char *syspath = "/devices/virtual/mem/null";
+        const char *subsystem = NULL;
+        int r;
+
+        test_setup_logging(LOG_INFO);
+
+        r = parse_args(argc, argv, &syspath, &subsystem);
+        if (r <= 0)
+                return r;
+
+        assert_se(udev = udev_new());
+
         /* add sys path if needed */
         if (!startswith(syspath, "/sys"))
                 syspath = strjoina("/sys/", syspath);
@@ -555,5 +579,7 @@ int main(int argc, char *argv[]) {
 
         test_list();
 
-        return EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index eb2477cea418b37c07bcda5d7d3b6a079741cf15..60da08a86ff390c28e6cccbc7a34c118c0a88545 100644 (file)
@@ -187,19 +187,19 @@ 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) {
+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, "name_assign_type", &s);
+        r = sd_device_get_sysattr_value(device, attr, &s);
         if (r < 0)
-                return log_device_debug_errno(device, r, "Failed to query name_assign_type: %m");
+                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 name_assign_type \"%s\": %m", s);
+                return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
 
-        log_device_debug(device, "Device has name_assign_type=%d", *type);
+        log_device_debug(device, "Device has %s=%u", attr, *type);
         return 0;
 }
 
@@ -265,11 +265,9 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
                                      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'",
@@ -297,34 +295,41 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
         return -ENOENT;
 }
 
-static bool mac_is_random(sd_device *device) {
-        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 assign type, assume it is not random */
-        if (sd_device_get_sysattr_value(device, "addr_assign_type", &s) < 0)
-                return false;
+        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 false;
-
-        return type == NET_ADDR_RANDOM;
-}
+                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:
+                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);
@@ -333,8 +338,7 @@ 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,
@@ -398,7 +402,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
 
 
-        (void) link_name_type(device, &name_type);
+        (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)) {
@@ -455,33 +459,11 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                 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)
diff --git a/test/test-network/conf/25-bind-carrier.network b/test/test-network/conf/25-bind-carrier.network
new file mode 100644 (file)
index 0000000..cf854d3
--- /dev/null
@@ -0,0 +1,8 @@
+[Match]
+Name=test1
+
+[Network]
+BindCarrier=dummy99 dummy98
+Address=192.168.10.30/24
+Gateway=192.168.10.1
+IPv6AcceptRA=no
index 1fc7094d281664896bc41a36d31a7548fb39abca..ad7ae9df63fe783225fb9a4ccb88f7d7e70e2721 100755 (executable)
@@ -548,6 +548,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
     links = [
         'bond199',
         'dummy98',
+        'dummy99',
         'test1']
 
     units = [
@@ -560,6 +561,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         '25-address-link-section.network',
         '25-address-section-miscellaneous.network',
         '25-address-section.network',
+        '25-bind-carrier.network',
         '25-bond-active-backup-slave.netdev',
         '25-fibrule-invert.network',
         '25-fibrule-port-range.network',
@@ -937,6 +939,64 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
         self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
 
+    def test_bind_carrier(self):
+        self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('test1'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertNotRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'DOWN')
+        self.assertNotRegex(output, '192.168.10')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: off \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
 class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
     links = [
         'bridge99',