diff options
author | 2022-03-14 17:09:18 +0100 | |
---|---|---|
committer | 2022-03-15 20:40:55 -0700 | |
commit | 9f01cfbf2922432668c2fd4dfc0413342aaff48b (patch) | |
tree | 47282b9d45993b3dea13053218cd55f2cb468e0b /drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c | |
parent | net: Add l3mdev index to flow struct and avoid oif reset for port devices (diff) | |
download | linux-dev-9f01cfbf2922432668c2fd4dfc0413342aaff48b.tar.xz linux-dev-9f01cfbf2922432668c2fd4dfc0413342aaff48b.zip |
net: sparx5: Use Switchdev fdb events for managing fdb entries
Changes the handling of fdb entries to use Switchdev events,
instead of the previous "sync_bridge" and "sync_port" which
only run when adding or removing VLANs on the bridge.
Signed-off-by: Casper Andersson <casper.casan@gmail.com>
Link: https://lore.kernel.org/r/20220314160918.4rfrrfgmbsf2pxl3@wse-c0155
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to '')
-rw-r--r-- | drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c | 91 |
1 files changed, 25 insertions, 66 deletions
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c index dacb87f49552..2d5de1c06fab 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c @@ -16,6 +16,7 @@ struct sparx5_switchdev_event_work { struct work_struct work; struct switchdev_notifier_fdb_info fdb_info; struct net_device *dev; + struct sparx5 *sparx5; unsigned long event; }; @@ -247,31 +248,34 @@ static void sparx5_switchdev_bridge_fdb_event_work(struct work_struct *work) struct switchdev_notifier_fdb_info *fdb_info; struct sparx5_port *port; struct sparx5 *sparx5; + bool host_addr; rtnl_lock(); - if (!sparx5_netdevice_check(dev)) - goto out; - - port = netdev_priv(dev); - sparx5 = port->sparx5; + if (!sparx5_netdevice_check(dev)) { + host_addr = true; + sparx5 = switchdev_work->sparx5; + } else { + host_addr = false; + sparx5 = switchdev_work->sparx5; + port = netdev_priv(dev); + } fdb_info = &switchdev_work->fdb_info; switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: - if (!fdb_info->added_by_user) - break; - sparx5_add_mact_entry(sparx5, port, fdb_info->addr, - fdb_info->vid); + if (host_addr) + sparx5_add_mact_entry(sparx5, dev, PGID_CPU, + fdb_info->addr, fdb_info->vid); + else + sparx5_add_mact_entry(sparx5, port->ndev, port->portno, + fdb_info->addr, fdb_info->vid); break; case SWITCHDEV_FDB_DEL_TO_DEVICE: - if (!fdb_info->added_by_user) - break; sparx5_del_mact_entry(sparx5, fdb_info->addr, fdb_info->vid); break; } -out: rtnl_unlock(); kfree(switchdev_work->fdb_info.addr); kfree(switchdev_work); @@ -283,15 +287,18 @@ static void sparx5_schedule_work(struct work_struct *work) queue_work(sparx5_owq, work); } -static int sparx5_switchdev_event(struct notifier_block *unused, +static int sparx5_switchdev_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct net_device *dev = switchdev_notifier_info_to_dev(ptr); struct sparx5_switchdev_event_work *switchdev_work; struct switchdev_notifier_fdb_info *fdb_info; struct switchdev_notifier_info *info = ptr; + struct sparx5 *spx5; int err; + spx5 = container_of(nb, struct sparx5, switchdev_nb); + switch (event) { case SWITCHDEV_PORT_ATTR_SET: err = switchdev_handle_port_attr_set(dev, ptr, @@ -307,6 +314,7 @@ static int sparx5_switchdev_event(struct notifier_block *unused, switchdev_work->dev = dev; switchdev_work->event = event; + switchdev_work->sparx5 = spx5; fdb_info = container_of(info, struct switchdev_notifier_fdb_info, @@ -333,54 +341,6 @@ err_addr_alloc: return NOTIFY_BAD; } -static void sparx5_sync_port_dev_addr(struct sparx5 *sparx5, - struct sparx5_port *port, - u16 vid, bool add) -{ - if (!port || - !test_bit(port->portno, sparx5->bridge_mask)) - return; /* Skip null/host interfaces */ - - /* Bridge connects to vid? */ - if (add) { - /* Add port MAC address from the VLAN */ - sparx5_mact_learn(sparx5, PGID_CPU, - port->ndev->dev_addr, vid); - } else { - /* Control port addr visibility depending on - * port VLAN connectivity. - */ - if (test_bit(port->portno, sparx5->vlan_mask[vid])) - sparx5_mact_learn(sparx5, PGID_CPU, - port->ndev->dev_addr, vid); - else - sparx5_mact_forget(sparx5, - port->ndev->dev_addr, vid); - } -} - -static void sparx5_sync_bridge_dev_addr(struct net_device *dev, - struct sparx5 *sparx5, - u16 vid, bool add) -{ - int i; - - /* First, handle bridge address'es */ - if (add) { - sparx5_mact_learn(sparx5, PGID_CPU, dev->dev_addr, - vid); - sparx5_mact_learn(sparx5, PGID_BCAST, dev->broadcast, - vid); - } else { - sparx5_mact_forget(sparx5, dev->dev_addr, vid); - sparx5_mact_forget(sparx5, dev->broadcast, vid); - } - - /* Now look at bridged ports */ - for (i = 0; i < SPX5_PORTS; i++) - sparx5_sync_port_dev_addr(sparx5, sparx5->ports[i], vid, add); -} - static int sparx5_handle_port_vlan_add(struct net_device *dev, struct notifier_block *nb, const struct switchdev_obj_port_vlan *v) @@ -392,7 +352,9 @@ static int sparx5_handle_port_vlan_add(struct net_device *dev, container_of(nb, struct sparx5, switchdev_blocking_nb); - sparx5_sync_bridge_dev_addr(dev, sparx5, v->vid, true); + /* Flood broadcast to CPU */ + sparx5_mact_learn(sparx5, PGID_BCAST, dev->broadcast, + v->vid); return 0; } @@ -438,7 +400,7 @@ static int sparx5_handle_port_vlan_del(struct net_device *dev, container_of(nb, struct sparx5, switchdev_blocking_nb); - sparx5_sync_bridge_dev_addr(dev, sparx5, vid, false); + sparx5_mact_forget(sparx5, dev->broadcast, vid); return 0; } @@ -449,9 +411,6 @@ static int sparx5_handle_port_vlan_del(struct net_device *dev, if (ret) return ret; - /* Delete the port MAC address with the matching VLAN information */ - sparx5_mact_forget(port->sparx5, port->ndev->dev_addr, vid); - return 0; } |