[openwrt/openwrt] realtek: fix flooding of unsnoopable multicast addresses

LEDE Commits lede-commits at lists.infradead.org
Thu May 15 10:01:26 PDT 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/64ad16993dc423e29ed59effb6d4784e27ca8c31

commit 64ad16993dc423e29ed59effb6d4784e27ca8c31
Author: Linus Lüssing <linus.luessing at c0d3.blue>
AuthorDate: Sat May 10 05:22:22 2025 +0200

    realtek: fix flooding of unsnoopable multicast addresses
    
    RFC4541, section 2.1.2 says:
    
      Packets with a destination IP (DIP) address in the 224.0.0.X range
      which are not IGMP must be forwarded on all ports.
    
    And section 3 says:
    
      In IPv6, the data forwarding rules are more straight forward because
      MLD is mandated for addresses with scope 2 (link-scope) or greater.
      The only exception is the address FF02::1 which is the all hosts
      link-scope address for which MLD messages are never sent.  Packets
      with the all hosts link-scope address should be forwarded on all
      ports.
    
    However, currently when a listener on FF12::1 or FF12::1234:0:1 for
    example joins then not only packets to these addresses but also for
    FF02::1 won't be flooded to all ports anymore, too. Which violates
    RFC4541.
    
    This happens because A): They all map to the same ethernet multicast
    address, that is 33:33:00:00:00:01. And B) the VLAN profile L2
    unknown MC flood setting will only apply flooding of 33:33:00:00:00:01
    if there is no specific listener registered for it.
    
    So to fix this, avoid registering an MDB entry in the switch for
    33:33:00:00:00:01 at all.
    
    The downside of this is that FF12::1, FF12::1234:0:1 etc.
    will always be flooded, too. However fixing the handling of 224.0.0.X
    and FF02::1 and adhering to RFC4541 must have priority to avoid
    undesired packetloss, to avoid breaking IPv4/IPv6.
    
    Tested-on: ZyXEL GS1900-24HP v1
    
    Fixes: cde31976e375 ("realtek: Add support for Layer 2 Multicast")
    Signed-off-by: Linus Lüssing <linus.luessing at c0d3.blue>
    Link: https://github.com/openwrt/openwrt/pull/18769
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../files-6.6/drivers/net/dsa/rtl83xx/dsa.c        | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c
index 46683cbb14..fd018108ce 100644
--- a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c
+++ b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c
@@ -7,6 +7,15 @@
 
 #include "rtl83xx.h"
 
+static const u8 ipv4_ll_mcast_addr_base[ETH_ALEN] =
+{ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
+static const u8 ipv4_ll_mcast_addr_mask[ETH_ALEN] =
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+static const u8 ipv6_all_hosts_mcast_addr_base[ETH_ALEN] =
+{ 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 };
+static const u8 ipv6_all_hosts_mcast_addr_mask[ETH_ALEN] =
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
 extern struct rtl83xx_soc_info soc_info;
 
 static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv)
@@ -1752,6 +1761,24 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
 	return 0;
 }
 
+static bool rtl83xx_mac_is_unsnoop(const unsigned char *addr)
+{
+	/*
+	 * RFC4541, section 2.1.2.2 + section 3:
+	 * Unsnoopable address ranges must always be flooded.
+	 *
+	 * mapped MAC for 224.0.0.x -> 01:00:5e:00:00:xx
+	 * mapped MAC for ff02::1 -> 33:33:00:00:00:01
+	 */
+	if (ether_addr_equal_masked(addr, ipv4_ll_mcast_addr_base,
+				    ipv4_ll_mcast_addr_mask) ||
+	    ether_addr_equal_masked(addr, ipv6_all_hosts_mcast_addr_base,
+				    ipv6_all_hosts_mcast_addr_mask))
+		return true;
+
+	return false;
+}
+
 static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
 				const struct switchdev_obj_port_mdb *mdb,
 				const struct dsa_db db)
@@ -1774,6 +1801,13 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
 		return -EINVAL;
 	}
 
+	if (rtl83xx_mac_is_unsnoop(mdb->addr)) {
+		dev_dbg(priv->dev,
+			"%s: %pM might belong to an unsnoopable IP. ignore\n",
+			__func__, mdb->addr);
+		return -EADDRNOTAVAIL;
+	}
+
 	mutex_lock(&priv->reg_mutex);
 
 	idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e);
@@ -1847,6 +1881,13 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port,
 		return 0;
 	}
 
+	if (rtl83xx_mac_is_unsnoop(mdb->addr)) {
+		dev_dbg(priv->dev,
+			"%s: %pM might belong to an unsnoopable IP. ignore\n",
+			__func__, mdb->addr);
+		return 0;
+	}
+
 	mutex_lock(&priv->reg_mutex);
 
 	idx = rtl83xx_find_l2_hash_entry(priv, seed, true, &e);




More information about the lede-commits mailing list