system-linux: refresh MAC address on DSA port conduit change
authorChristian Marangi <ansuelsmth@gmail.com>
Sat, 11 Nov 2023 22:27:11 +0000 (23:27 +0100)
committerChristian Marangi <ansuelsmth@gmail.com>
Sat, 11 Nov 2023 22:36:48 +0000 (23:36 +0100)
On changing the conduit for a DSA port, the conduit may have different
a MAC address. In the scenario where a port is part of a bridge and
is the primary port, some inconsistency may arise where the bridge have
the MAC address of the previous conduit and is never updated.
This inconsistency cause problem with packet forwarding with FDB and
other related problems.

To fix this, refresh the original MAC address after the conduit for the
DSA port is changed by polling the new MAC address for the device using
ioctl API.

Fixes: 2dc7f450f3a2 ("system-linux: add option to configure DSA conduit device")
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
system-linux.c

index 21110c552157268e18514fa25e1590f9e5a31af4..cc1b5e969132c41ceaa38744faa07b9d94125436 100644 (file)
@@ -1842,6 +1842,17 @@ out:
        return ret;
 }
 
+static void system_refresh_orig_macaddr(struct device *dev, struct device_settings *s)
+{
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
+
+       if (ioctl(sock_ioctl, SIOCGIFHWADDR, &ifr) == 0)
+               memcpy(s->macaddr, &ifr.ifr_hwaddr.sa_data, sizeof(s->macaddr));
+}
+
 static void system_set_master(struct device *dev, int master_ifindex)
 {
        struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC, };
@@ -2322,12 +2333,14 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, uint64_t
                system_set_drop_unsolicited_na(dev, s->drop_unsolicited_na ? "1" : "0");
        if (apply_mask & DEV_OPT_ARP_ACCEPT)
                system_set_arp_accept(dev, s->arp_accept ? "1" : "0");
-       if (apply_mask & DEV_OPT_MASTER)
+       if (apply_mask & DEV_OPT_MASTER) {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)
                system_set_master(dev, s->master_ifindex);
+               system_refresh_orig_macaddr(dev, &dev->orig_settings);
 #else
                netifd_log_message(L_WARNING, "%s Your kernel is older than linux 6.1.0, changing DSA port conduit is not supported!", dev->ifname);
 #endif
+       }
        system_set_ethtool_settings(dev, s);
 }