@@ -304,6 +304,21 @@ int link_get_by_name(Manager *m, const char *ifname, Link **ret) {
304304 return 0 ;
305305}
306306
307+ int link_get_by_hw_addr (Manager * m , const struct hw_addr_data * hw_addr , Link * * ret ) {
308+ Link * link ;
309+
310+ assert (m );
311+ assert (hw_addr );
312+
313+ link = hashmap_get (m -> links_by_hw_addr , hw_addr );
314+ if (!link )
315+ return - ENODEV ;
316+
317+ if (ret )
318+ * ret = link ;
319+ return 0 ;
320+ }
321+
307322int link_get_master (Link * link , Link * * ret ) {
308323 assert (link );
309324 assert (link -> manager );
@@ -961,9 +976,12 @@ static Link *link_drop(Link *link) {
961976
962977 STRV_FOREACH (n , link -> alternative_names )
963978 hashmap_remove (link -> manager -> links_by_name , * n );
964-
965979 hashmap_remove (link -> manager -> links_by_name , link -> ifname );
966980
981+ /* bonding master and its slaves have the same hardware address. */
982+ if (hashmap_get (link -> manager -> links_by_hw_addr , & link -> hw_addr ) == link )
983+ hashmap_remove (link -> manager -> links_by_hw_addr , & link -> hw_addr );
984+
967985 /* The following must be called at last. */
968986 assert_se (hashmap_remove (link -> manager -> links_by_index , INT_TO_PTR (link -> ifindex )) == link );
969987 return link_unref (link );
@@ -1974,7 +1992,7 @@ static int link_update_master(Link *link, sd_netlink_message *message) {
19741992}
19751993
19761994static int link_update_hardware_address (Link * link , sd_netlink_message * message ) {
1977- struct hw_addr_data hw_addr ;
1995+ struct hw_addr_data old ;
19781996 int r ;
19791997
19801998 assert (link );
@@ -1984,18 +2002,34 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
19842002 if (r < 0 && r != - ENODATA )
19852003 return log_link_debug_errno (link , r , "rtnl: failed to read broadcast address: %m" );
19862004
1987- r = netlink_message_read_hw_addr (message , IFLA_ADDRESS , & hw_addr );
2005+ old = link -> hw_addr ;
2006+ r = netlink_message_read_hw_addr (message , IFLA_ADDRESS , & link -> hw_addr );
19882007 if (r == - ENODATA )
19892008 return 0 ;
19902009 if (r < 0 )
1991- return log_link_warning_errno (link , r , "rtnl: failed to read hardware address: %m" );
2010+ return log_link_debug_errno (link , r , "rtnl: failed to read hardware address: %m" );
19922011
1993- if (hw_addr_equal (& link -> hw_addr , & hw_addr ))
2012+ if (hw_addr_equal (& link -> hw_addr , & old ))
19942013 return 0 ;
19952014
1996- link -> hw_addr = hw_addr ;
2015+ if (hw_addr_is_null (& old ))
2016+ log_link_debug (link , "Saved hardware address: %s" , HW_ADDR_TO_STR (& link -> hw_addr ));
2017+ else {
2018+ log_link_debug (link , "Hardware address is changed: %s → %s" ,
2019+ HW_ADDR_TO_STR (& old ), HW_ADDR_TO_STR (& link -> hw_addr ));
19972020
1998- log_link_debug (link , "Gained new hardware address: %s" , HW_ADDR_TO_STR (& hw_addr ));
2021+ if (hashmap_get (link -> manager -> links_by_hw_addr , & old ) == link )
2022+ hashmap_remove (link -> manager -> links_by_hw_addr , & old );
2023+ }
2024+
2025+ if (!hw_addr_is_null (& link -> hw_addr )) {
2026+ r = hashmap_ensure_put (& link -> manager -> links_by_hw_addr , & hw_addr_hash_ops , & link -> hw_addr , link );
2027+ if (r == - EEXIST && streq_ptr (link -> kind , "bond" ))
2028+ /* bonding master and its slaves have the same hardware address. */
2029+ r = hashmap_replace (link -> manager -> links_by_hw_addr , & link -> hw_addr , link );
2030+ if (r < 0 )
2031+ log_link_debug_errno (link , r , "Failed to manage link by its new hardware address, ignoring: %m" );
2032+ }
19992033
20002034 r = ipv4ll_update_mac (link );
20012035 if (r < 0 )
0 commit comments