123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- From c4bb76a9a0ef87c4cc1f636defed5f12deb9f5a7 Mon Sep 17 00:00:00 2001
- From: Vladimir Oltean <[email protected]>
- 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 <[email protected]>
- Reviewed-by: Florian Fainelli <[email protected]>
- Signed-off-by: Jakub Kicinski <[email protected]>
- ---
- 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
- @@ -2050,76 +2050,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() */
- @@ -2127,7 +2117,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) {
- @@ -2140,20 +2132,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:
- @@ -2163,10 +2167,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,
|