OSDN Git Service

net: bridge: switchdev: include local flag in FDB notifications
authorVladimir Oltean <vladimir.oltean@nxp.com>
Wed, 14 Apr 2021 16:52:56 +0000 (19:52 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 16 Apr 2021 22:15:45 +0000 (15:15 -0700)
As explained in bugfix commit 6ab4c3117aec ("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>
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/rocker/rocker_main.c
drivers/net/ethernet/ti/am65-cpsw-switchdev.c
drivers/net/ethernet/ti/cpsw_switchdev.c
include/net/switchdev.h
net/bridge/br_switchdev.c
net/dsa/slave.c

index 5250d51..05de37c 100644 (file)
@@ -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),
@@ -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);
index 49e0522..cb56489 100644 (file)
@@ -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);
index c1f05c1..eeccd58 100644 (file)
@@ -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))
@@ -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)
index 3473d29..a466336 100644 (file)
@@ -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) {
@@ -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)
index d93ffd8..23cfb91 100644 (file)
@@ -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;
@@ -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;
index a72bb57..05a64fb 100644 (file)
@@ -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;
@@ -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;
index 8c32181..f1a5a9a 100644 (file)
@@ -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;
 };
 
index c390f84..a5e601e 100644 (file)
@@ -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:
index 9300cb6..3ae6720 100644 (file)
@@ -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);