Skip to content

Commit

Permalink
net: switchdev: pass flags and mask to both {PRE_,}BRIDGE_FLAGS attri…
Browse files Browse the repository at this point in the history
…butes

This switchdev attribute offers a counterproductive API for a driver
writer, because although br_switchdev_set_port_flag gets passed a
"flags" and a "mask", those are passed piecemeal to the driver, so while
the PRE_BRIDGE_FLAGS listener knows what changed because it has the
"mask", the BRIDGE_FLAGS listener doesn't, because it only has the final
value. But certain drivers can offload only certain combinations of
settings, like for example they cannot change unicast flooding
independently of multicast flooding - they must be both on or both off.
The way the information is passed to switchdev makes drivers not
expressive enough, and unable to reject this request ahead of time, in
the PRE_BRIDGE_FLAGS notifier, so they are forced to reject it during
the deferred BRIDGE_FLAGS attribute, where the rejection is currently
ignored.

This patch also changes drivers to make use of the "mask" field for edge
detection when possible.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Grygorii Strashko <grygorii.strashko@ti.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vladimir Oltean authored and David S. Miller committed Feb 13, 2021
1 parent 5e38c15 commit e18f4c1
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 89 deletions.
23 changes: 14 additions & 9 deletions drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ int prestera_bridge_port_event(struct net_device *dev, unsigned long event,

static int prestera_port_attr_br_flags_set(struct prestera_port *port,
struct net_device *dev,
unsigned long flags)
struct switchdev_brport_flags flags)
{
struct prestera_bridge_port *br_port;
int err;
Expand All @@ -590,15 +590,20 @@ static int prestera_port_attr_br_flags_set(struct prestera_port *port,
if (!br_port)
return 0;

err = prestera_hw_port_flood_set(port, flags & BR_FLOOD);
if (err)
return err;
if (flags.mask & BR_FLOOD) {
err = prestera_hw_port_flood_set(port, flags.val & BR_FLOOD);
if (err)
return err;
}

err = prestera_hw_port_learning_set(port, flags & BR_LEARNING);
if (err)
return err;
if (flags.mask & BR_LEARNING) {
err = prestera_hw_port_learning_set(port,
flags.val & BR_LEARNING);
if (err)
return err;
}

memcpy(&br_port->flags, &flags, sizeof(flags));
memcpy(&br_port->flags, &flags.val, sizeof(flags.val));

return 0;
}
Expand Down Expand Up @@ -707,7 +712,7 @@ static int prestera_port_obj_attr_set(struct net_device *dev,
attr->u.stp_state);
break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
if (attr->u.brport_flags &
if (attr->u.brport_flags.mask &
~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
err = -EINVAL;
break;
Expand Down
50 changes: 29 additions & 21 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,19 +653,19 @@ mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}

static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port
*mlxsw_sp_port,
unsigned long brport_flags)
static int
mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_brport_flags flags)
{
if (brport_flags & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
return -EINVAL;

return 0;
}

static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *orig_dev,
unsigned long brport_flags)
struct switchdev_brport_flags flags)
{
struct mlxsw_sp_bridge_port *bridge_port;
int err;
Expand All @@ -675,29 +675,37 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
if (!bridge_port)
return 0;

err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
MLXSW_SP_FLOOD_TYPE_UC,
brport_flags & BR_FLOOD);
if (err)
return err;
if (flags.mask & BR_FLOOD) {
err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
bridge_port,
MLXSW_SP_FLOOD_TYPE_UC,
flags.val & BR_FLOOD);
if (err)
return err;
}

err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port,
brport_flags & BR_LEARNING);
if (err)
return err;
if (flags.mask & BR_LEARNING) {
err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port,
bridge_port,
flags.val & BR_LEARNING);
if (err)
return err;
}

if (bridge_port->bridge_device->multicast_enabled)
goto out;

err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
MLXSW_SP_FLOOD_TYPE_MC,
brport_flags &
BR_MCAST_FLOOD);
if (err)
return err;
if (flags.mask & BR_MCAST_FLOOD) {
err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
bridge_port,
MLXSW_SP_FLOOD_TYPE_MC,
flags.val & BR_MCAST_FLOOD);
if (err)
return err;
}

out:
memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags));
memcpy(&bridge_port->flags, &flags.val, sizeof(flags.val));
return 0;
}

Expand Down
10 changes: 5 additions & 5 deletions drivers/net/ethernet/rocker/rocker_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1576,7 +1576,7 @@ rocker_world_port_attr_bridge_flags_support_get(const struct rocker_port *

static int
rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port,
unsigned long brport_flags)
struct switchdev_brport_flags flags)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
unsigned long brport_flags_s;
Expand All @@ -1590,22 +1590,22 @@ rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port,
if (err)
return err;

if (brport_flags & ~brport_flags_s)
if (flags.mask & ~brport_flags_s)
return -EINVAL;

return 0;
}

static int
rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
unsigned long brport_flags)
struct switchdev_brport_flags flags)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;

if (!wops->port_attr_bridge_flags_set)
return -EOPNOTSUPP;

return wops->port_attr_bridge_flags_set(rocker_port, brport_flags);
return wops->port_attr_bridge_flags_set(rocker_port, flags.val);
}

static int
Expand Down Expand Up @@ -2058,7 +2058,7 @@ static int rocker_port_attr_set(struct net_device *dev,
break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
err = rocker_world_port_attr_pre_bridge_flags_set(rocker_port,
attr->u.brport_flags);
attr->u.brport_flags);
break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = rocker_world_port_attr_bridge_flags_set(rocker_port,
Expand Down
24 changes: 14 additions & 10 deletions drivers/net/ethernet/ti/am65-cpsw-switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,30 @@ static int am65_cpsw_port_stp_state_set(struct am65_cpsw_port *port, u8 state)

static int am65_cpsw_port_attr_br_flags_set(struct am65_cpsw_port *port,
struct net_device *orig_dev,
unsigned long brport_flags)
struct switchdev_brport_flags flags)
{
struct am65_cpsw_common *cpsw = port->common;
bool unreg_mcast_add = false;

if (brport_flags & BR_MCAST_FLOOD)
unreg_mcast_add = true;
netdev_dbg(port->ndev, "BR_MCAST_FLOOD: %d port %u\n",
unreg_mcast_add, port->port_id);
if (flags.mask & BR_MCAST_FLOOD) {
bool unreg_mcast_add = false;

cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(port->port_id),
unreg_mcast_add);
if (flags.val & BR_MCAST_FLOOD)
unreg_mcast_add = true;

netdev_dbg(port->ndev, "BR_MCAST_FLOOD: %d port %u\n",
unreg_mcast_add, port->port_id);

cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(port->port_id),
unreg_mcast_add);
}

return 0;
}

static int am65_cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
unsigned long flags)
struct switchdev_brport_flags flags)
{
if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD))
if (flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD))
return -EINVAL;

return 0;
Expand Down
24 changes: 14 additions & 10 deletions drivers/net/ethernet/ti/cpsw_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,30 @@ static int cpsw_port_stp_state_set(struct cpsw_priv *priv, u8 state)

static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv,
struct net_device *orig_dev,
unsigned long brport_flags)
struct switchdev_brport_flags flags)
{
struct cpsw_common *cpsw = priv->cpsw;
bool unreg_mcast_add = false;

if (brport_flags & BR_MCAST_FLOOD)
unreg_mcast_add = true;
dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n",
unreg_mcast_add, priv->emac_port);
if (flags.mask & BR_MCAST_FLOOD) {
bool unreg_mcast_add = false;

cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port),
unreg_mcast_add);
if (flags.val & BR_MCAST_FLOOD)
unreg_mcast_add = true;

dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n",
unreg_mcast_add, priv->emac_port);

cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port),
unreg_mcast_add);
}

return 0;
}

static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
unsigned long flags)
struct switchdev_brport_flags flags)
{
if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD))
if (flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD))
return -EINVAL;

return 0;
Expand Down
34 changes: 21 additions & 13 deletions drivers/staging/fsl-dpaa2/ethsw/ethsw.c
Original file line number Diff line number Diff line change
Expand Up @@ -908,31 +908,39 @@ static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev,
return dpaa2_switch_port_set_stp_state(port_priv, state);
}

static int dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev,
unsigned long flags)
static int
dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev,
struct switchdev_brport_flags flags)
{
if (flags & ~(BR_LEARNING | BR_FLOOD))
if (flags.mask & ~(BR_LEARNING | BR_FLOOD))
return -EINVAL;

return 0;
}

static int dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev,
unsigned long flags)
static int
dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev,
struct switchdev_brport_flags flags)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int err = 0;

/* Learning is enabled per switch */
err = dpaa2_switch_set_learning(port_priv->ethsw_data,
!!(flags & BR_LEARNING));
if (err)
goto exit;
if (flags.mask & BR_LEARNING) {
/* Learning is enabled per switch */
err = dpaa2_switch_set_learning(port_priv->ethsw_data,
!!(flags.val & BR_LEARNING));
if (err)
return err;
}

err = dpaa2_switch_port_set_flood(port_priv, !!(flags & BR_FLOOD));
if (flags.mask & BR_FLOOD) {
err = dpaa2_switch_port_set_flood(port_priv,
!!(flags.val & BR_FLOOD));
if (err)
return err;
}

exit:
return err;
return 0;
}

static int dpaa2_switch_port_attr_set(struct net_device *netdev,
Expand Down
7 changes: 6 additions & 1 deletion include/net/switchdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ enum switchdev_attr_id {
#endif
};

struct switchdev_brport_flags {
unsigned long val;
unsigned long mask;
};

struct switchdev_attr {
struct net_device *orig_dev;
enum switchdev_attr_id id;
Expand All @@ -40,7 +45,7 @@ struct switchdev_attr {
void (*complete)(struct net_device *dev, int err, void *priv);
union {
u8 stp_state; /* PORT_STP_STATE */
unsigned long brport_flags; /* PORT_{PRE}_BRIDGE_FLAGS */
struct switchdev_brport_flags brport_flags; /* PORT_BRIDGE_FLAGS */
bool mrouter; /* PORT_MROUTER */
clock_t ageing_time; /* BRIDGE_AGEING_TIME */
bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */
Expand Down
6 changes: 3 additions & 3 deletions net/bridge/br_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,
{
struct switchdev_attr attr = {
.orig_dev = p->dev,
.id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS,
};
struct switchdev_notifier_port_attr_info info = {
.attr = &attr,
Expand All @@ -76,7 +75,9 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,
if (!mask)
return 0;

attr.u.brport_flags = mask;
attr.id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS;
attr.u.brport_flags.val = flags;
attr.u.brport_flags.mask = mask;

/* We run from atomic context here */
err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev,
Expand All @@ -94,7 +95,6 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,

attr.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS;
attr.flags = SWITCHDEV_F_DEFER;
attr.u.brport_flags = flags;

err = switchdev_port_attr_set(p->dev, &attr);
if (err) {
Expand Down
6 changes: 4 additions & 2 deletions net/dsa/dsa_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,10 @@ int dsa_port_mdb_add(const struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb);
int dsa_port_mdb_del(const struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb);
int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags);
int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags);
int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
struct switchdev_brport_flags flags);
int dsa_port_bridge_flags(const struct dsa_port *dp,
struct switchdev_brport_flags flags);
int dsa_port_mrouter(struct dsa_port *dp, bool mrouter);
int dsa_port_vlan_add(struct dsa_port *dp,
const struct switchdev_obj_port_vlan *vlan);
Expand Down
Loading

0 comments on commit e18f4c1

Please sign in to comment.