Commit 3dc80afc authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: introduce a separate cross-chip notifier type for host FDBs

DSA treats some bridge FDB entries by trapping them to the CPU port.
Currently, the only class of such entries are FDB addresses learnt by
the software bridge on a foreign interface. However there are many more
to be added:

- FDB entries with the is_local flag (for termination) added by the
  bridge on the user ports (typically containing the MAC address of the
  bridge port)
- FDB entries pointing towards the bridge net device (for termination).
  Typically these contain the MAC address of the bridge net device.
- Static FDB entries installed on a foreign interface that is in the
  same bridge with a DSA user port.

The reason why a separate cross-chip notifier for host FDBs is justified
compared to normal FDBs is the same as in the case of host MDBs: the
cross-chip notifier matching function in switch.c should avoid
installing these entries on routing ports that route towards the
targeted switch, but not towards the CPU. This is required in order to
have proper support for H-like multi-chip topologies.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 161ca59d
...@@ -20,6 +20,8 @@ enum { ...@@ -20,6 +20,8 @@ enum {
DSA_NOTIFIER_BRIDGE_LEAVE, DSA_NOTIFIER_BRIDGE_LEAVE,
DSA_NOTIFIER_FDB_ADD, DSA_NOTIFIER_FDB_ADD,
DSA_NOTIFIER_FDB_DEL, DSA_NOTIFIER_FDB_DEL,
DSA_NOTIFIER_HOST_FDB_ADD,
DSA_NOTIFIER_HOST_FDB_DEL,
DSA_NOTIFIER_HSR_JOIN, DSA_NOTIFIER_HSR_JOIN,
DSA_NOTIFIER_HSR_LEAVE, DSA_NOTIFIER_HSR_LEAVE,
DSA_NOTIFIER_LAG_CHANGE, DSA_NOTIFIER_LAG_CHANGE,
...@@ -121,6 +123,7 @@ struct dsa_switchdev_event_work { ...@@ -121,6 +123,7 @@ struct dsa_switchdev_event_work {
*/ */
unsigned char addr[ETH_ALEN]; unsigned char addr[ETH_ALEN];
u16 vid; u16 vid;
bool host_addr;
}; };
/* DSA_NOTIFIER_HSR_* */ /* DSA_NOTIFIER_HSR_* */
...@@ -211,6 +214,10 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, ...@@ -211,6 +214,10 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
u16 vid); u16 vid);
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
u16 vid); u16 vid);
int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
u16 vid);
int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
u16 vid);
int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data); int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data);
int dsa_port_mdb_add(const struct dsa_port *dp, int dsa_port_mdb_add(const struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb); const struct switchdev_obj_port_mdb *mdb);
......
...@@ -646,6 +646,32 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, ...@@ -646,6 +646,32 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info);
} }
int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
u16 vid)
{
struct dsa_notifier_fdb_info info = {
.sw_index = dp->ds->index,
.port = dp->index,
.addr = addr,
.vid = vid,
};
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_ADD, &info);
}
int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
u16 vid)
{
struct dsa_notifier_fdb_info info = {
.sw_index = dp->ds->index,
.port = dp->index,
.addr = addr,
.vid = vid,
};
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_DEL, &info);
}
int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data) int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
......
...@@ -2315,8 +2315,12 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work) ...@@ -2315,8 +2315,12 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
rtnl_lock(); rtnl_lock();
switch (switchdev_work->event) { switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE: case SWITCHDEV_FDB_ADD_TO_DEVICE:
err = dsa_port_fdb_add(dp, switchdev_work->addr, if (switchdev_work->host_addr)
switchdev_work->vid); err = dsa_port_host_fdb_add(dp, switchdev_work->addr,
switchdev_work->vid);
else
err = dsa_port_fdb_add(dp, switchdev_work->addr,
switchdev_work->vid);
if (err) { if (err) {
dev_err(ds->dev, dev_err(ds->dev,
"port %d failed to add %pM vid %d to fdb: %d\n", "port %d failed to add %pM vid %d to fdb: %d\n",
...@@ -2328,8 +2332,12 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work) ...@@ -2328,8 +2332,12 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
break; break;
case SWITCHDEV_FDB_DEL_TO_DEVICE: case SWITCHDEV_FDB_DEL_TO_DEVICE:
err = dsa_port_fdb_del(dp, switchdev_work->addr, if (switchdev_work->host_addr)
switchdev_work->vid); err = dsa_port_host_fdb_del(dp, switchdev_work->addr,
switchdev_work->vid);
else
err = dsa_port_fdb_del(dp, switchdev_work->addr,
switchdev_work->vid);
if (err) { if (err) {
dev_err(ds->dev, dev_err(ds->dev,
"port %d failed to delete %pM vid %d from fdb: %d\n", "port %d failed to delete %pM vid %d from fdb: %d\n",
...@@ -2375,6 +2383,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, ...@@ -2375,6 +2383,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
struct net_device *dev = switchdev_notifier_info_to_dev(ptr); struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
const struct switchdev_notifier_fdb_info *fdb_info; const struct switchdev_notifier_fdb_info *fdb_info;
struct dsa_switchdev_event_work *switchdev_work; struct dsa_switchdev_event_work *switchdev_work;
bool host_addr = false;
struct dsa_port *dp; struct dsa_port *dp;
int err; int err;
...@@ -2412,7 +2421,8 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, ...@@ -2412,7 +2421,8 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
if (!p) if (!p)
return NOTIFY_DONE; return NOTIFY_DONE;
dp = p->dp->cpu_dp; dp = p->dp;
host_addr = true;
if (!dp->ds->assisted_learning_on_cpu_port) if (!dp->ds->assisted_learning_on_cpu_port)
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -2442,6 +2452,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, ...@@ -2442,6 +2452,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
ether_addr_copy(switchdev_work->addr, ether_addr_copy(switchdev_work->addr,
fdb_info->addr); fdb_info->addr);
switchdev_work->vid = fdb_info->vid; switchdev_work->vid = fdb_info->vid;
switchdev_work->host_addr = host_addr;
/* Hold a reference on the slave for dsa_fdb_offload_notify */ /* Hold a reference on the slave for dsa_fdb_offload_notify */
if (dsa_is_user_port(dp->ds, dp->index)) if (dsa_is_user_port(dp->ds, dp->index))
......
...@@ -253,6 +253,41 @@ static int dsa_switch_do_mdb_del(struct dsa_switch *ds, int port, ...@@ -253,6 +253,41 @@ static int dsa_switch_do_mdb_del(struct dsa_switch *ds, int port,
return 0; return 0;
} }
static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
struct dsa_notifier_fdb_info *info)
{
int err = 0;
int port;
if (!ds->ops->port_fdb_add)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_host_address_match(ds, port, info->sw_index,
info->port)) {
err = ds->ops->port_fdb_add(ds, port, info->addr,
info->vid);
if (err)
break;
}
}
return err;
}
static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
struct dsa_notifier_fdb_info *info)
{
if (!ds->ops->port_fdb_del)
return -EOPNOTSUPP;
if (ds->index == info->sw_index)
return ds->ops->port_fdb_del(ds, info->port, info->addr,
info->vid);
return 0;
}
static int dsa_switch_fdb_add(struct dsa_switch *ds, static int dsa_switch_fdb_add(struct dsa_switch *ds,
struct dsa_notifier_fdb_info *info) struct dsa_notifier_fdb_info *info)
{ {
...@@ -560,6 +595,12 @@ static int dsa_switch_event(struct notifier_block *nb, ...@@ -560,6 +595,12 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_FDB_DEL: case DSA_NOTIFIER_FDB_DEL:
err = dsa_switch_fdb_del(ds, info); err = dsa_switch_fdb_del(ds, info);
break; break;
case DSA_NOTIFIER_HOST_FDB_ADD:
err = dsa_switch_host_fdb_add(ds, info);
break;
case DSA_NOTIFIER_HOST_FDB_DEL:
err = dsa_switch_host_fdb_del(ds, info);
break;
case DSA_NOTIFIER_HSR_JOIN: case DSA_NOTIFIER_HSR_JOIN:
err = dsa_switch_hsr_join(ds, info); err = dsa_switch_hsr_join(ds, info);
break; break;
......
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