|
@@ -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)
|
|
|
{
|
|
@@ -317,7 +357,7 @@ static void __br_mdb_notify(struct net_device *dev, struct net_bridge_port *p,
|
|
|
#endif
|
|
|
|
|
|
mdb.obj.orig_dev = port_dev;
|
|
|
- if (port_dev && type == RTM_NEWMDB) {
|
|
|
+ if (p && port_dev && type == RTM_NEWMDB) {
|
|
|
complete_info = kmalloc(sizeof(*complete_info), GFP_ATOMIC);
|
|
|
if (complete_info) {
|
|
|
complete_info->port = p;
|
|
@@ -327,10 +367,13 @@ static void __br_mdb_notify(struct net_device *dev, struct net_bridge_port *p,
|
|
|
if (switchdev_port_obj_add(port_dev, &mdb.obj))
|
|
|
kfree(complete_info);
|
|
|
}
|
|
|
- } else if (port_dev && type == RTM_DELMDB) {
|
|
|
+ } else if (p && port_dev && type == RTM_DELMDB) {
|
|
|
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;
|
|
@@ -353,7 +396,10 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
|
|
|
struct br_mdb_entry entry;
|
|
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
|
|
- entry.ifindex = port->dev->ifindex;
|
|
|
+ if (port)
|
|
|
+ entry.ifindex = port->dev->ifindex;
|
|
|
+ else
|
|
|
+ entry.ifindex = dev->ifindex;
|
|
|
entry.addr.proto = group->proto;
|
|
|
entry.addr.u.ip4 = group->u.ip4;
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
@@ -655,7 +701,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
|
|
|
call_rcu_bh(&p->rcu, br_multicast_free_pg);
|
|
|
err = 0;
|
|
|
|
|
|
- if (!mp->ports && !mp->mglist &&
|
|
|
+ if (!mp->ports && !mp->host_joined &&
|
|
|
netif_running(br->dev))
|
|
|
mod_timer(&mp->timer, jiffies);
|
|
|
break;
|