Commit 045c45d1 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: centralize fast ageing when address learning is turned off

Currently DSA leaves it down to device drivers to fast age the FDB on a
port when address learning is disabled on it. There are 2 reasons for
doing that in the first place:

- when address learning is disabled by user space, through
  IFLA_BRPORT_LEARNING or the brport_attr_learning sysfs, what user
  space typically wants to achieve is to operate in a mode with no
  dynamic FDB entry on that port. But if the port is already up, some
  addresses might have been already learned on it, and it seems silly to
  wait for 5 minutes for them to expire until something useful can be
  done.

- when a port leaves a bridge and becomes standalone, DSA turns off
  address learning on it. This also has the nice side effect of flushing
  the dynamically learned bridge FDB entries on it, which is a good idea
  because standalone ports should not have bridge FDB entries on them.

We let drivers manage fast ageing under this condition because if DSA
were to do it, it would need to track each port's learning state, and
act upon the transition, which it currently doesn't.

But there are 2 reasons why doing it is better after all:

- drivers might get it wrong and not do it (see b53_port_set_learning)

- we would like to flush the dynamic entries from the software bridge
  too, and letting drivers do that would be another pain point

So track the port learning state and trigger a fast age process
automatically within DSA.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 64ec13ec
...@@ -5797,7 +5797,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, ...@@ -5797,7 +5797,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_chip *chip = ds->priv;
bool do_fast_age = false;
int err = -EOPNOTSUPP; int err = -EOPNOTSUPP;
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
...@@ -5809,9 +5808,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, ...@@ -5809,9 +5808,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
err = mv88e6xxx_port_set_assoc_vector(chip, port, pav); err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
if (err) if (err)
goto out; goto out;
if (!learning)
do_fast_age = true;
} }
if (flags.mask & BR_FLOOD) { if (flags.mask & BR_FLOOD) {
...@@ -5843,9 +5839,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, ...@@ -5843,9 +5839,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
out: out:
mv88e6xxx_reg_unlock(chip); mv88e6xxx_reg_unlock(chip);
if (do_fast_age)
mv88e6xxx_port_fast_age(ds, port);
return err; return err;
} }
......
...@@ -254,6 +254,7 @@ struct dsa_port { ...@@ -254,6 +254,7 @@ struct dsa_port {
struct device_node *dn; struct device_node *dn;
unsigned int ageing_time; unsigned int ageing_time;
bool vlan_filtering; bool vlan_filtering;
bool learning;
u8 stp_state; u8 stp_state;
struct net_device *bridge_dev; struct net_device *bridge_dev;
int bridge_num; int bridge_num;
......
...@@ -241,7 +241,7 @@ int dsa_port_host_mdb_del(const struct dsa_port *dp, ...@@ -241,7 +241,7 @@ int dsa_port_host_mdb_del(const struct dsa_port *dp,
int dsa_port_pre_bridge_flags(const struct dsa_port *dp, int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
struct switchdev_brport_flags flags, struct switchdev_brport_flags flags,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int dsa_port_bridge_flags(const struct dsa_port *dp, int dsa_port_bridge_flags(struct dsa_port *dp,
struct switchdev_brport_flags flags, struct switchdev_brport_flags flags,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int dsa_port_vlan_add(struct dsa_port *dp, int dsa_port_vlan_add(struct dsa_port *dp,
......
...@@ -30,6 +30,16 @@ static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v) ...@@ -30,6 +30,16 @@ static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v)
return dsa_tree_notify(dp->ds->dst, e, v); return dsa_tree_notify(dp->ds->dst, e, v);
} }
static void dsa_port_fast_age(const struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
if (!ds->ops->port_fast_age)
return;
ds->ops->port_fast_age(ds, dp->index);
}
int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age) int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
...@@ -40,7 +50,7 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age) ...@@ -40,7 +50,7 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
ds->ops->port_stp_state_set(ds, port, state); ds->ops->port_stp_state_set(ds, port, state);
if (do_fast_age && ds->ops->port_fast_age) { if (do_fast_age) {
/* Fast age FDB entries or flush appropriate forwarding database /* Fast age FDB entries or flush appropriate forwarding database
* for the given port, if we are moving it from Learning or * for the given port, if we are moving it from Learning or
* Forwarding state, to Disabled or Blocking or Listening state. * Forwarding state, to Disabled or Blocking or Listening state.
...@@ -54,7 +64,7 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age) ...@@ -54,7 +64,7 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
(state == BR_STATE_DISABLED || (state == BR_STATE_DISABLED ||
state == BR_STATE_BLOCKING || state == BR_STATE_BLOCKING ||
state == BR_STATE_LISTENING)) state == BR_STATE_LISTENING))
ds->ops->port_fast_age(ds, port); dsa_port_fast_age(dp);
} }
dp->stp_state = state; dp->stp_state = state;
...@@ -633,16 +643,33 @@ int dsa_port_pre_bridge_flags(const struct dsa_port *dp, ...@@ -633,16 +643,33 @@ int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack); return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack);
} }
int dsa_port_bridge_flags(const struct dsa_port *dp, int dsa_port_bridge_flags(struct dsa_port *dp,
struct switchdev_brport_flags flags, struct switchdev_brport_flags flags,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
int err;
if (!ds->ops->port_bridge_flags) if (!ds->ops->port_bridge_flags)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ds->ops->port_bridge_flags(ds, dp->index, flags, extack); err = ds->ops->port_bridge_flags(ds, dp->index, flags, extack);
if (err)
return err;
if (flags.mask & BR_LEARNING) {
bool learning = flags.val & BR_LEARNING;
if (learning == dp->learning)
return 0;
if (dp->learning && !learning)
dsa_port_fast_age(dp);
dp->learning = learning;
}
return 0;
} }
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment