|
@@ -80,7 +80,8 @@ struct mlxsw_sp_bridge_device {
|
|
|
struct list_head ports_list;
|
|
|
struct list_head mids_list;
|
|
|
u8 vlan_enabled:1,
|
|
|
- multicast_enabled:1;
|
|
|
+ multicast_enabled:1,
|
|
|
+ mrouter:1;
|
|
|
const struct mlxsw_sp_bridge_ops *ops;
|
|
|
};
|
|
|
|
|
@@ -171,6 +172,7 @@ mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
|
|
|
bridge_device->dev = br_dev;
|
|
|
bridge_device->vlan_enabled = vlan_enabled;
|
|
|
bridge_device->multicast_enabled = br_multicast_enabled(br_dev);
|
|
|
+ bridge_device->mrouter = br_multicast_router(br_dev);
|
|
|
INIT_LIST_HEAD(&bridge_device->ports_list);
|
|
|
if (vlan_enabled) {
|
|
|
bridge->vlan_enabled_exists = true;
|
|
@@ -813,6 +815,60 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int mlxsw_sp_smid_router_port_set(struct mlxsw_sp *mlxsw_sp,
|
|
|
+ u16 mid_idx, bool add)
|
|
|
+{
|
|
|
+ char *smid_pl;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
|
|
|
+ if (!smid_pl)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ mlxsw_reg_smid_pack(smid_pl, mid_idx,
|
|
|
+ mlxsw_sp_router_port(mlxsw_sp), add);
|
|
|
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
|
|
|
+ kfree(smid_pl);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+mlxsw_sp_bridge_mrouter_update_mdb(struct mlxsw_sp *mlxsw_sp,
|
|
|
+ struct mlxsw_sp_bridge_device *bridge_device,
|
|
|
+ bool add)
|
|
|
+{
|
|
|
+ struct mlxsw_sp_mid *mid;
|
|
|
+
|
|
|
+ list_for_each_entry(mid, &bridge_device->mids_list, list)
|
|
|
+ mlxsw_sp_smid_router_port_set(mlxsw_sp, mid->mid, add);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
+ struct switchdev_trans *trans,
|
|
|
+ struct net_device *orig_dev,
|
|
|
+ bool is_mrouter)
|
|
|
+{
|
|
|
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
|
|
+ struct mlxsw_sp_bridge_device *bridge_device;
|
|
|
+
|
|
|
+ if (switchdev_trans_ph_prepare(trans))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* It's possible we failed to enslave the port, yet this
|
|
|
+ * operation is executed due to it being deferred.
|
|
|
+ */
|
|
|
+ bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
|
|
|
+ if (!bridge_device)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (bridge_device->mrouter != is_mrouter)
|
|
|
+ mlxsw_sp_bridge_mrouter_update_mdb(mlxsw_sp, bridge_device,
|
|
|
+ is_mrouter);
|
|
|
+ bridge_device->mrouter = is_mrouter;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int mlxsw_sp_port_attr_set(struct net_device *dev,
|
|
|
const struct switchdev_attr *attr,
|
|
|
struct switchdev_trans *trans)
|
|
@@ -850,6 +906,11 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
|
|
|
attr->orig_dev,
|
|
|
attr->u.mc_disabled);
|
|
|
break;
|
|
|
+ case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
|
|
|
+ err = mlxsw_sp_port_attr_br_mrouter_set(mlxsw_sp_port, trans,
|
|
|
+ attr->orig_dev,
|
|
|
+ attr->u.mrouter);
|
|
|
+ break;
|
|
|
default:
|
|
|
err = -EOPNOTSUPP;
|
|
|
break;
|
|
@@ -1373,7 +1434,7 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
|
|
|
|
|
|
mid->mid = mid_idx;
|
|
|
err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap,
|
|
|
- false);
|
|
|
+ bridge_device->mrouter);
|
|
|
kfree(flood_bitmap);
|
|
|
if (err)
|
|
|
return false;
|