Commit 2c4eca3e authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: bridge: switchdev: include local flag in FDB notifications

As explained in bugfix commit 6ab4c311 ("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: default avatarTobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: default avatarTobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e5b4b898
...@@ -2098,7 +2098,7 @@ static void dpaa2_switch_event_work(struct work_struct *work) ...@@ -2098,7 +2098,7 @@ static void dpaa2_switch_event_work(struct work_struct *work)
switch (switchdev_work->event) { switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE: case SWITCHDEV_FDB_ADD_TO_DEVICE:
if (!fdb_info->added_by_user) if (!fdb_info->added_by_user || fdb_info->is_local)
break; break;
if (is_unicast_ether_addr(fdb_info->addr)) if (is_unicast_ether_addr(fdb_info->addr))
err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev), err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev),
...@@ -2113,7 +2113,7 @@ static void dpaa2_switch_event_work(struct work_struct *work) ...@@ -2113,7 +2113,7 @@ static void dpaa2_switch_event_work(struct work_struct *work)
&fdb_info->info, NULL); &fdb_info->info, NULL);
break; break;
case SWITCHDEV_FDB_DEL_TO_DEVICE: case SWITCHDEV_FDB_DEL_TO_DEVICE:
if (!fdb_info->added_by_user) if (!fdb_info->added_by_user || fdb_info->is_local)
break; break;
if (is_unicast_ether_addr(fdb_info->addr)) if (is_unicast_ether_addr(fdb_info->addr))
dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr); dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);
......
...@@ -798,7 +798,7 @@ static void prestera_fdb_event_work(struct work_struct *work) ...@@ -798,7 +798,7 @@ static void prestera_fdb_event_work(struct work_struct *work)
switch (swdev_work->event) { switch (swdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE: case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb_info = &swdev_work->fdb_info; fdb_info = &swdev_work->fdb_info;
if (!fdb_info->added_by_user) if (!fdb_info->added_by_user || fdb_info->is_local)
break; break;
err = prestera_port_fdb_set(port, fdb_info, true); err = prestera_port_fdb_set(port, fdb_info, true);
......
...@@ -2916,7 +2916,8 @@ mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work * ...@@ -2916,7 +2916,8 @@ mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work *
return; return;
if (switchdev_work->event == SWITCHDEV_FDB_ADD_TO_DEVICE && 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; return;
if (!netif_running(dev)) if (!netif_running(dev))
...@@ -2971,7 +2972,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work) ...@@ -2971,7 +2972,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
switch (switchdev_work->event) { switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE: case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info; fdb_info = &switchdev_work->fdb_info;
if (!fdb_info->added_by_user) if (!fdb_info->added_by_user || fdb_info->is_local)
break; break;
err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true); err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);
if (err) if (err)
......
...@@ -2736,7 +2736,7 @@ static void rocker_switchdev_event_work(struct work_struct *work) ...@@ -2736,7 +2736,7 @@ static void rocker_switchdev_event_work(struct work_struct *work)
switch (switchdev_work->event) { switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE: case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info; fdb_info = &switchdev_work->fdb_info;
if (!fdb_info->added_by_user) if (!fdb_info->added_by_user || fdb_info->is_local)
break; break;
err = rocker_world_port_fdb_add(rocker_port, fdb_info); err = rocker_world_port_fdb_add(rocker_port, fdb_info);
if (err) { if (err) {
...@@ -2747,7 +2747,7 @@ static void rocker_switchdev_event_work(struct work_struct *work) ...@@ -2747,7 +2747,7 @@ static void rocker_switchdev_event_work(struct work_struct *work)
break; break;
case SWITCHDEV_FDB_DEL_TO_DEVICE: case SWITCHDEV_FDB_DEL_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info; fdb_info = &switchdev_work->fdb_info;
if (!fdb_info->added_by_user) if (!fdb_info->added_by_user || fdb_info->is_local)
break; break;
err = rocker_world_port_fdb_del(rocker_port, fdb_info); err = rocker_world_port_fdb_del(rocker_port, fdb_info);
if (err) if (err)
......
...@@ -385,7 +385,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work) ...@@ -385,7 +385,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user, fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port_id); fdb->offloaded, port_id);
if (!fdb->added_by_user) if (!fdb->added_by_user || fdb->is_local)
break; break;
if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port_id = HOST_PORT_NUM; port_id = HOST_PORT_NUM;
...@@ -401,7 +401,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work) ...@@ -401,7 +401,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user, fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port_id); fdb->offloaded, port_id);
if (!fdb->added_by_user) if (!fdb->added_by_user || fdb->is_local)
break; break;
if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port_id = HOST_PORT_NUM; port_id = HOST_PORT_NUM;
......
...@@ -395,7 +395,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work) ...@@ -395,7 +395,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user, fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port); fdb->offloaded, port);
if (!fdb->added_by_user) if (!fdb->added_by_user || fdb->is_local)
break; break;
if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port = HOST_PORT_NUM; port = HOST_PORT_NUM;
...@@ -411,7 +411,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work) ...@@ -411,7 +411,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work)
fdb->addr, fdb->vid, fdb->added_by_user, fdb->addr, fdb->vid, fdb->added_by_user,
fdb->offloaded, port); fdb->offloaded, port);
if (!fdb->added_by_user) if (!fdb->added_by_user || fdb->is_local)
break; break;
if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
port = HOST_PORT_NUM; port = HOST_PORT_NUM;
......
...@@ -209,6 +209,7 @@ struct switchdev_notifier_fdb_info { ...@@ -209,6 +209,7 @@ struct switchdev_notifier_fdb_info {
const unsigned char *addr; const unsigned char *addr;
u16 vid; u16 vid;
u8 added_by_user:1, u8 added_by_user:1,
is_local:1,
offloaded:1; offloaded:1;
}; };
......
...@@ -114,13 +114,12 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) ...@@ -114,13 +114,12 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
.addr = fdb->key.addr.addr, .addr = fdb->key.addr.addr,
.vid = fdb->key.vlan_id, .vid = fdb->key.vlan_id,
.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags), .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), .offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
}; };
if (!fdb->dst) if (!fdb->dst)
return; return;
if (test_bit(BR_FDB_LOCAL, &fdb->flags))
return;
switch (type) { switch (type) {
case RTM_DELNEIGH: case RTM_DELNEIGH:
......
...@@ -2329,7 +2329,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, ...@@ -2329,7 +2329,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
fdb_info = ptr; fdb_info = ptr;
if (dsa_slave_dev_check(dev)) { 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; return NOTIFY_OK;
dp = dsa_slave_to_port(dev); dp = dsa_slave_to_port(dev);
......
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