|
@@ -49,6 +49,7 @@
|
|
|
#include <linux/netlink.h>
|
|
|
#include <net/switchdev.h>
|
|
|
|
|
|
+#include "spectrum_router.h"
|
|
|
#include "spectrum.h"
|
|
|
#include "core.h"
|
|
|
#include "reg.h"
|
|
@@ -79,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;
|
|
|
};
|
|
|
|
|
@@ -170,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;
|
|
@@ -812,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)
|
|
@@ -849,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;
|
|
@@ -1243,7 +1305,8 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
|
|
|
}
|
|
|
|
|
|
static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx,
|
|
|
- long *ports_bitmap)
|
|
|
+ long *ports_bitmap,
|
|
|
+ bool set_router_port)
|
|
|
{
|
|
|
char *smid_pl;
|
|
|
int err, i;
|
|
@@ -1258,9 +1321,15 @@ static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx,
|
|
|
mlxsw_reg_smid_port_mask_set(smid_pl, i, 1);
|
|
|
}
|
|
|
|
|
|
+ mlxsw_reg_smid_port_mask_set(smid_pl,
|
|
|
+ mlxsw_sp_router_port(mlxsw_sp), 1);
|
|
|
+
|
|
|
for_each_set_bit(i, ports_bitmap, mlxsw_core_max_ports(mlxsw_sp->core))
|
|
|
mlxsw_reg_smid_port_set(smid_pl, i, 1);
|
|
|
|
|
|
+ mlxsw_reg_smid_port_set(smid_pl, mlxsw_sp_router_port(mlxsw_sp),
|
|
|
+ set_router_port);
|
|
|
+
|
|
|
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
|
|
|
kfree(smid_pl);
|
|
|
return err;
|
|
@@ -1364,7 +1433,8 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
|
|
|
mlxsw_sp_mc_get_mrouters_bitmap(flood_bitmap, bridge_device, mlxsw_sp);
|
|
|
|
|
|
mid->mid = mid_idx;
|
|
|
- err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap);
|
|
|
+ err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap,
|
|
|
+ bridge_device->mrouter);
|
|
|
kfree(flood_bitmap);
|
|
|
if (err)
|
|
|
return false;
|