diff options
Diffstat (limited to 'target/linux/generic/backport-5.10/722-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch')
-rw-r--r-- | target/linux/generic/backport-5.10/722-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.10/722-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch b/target/linux/generic/backport-5.10/722-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch new file mode 100644 index 0000000000..c1aa8fda82 --- /dev/null +++ b/target/linux/generic/backport-5.10/722-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch @@ -0,0 +1,226 @@ +From c4bb76a9a0ef87c4cc1f636defed5f12deb9f5a7 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean <vladimir.oltean@nxp.com> +Date: Wed, 6 Jan 2021 11:51:32 +0200 +Subject: [PATCH] net: dsa: don't use switchdev_notifier_fdb_info in + dsa_switchdev_event_work + +Currently DSA doesn't add FDB entries on the CPU port, because it only +does so through switchdev, which is associated with a net_device, and +there are none of those for the CPU port. + +But actually FDB addresses on the CPU port have some use cases of their +own, if the switchdev operations are initiated from within the DSA +layer. There is just one problem with the existing code: it passes a +structure in dsa_switchdev_event_work which was retrieved directly from +switchdev, so it contains a net_device. We need to generalize the +contents to something that covers the CPU port as well: the "ds, port" +tuple is fine for that. + +Note that the new procedure for notifying the successful FDB offload is +inspired from the rocker model. + +Also, nothing was being done if added_by_user was false. Let's check for +that a lot earlier, and don't actually bother to schedule the worker +for nothing. + +Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> +Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> +Signed-off-by: Jakub Kicinski <kuba@kernel.org> +--- + net/dsa/dsa_priv.h | 12 +++++ + net/dsa/slave.c | 106 ++++++++++++++++++++++----------------------- + 2 files changed, 65 insertions(+), 53 deletions(-) + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -73,6 +73,18 @@ struct dsa_notifier_mtu_info { + int mtu; + }; + ++struct dsa_switchdev_event_work { ++ struct dsa_switch *ds; ++ int port; ++ struct work_struct work; ++ unsigned long event; ++ /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and ++ * SWITCHDEV_FDB_DEL_TO_DEVICE ++ */ ++ unsigned char addr[ETH_ALEN]; ++ u16 vid; ++}; ++ + struct dsa_slave_priv { + /* Copy of CPU port xmit for faster access in slave transmit hot path */ + struct sk_buff * (*xmit)(struct sk_buff *skb, +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -2087,76 +2087,66 @@ static int dsa_slave_netdevice_event(str + return NOTIFY_DONE; + } + +-struct dsa_switchdev_event_work { +- struct work_struct work; +- struct switchdev_notifier_fdb_info fdb_info; +- struct net_device *dev; +- unsigned long event; +-}; ++static void ++dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) ++{ ++ struct dsa_switch *ds = switchdev_work->ds; ++ struct switchdev_notifier_fdb_info info; ++ struct dsa_port *dp; ++ ++ if (!dsa_is_user_port(ds, switchdev_work->port)) ++ return; ++ ++ info.addr = switchdev_work->addr; ++ info.vid = switchdev_work->vid; ++ info.offloaded = true; ++ dp = dsa_to_port(ds, switchdev_work->port); ++ call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, ++ dp->slave, &info.info, NULL); ++} + + static void dsa_slave_switchdev_event_work(struct work_struct *work) + { + struct dsa_switchdev_event_work *switchdev_work = + container_of(work, struct dsa_switchdev_event_work, work); +- struct net_device *dev = switchdev_work->dev; +- struct switchdev_notifier_fdb_info *fdb_info; +- struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct dsa_switch *ds = switchdev_work->ds; ++ struct dsa_port *dp; + int err; + ++ dp = dsa_to_port(ds, switchdev_work->port); ++ + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: +- fdb_info = &switchdev_work->fdb_info; +- if (!fdb_info->added_by_user) +- break; +- +- err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid); ++ err = dsa_port_fdb_add(dp, switchdev_work->addr, ++ switchdev_work->vid); + if (err) { +- netdev_err(dev, +- "failed to add %pM vid %d to fdb: %d\n", +- fdb_info->addr, fdb_info->vid, err); ++ dev_err(ds->dev, ++ "port %d failed to add %pM vid %d to fdb: %d\n", ++ dp->index, switchdev_work->addr, ++ switchdev_work->vid, err); + break; + } +- fdb_info->offloaded = true; +- call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev, +- &fdb_info->info, NULL); ++ dsa_fdb_offload_notify(switchdev_work); + break; + + case SWITCHDEV_FDB_DEL_TO_DEVICE: +- fdb_info = &switchdev_work->fdb_info; +- if (!fdb_info->added_by_user) +- break; +- +- err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid); ++ err = dsa_port_fdb_del(dp, switchdev_work->addr, ++ switchdev_work->vid); + if (err) { +- netdev_err(dev, +- "failed to delete %pM vid %d from fdb: %d\n", +- fdb_info->addr, fdb_info->vid, err); ++ dev_err(ds->dev, ++ "port %d failed to delete %pM vid %d from fdb: %d\n", ++ dp->index, switchdev_work->addr, ++ switchdev_work->vid, err); + } + + break; + } + rtnl_unlock(); + +- kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); +- dev_put(dev); +-} +- +-static int +-dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work * +- switchdev_work, +- const struct switchdev_notifier_fdb_info * +- fdb_info) +-{ +- memcpy(&switchdev_work->fdb_info, fdb_info, +- sizeof(switchdev_work->fdb_info)); +- switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); +- if (!switchdev_work->fdb_info.addr) +- return -ENOMEM; +- ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, +- fdb_info->addr); +- return 0; ++ if (dsa_is_user_port(ds, dp->index)) ++ dev_put(dp->slave); + } + + /* Called under rcu_read_lock() */ +@@ -2164,7 +2154,9 @@ static int dsa_slave_switchdev_event(str + unsigned long event, void *ptr) + { + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); ++ const struct switchdev_notifier_fdb_info *fdb_info; + struct dsa_switchdev_event_work *switchdev_work; ++ struct dsa_port *dp; + int err; + + if (event == SWITCHDEV_PORT_ATTR_SET) { +@@ -2177,20 +2169,32 @@ static int dsa_slave_switchdev_event(str + if (!dsa_slave_dev_check(dev)) + return NOTIFY_DONE; + ++ dp = dsa_slave_to_port(dev); ++ + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, + dsa_slave_switchdev_event_work); +- switchdev_work->dev = dev; ++ switchdev_work->ds = dp->ds; ++ switchdev_work->port = dp->index; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: +- if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr)) +- goto err_fdb_work_init; ++ fdb_info = ptr; ++ ++ if (!fdb_info->added_by_user) { ++ kfree(switchdev_work); ++ return NOTIFY_OK; ++ } ++ ++ ether_addr_copy(switchdev_work->addr, ++ fdb_info->addr); ++ switchdev_work->vid = fdb_info->vid; ++ + dev_hold(dev); + break; + default: +@@ -2200,10 +2204,6 @@ static int dsa_slave_switchdev_event(str + + dsa_schedule_work(&switchdev_work->work); + return NOTIFY_OK; +- +-err_fdb_work_init: +- kfree(switchdev_work); +- return NOTIFY_BAD; + } + + static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused, |