Skip to content

Commit

Permalink
net: bridge: switchdev: include local flag in FDB notifications
Browse files Browse the repository at this point in the history
As explained in bugfix commit 6ab4c31 ("net: bridge: don't notify
switchdev for local FDB addresses") as well as in this discussion:
https://lore.kernel.org/netdev/20210117193009.io3nungdwuzmo5f7@skbuf/

the switchdev notifiers for FDB entries managed to have a zero-day bug,
which was that drivers would not know what to do with local FDB entries,
because they were not told that they are local. The bug fix was to
simply not notify them of those addresses.

Let us now add the 'is_local' bit to bridge FDB entries, and make all
drivers ignore these entries by their own choice.

Co-developed-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Grygorii Strashko <grygorii.strashko@ti.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vladimir Oltean authored and David S. Miller committed Apr 16, 2021
1 parent e5b4b89 commit 2c4eca3
Show file tree
Hide file tree
Showing 9 changed files with 15 additions and 14 deletions.
4 changes: 2 additions & 2 deletions drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -2098,7 +2098,7 @@ static void dpaa2_switch_event_work(struct work_struct *work)

switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
break;
if (is_unicast_ether_addr(fdb_info->addr))
err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev),
Expand All @@ -2113,7 +2113,7 @@ static void dpaa2_switch_event_work(struct work_struct *work)
&fdb_info->info, NULL);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
break;
if (is_unicast_ether_addr(fdb_info->addr))
dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ static void prestera_fdb_event_work(struct work_struct *work)
switch (swdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb_info = &swdev_work->fdb_info;
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
break;

err = prestera_port_fdb_set(port, fdb_info, true);
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -2916,7 +2916,8 @@ mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work *
return;

if (switchdev_work->event == SWITCHDEV_FDB_ADD_TO_DEVICE &&
!switchdev_work->fdb_info.added_by_user)
(!switchdev_work->fdb_info.added_by_user ||
switchdev_work->fdb_info.is_local))
return;

if (!netif_running(dev))
Expand Down Expand Up @@ -2971,7 +2972,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info;
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
break;
err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);
if (err)
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/rocker/rocker_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2736,7 +2736,7 @@ static void rocker_switchdev_event_work(struct work_struct *work)
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info;
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
break;
err = rocker_world_port_fdb_add(rocker_port, fdb_info);
if (err) {
Expand All @@ -2747,7 +2747,7 @@ static void rocker_switchdev_event_work(struct work_struct *work)
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info;
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
break;
err = rocker_world_port_fdb_del(rocker_port, fdb_info);
if (err)
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/ti/am65-cpsw-switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port_id);

if (!fdb->added_by_user)
if (!fdb->added_by_user || fdb->is_local)
break;
if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port_id = HOST_PORT_NUM;
Expand All @@ -401,7 +401,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port_id);

if (!fdb->added_by_user)
if (!fdb->added_by_user || fdb->is_local)
break;
if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port_id = HOST_PORT_NUM;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/ti/cpsw_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port);

if (!fdb->added_by_user)
if (!fdb->added_by_user || fdb->is_local)
break;
if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port = HOST_PORT_NUM;
Expand All @@ -411,7 +411,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port);

if (!fdb->added_by_user)
if (!fdb->added_by_user || fdb->is_local)
break;
if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port = HOST_PORT_NUM;
Expand Down
1 change: 1 addition & 0 deletions include/net/switchdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ struct switchdev_notifier_fdb_info {
const unsigned char *addr;
u16 vid;
u8 added_by_user:1,
is_local:1,
offloaded:1;
};

Expand Down
3 changes: 1 addition & 2 deletions net/bridge/br_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,12 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
.addr = fdb->key.addr.addr,
.vid = fdb->key.vlan_id,
.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags),
.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags),
.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
};

if (!fdb->dst)
return;
if (test_bit(BR_FDB_LOCAL, &fdb->flags))
return;

switch (type) {
case RTM_DELNEIGH:
Expand Down
2 changes: 1 addition & 1 deletion net/dsa/slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -2329,7 +2329,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
fdb_info = ptr;

if (dsa_slave_dev_check(dev)) {
if (!fdb_info->added_by_user)
if (!fdb_info->added_by_user || fdb_info->is_local)
return NOTIFY_OK;

dp = dsa_slave_to_port(dev);
Expand Down

0 comments on commit 2c4eca3

Please sign in to comment.