]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: introduce link_get_by_hw_addr()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 25 Jun 2021 07:25:48 +0000 (16:25 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 30 Jun 2021 15:49:02 +0000 (00:49 +0900)
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager.c
src/network/networkd-manager.h

index c3be8aa5c207d5182d198648f818edc86bc74f10..378420d9d3e09d7493e9374964f6f86bc2288e32 100644 (file)
@@ -304,6 +304,21 @@ int link_get_by_name(Manager *m, const char *ifname, Link **ret) {
         return 0;
 }
 
+int link_get_by_hw_addr(Manager *m, const struct hw_addr_data *hw_addr, Link **ret) {
+        Link *link;
+
+        assert(m);
+        assert(hw_addr);
+
+        link = hashmap_get(m->links_by_hw_addr, hw_addr);
+        if (!link)
+                return -ENODEV;
+
+        if (ret)
+                *ret = link;
+        return 0;
+}
+
 int link_get_master(Link *link, Link **ret) {
         assert(link);
         assert(link->manager);
@@ -961,9 +976,12 @@ static Link *link_drop(Link *link) {
 
         STRV_FOREACH(n, link->alternative_names)
                 hashmap_remove(link->manager->links_by_name, *n);
-
         hashmap_remove(link->manager->links_by_name, link->ifname);
 
+        /* bonding master and its slaves have the same hardware address. */
+        if (hashmap_get(link->manager->links_by_hw_addr, &link->hw_addr) == link)
+                hashmap_remove(link->manager->links_by_hw_addr, &link->hw_addr);
+
         /* The following must be called at last. */
         assert_se(hashmap_remove(link->manager->links_by_index, INT_TO_PTR(link->ifindex)) == link);
         return link_unref(link);
@@ -1974,7 +1992,7 @@ static int link_update_master(Link *link, sd_netlink_message *message) {
 }
 
 static int link_update_hardware_address(Link *link, sd_netlink_message *message) {
-        struct hw_addr_data hw_addr;
+        struct hw_addr_data old;
         int r;
 
         assert(link);
@@ -1984,18 +2002,34 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
         if (r < 0 && r != -ENODATA)
                 return log_link_debug_errno(link, r, "rtnl: failed to read broadcast address: %m");
 
-        r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, &hw_addr);
+        old = link->hw_addr;
+        r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, &link->hw_addr);
         if (r == -ENODATA)
                 return 0;
         if (r < 0)
-                return log_link_warning_errno(link, r, "rtnl: failed to read hardware address: %m");
+                return log_link_debug_errno(link, r, "rtnl: failed to read hardware address: %m");
 
-        if (hw_addr_equal(&link->hw_addr, &hw_addr))
+        if (hw_addr_equal(&link->hw_addr, &old))
                 return 0;
 
-        link->hw_addr = hw_addr;
+        if (hw_addr_is_null(&old))
+                log_link_debug(link, "Saved hardware address: %s", HW_ADDR_TO_STR(&link->hw_addr));
+        else {
+                log_link_debug(link, "Hardware address is changed: %s → %s",
+                               HW_ADDR_TO_STR(&old), HW_ADDR_TO_STR(&link->hw_addr));
 
-        log_link_debug(link, "Gained new hardware address: %s", HW_ADDR_TO_STR(&hw_addr));
+                if (hashmap_get(link->manager->links_by_hw_addr, &old) == link)
+                        hashmap_remove(link->manager->links_by_hw_addr, &old);
+        }
+
+        if (!hw_addr_is_null(&link->hw_addr)) {
+                r = hashmap_ensure_put(&link->manager->links_by_hw_addr, &hw_addr_hash_ops, &link->hw_addr, link);
+                if (r == -EEXIST && streq_ptr(link->kind, "bond"))
+                        /* bonding master and its slaves have the same hardware address. */
+                        r = hashmap_replace(link->manager->links_by_hw_addr, &link->hw_addr, link);
+                if (r < 0)
+                        log_link_debug_errno(link, r, "Failed to manage link by its new hardware address, ignoring: %m");
+        }
 
         r = ipv4ll_update_mac(link);
         if (r < 0)
index c133927fd66c4fd39735008e5333ecc7bc224f41..28c2821ee6d322e115f780eae5380c2083f493b1 100644 (file)
@@ -220,6 +220,7 @@ DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
 
 int link_get_by_index(Manager *m, int ifindex, Link **ret);
 int link_get_by_name(Manager *m, const char *ifname, Link **ret);
+int link_get_by_hw_addr(Manager *m, const struct hw_addr_data *hw_addr, Link **ret);
 int link_get_master(Link *link, Link **ret);
 
 int link_getlink_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
index b95742f490773f558c93f09da489694ddd3618d2..374d27bef34cd2654ce025a5a087eca1658cdf41 100644 (file)
@@ -462,6 +462,7 @@ Manager* manager_free(Manager *m) {
         m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
         m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
         m->links_by_name = hashmap_free(m->links_by_name);
+        m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
         m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
 
         m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
index cef5eb889bc1e64061503a456fb3b7189bfcccac..4ee48f3468bf92b25ad582e97a062b4401876e98 100644 (file)
@@ -46,6 +46,7 @@ struct Manager {
 
         Hashmap *links_by_index;
         Hashmap *links_by_name;
+        Hashmap *links_by_hw_addr;
         Hashmap *netdevs;
         OrderedHashmap *networks;
         Hashmap *dhcp6_prefixes;