|
@@ -292,6 +292,46 @@ err:
|
|
|
kfree(priv);
|
|
|
}
|
|
|
|
|
|
+static void br_mdb_switchdev_host_port(struct net_device *dev,
|
|
|
+ struct net_device *lower_dev,
|
|
|
+ struct br_mdb_entry *entry, int type)
|
|
|
+{
|
|
|
+ struct switchdev_obj_port_mdb mdb = {
|
|
|
+ .obj = {
|
|
|
+ .id = SWITCHDEV_OBJ_ID_HOST_MDB,
|
|
|
+ .flags = SWITCHDEV_F_DEFER,
|
|
|
+ },
|
|
|
+ .vid = entry->vid,
|
|
|
+ };
|
|
|
+
|
|
|
+ if (entry->addr.proto == htons(ETH_P_IP))
|
|
|
+ ip_eth_mc_map(entry->addr.u.ip4, mdb.addr);
|
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
|
+ else
|
|
|
+ ipv6_eth_mc_map(&entry->addr.u.ip6, mdb.addr);
|
|
|
+#endif
|
|
|
+
|
|
|
+ mdb.obj.orig_dev = dev;
|
|
|
+ switch (type) {
|
|
|
+ case RTM_NEWMDB:
|
|
|
+ switchdev_port_obj_add(lower_dev, &mdb.obj);
|
|
|
+ break;
|
|
|
+ case RTM_DELMDB:
|
|
|
+ switchdev_port_obj_del(lower_dev, &mdb.obj);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void br_mdb_switchdev_host(struct net_device *dev,
|
|
|
+ struct br_mdb_entry *entry, int type)
|
|
|
+{
|
|
|
+ struct net_device *lower_dev;
|
|
|
+ struct list_head *iter;
|
|
|
+
|
|
|
+ netdev_for_each_lower_dev(dev, lower_dev, iter)
|
|
|
+ br_mdb_switchdev_host_port(dev, lower_dev, entry, type);
|
|
|
+}
|
|
|
+
|
|
|
static void __br_mdb_notify(struct net_device *dev, struct net_bridge_port *p,
|
|
|
struct br_mdb_entry *entry, int type)
|
|
|
{
|
|
@@ -331,6 +371,9 @@ static void __br_mdb_notify(struct net_device *dev, struct net_bridge_port *p,
|
|
|
switchdev_port_obj_del(port_dev, &mdb.obj);
|
|
|
}
|
|
|
|
|
|
+ if (!p)
|
|
|
+ br_mdb_switchdev_host(dev, entry, type);
|
|
|
+
|
|
|
skb = nlmsg_new(rtnl_mdb_nlmsg_size(), GFP_ATOMIC);
|
|
|
if (!skb)
|
|
|
goto errout;
|