From 9f01cfbf2922432668c2fd4dfc0413342aaff48b Mon Sep 17 00:00:00 2001 From: Casper Andersson Date: Mon, 14 Mar 2022 17:09:18 +0100 Subject: [PATCH] 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 Link: https://lore.kernel.org/r/20220314160918.4rfrrfgmbsf2pxl3@wse-c0155 Signed-off-by: Jakub Kicinski --- .../ethernet/microchip/sparx5/sparx5_mactable.c | 11 +-- .../net/ethernet/microchip/sparx5/sparx5_main.h | 3 +- .../ethernet/microchip/sparx5/sparx5_switchdev.c | 91 ++++++---------------- 3 files changed, 33 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c index 9a8e4f2..82b1b3c 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c @@ -286,7 +286,8 @@ static void sparx5_fdb_call_notifiers(enum switchdev_notifier_type type, } int sparx5_add_mact_entry(struct sparx5 *sparx5, - struct sparx5_port *port, + struct net_device *dev, + u16 portno, const unsigned char *addr, u16 vid) { struct sparx5_mact_entry *mact_entry; @@ -302,14 +303,14 @@ int sparx5_add_mact_entry(struct sparx5 *sparx5, * mact thread to start the frame will reach CPU and the CPU will * add the entry but without the extern_learn flag. */ - mact_entry = find_mact_entry(sparx5, addr, vid, port->portno); + mact_entry = find_mact_entry(sparx5, addr, vid, portno); if (mact_entry) goto update_hw; /* Add the entry in SW MAC table not to get the notification when * SW is pulling again */ - mact_entry = alloc_mact_entry(sparx5, addr, vid, port->portno); + mact_entry = alloc_mact_entry(sparx5, addr, vid, portno); if (!mact_entry) return -ENOMEM; @@ -318,13 +319,13 @@ int sparx5_add_mact_entry(struct sparx5 *sparx5, mutex_unlock(&sparx5->mact_lock); update_hw: - ret = sparx5_mact_learn(sparx5, port->portno, addr, vid); + ret = sparx5_mact_learn(sparx5, portno, addr, vid); /* New entry? */ if (mact_entry->flags == 0) { mact_entry->flags |= MAC_ENT_LOCK; /* Don't age this */ sparx5_fdb_call_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, addr, vid, - port->ndev, true); + dev, true); } return ret; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h index 33892df..df68a08 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h @@ -305,7 +305,8 @@ bool sparx5_mact_getnext(struct sparx5 *sparx5, int sparx5_mact_forget(struct sparx5 *sparx5, const unsigned char mac[ETH_ALEN], u16 vid); int sparx5_add_mact_entry(struct sparx5 *sparx5, - struct sparx5_port *port, + struct net_device *dev, + u16 portno, const unsigned char *addr, u16 vid); int sparx5_del_mact_entry(struct sparx5 *sparx5, const unsigned char *addr, diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c index dacb87f..2d5de1c 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; } -- 2.7.4