diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-06-25 16:25:48 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-07-01 00:49:02 +0900 |
commit | fe321d457c118be5d1640b586135a69d1db9270a (patch) | |
tree | b520a6ed26f17218f47d5cf792df8622c002925b | |
parent | 6eab614db805504cec3af0c1c7b21ae6275a89a6 (diff) | |
download | systemd-fe321d457c118be5d1640b586135a69d1db9270a.tar.gz |
network: introduce link_get_by_hw_addr()
-rw-r--r-- | src/network/networkd-link.c | 48 | ||||
-rw-r--r-- | src/network/networkd-link.h | 1 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 1 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 1 |
4 files changed, 44 insertions, 7 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c3be8aa5c2..378420d9d3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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) diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index c133927fd6..28c2821ee6 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -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); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b95742f490..374d27bef3 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index cef5eb889b..4ee48f3468 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -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; |