1007f790cSJiri Pirko /* 2007f790cSJiri Pirko * net/switchdev/switchdev.c - Switch device API 37ea6eb3fSJiri Pirko * Copyright (c) 2014-2015 Jiri Pirko <[email protected]> 4f8f21471SScott Feldman * Copyright (c) 2014-2015 Scott Feldman <[email protected]> 5007f790cSJiri Pirko * 6007f790cSJiri Pirko * This program is free software; you can redistribute it and/or modify 7007f790cSJiri Pirko * it under the terms of the GNU General Public License as published by 8007f790cSJiri Pirko * the Free Software Foundation; either version 2 of the License, or 9007f790cSJiri Pirko * (at your option) any later version. 10007f790cSJiri Pirko */ 11007f790cSJiri Pirko 12007f790cSJiri Pirko #include <linux/kernel.h> 13007f790cSJiri Pirko #include <linux/types.h> 14007f790cSJiri Pirko #include <linux/init.h> 1503bf0c28SJiri Pirko #include <linux/mutex.h> 1603bf0c28SJiri Pirko #include <linux/notifier.h> 17007f790cSJiri Pirko #include <linux/netdevice.h> 18850d0cbcSJiri Pirko #include <linux/etherdevice.h> 1947f8328bSScott Feldman #include <linux/if_bridge.h> 207ea6eb3fSJiri Pirko #include <linux/list.h> 21793f4014SJiri Pirko #include <linux/workqueue.h> 2287aaf2caSNikolay Aleksandrov #include <linux/if_vlan.h> 234f2c6ae5SIdo Schimmel #include <linux/rtnetlink.h> 24007f790cSJiri Pirko #include <net/switchdev.h> 25007f790cSJiri Pirko 26007f790cSJiri Pirko /** 277ea6eb3fSJiri Pirko * switchdev_trans_item_enqueue - Enqueue data item to transaction queue 287ea6eb3fSJiri Pirko * 297ea6eb3fSJiri Pirko * @trans: transaction 307ea6eb3fSJiri Pirko * @data: pointer to data being queued 317ea6eb3fSJiri Pirko * @destructor: data destructor 327ea6eb3fSJiri Pirko * @tritem: transaction item being queued 337ea6eb3fSJiri Pirko * 347ea6eb3fSJiri Pirko * Enqeueue data item to transaction queue. tritem is typically placed in 357ea6eb3fSJiri Pirko * cointainter pointed at by data pointer. Destructor is called on 367ea6eb3fSJiri Pirko * transaction abort and after successful commit phase in case 377ea6eb3fSJiri Pirko * the caller did not dequeue the item before. 387ea6eb3fSJiri Pirko */ 397ea6eb3fSJiri Pirko void switchdev_trans_item_enqueue(struct switchdev_trans *trans, 407ea6eb3fSJiri Pirko void *data, void (*destructor)(void const *), 417ea6eb3fSJiri Pirko struct switchdev_trans_item *tritem) 427ea6eb3fSJiri Pirko { 437ea6eb3fSJiri Pirko tritem->data = data; 447ea6eb3fSJiri Pirko tritem->destructor = destructor; 457ea6eb3fSJiri Pirko list_add_tail(&tritem->list, &trans->item_list); 467ea6eb3fSJiri Pirko } 477ea6eb3fSJiri Pirko EXPORT_SYMBOL_GPL(switchdev_trans_item_enqueue); 487ea6eb3fSJiri Pirko 497ea6eb3fSJiri Pirko static struct switchdev_trans_item * 507ea6eb3fSJiri Pirko __switchdev_trans_item_dequeue(struct switchdev_trans *trans) 517ea6eb3fSJiri Pirko { 527ea6eb3fSJiri Pirko struct switchdev_trans_item *tritem; 537ea6eb3fSJiri Pirko 547ea6eb3fSJiri Pirko if (list_empty(&trans->item_list)) 557ea6eb3fSJiri Pirko return NULL; 567ea6eb3fSJiri Pirko tritem = list_first_entry(&trans->item_list, 577ea6eb3fSJiri Pirko struct switchdev_trans_item, list); 587ea6eb3fSJiri Pirko list_del(&tritem->list); 597ea6eb3fSJiri Pirko return tritem; 607ea6eb3fSJiri Pirko } 617ea6eb3fSJiri Pirko 627ea6eb3fSJiri Pirko /** 637ea6eb3fSJiri Pirko * switchdev_trans_item_dequeue - Dequeue data item from transaction queue 647ea6eb3fSJiri Pirko * 657ea6eb3fSJiri Pirko * @trans: transaction 667ea6eb3fSJiri Pirko */ 677ea6eb3fSJiri Pirko void *switchdev_trans_item_dequeue(struct switchdev_trans *trans) 687ea6eb3fSJiri Pirko { 697ea6eb3fSJiri Pirko struct switchdev_trans_item *tritem; 707ea6eb3fSJiri Pirko 717ea6eb3fSJiri Pirko tritem = __switchdev_trans_item_dequeue(trans); 727ea6eb3fSJiri Pirko BUG_ON(!tritem); 737ea6eb3fSJiri Pirko return tritem->data; 747ea6eb3fSJiri Pirko } 757ea6eb3fSJiri Pirko EXPORT_SYMBOL_GPL(switchdev_trans_item_dequeue); 767ea6eb3fSJiri Pirko 777ea6eb3fSJiri Pirko static void switchdev_trans_init(struct switchdev_trans *trans) 787ea6eb3fSJiri Pirko { 797ea6eb3fSJiri Pirko INIT_LIST_HEAD(&trans->item_list); 807ea6eb3fSJiri Pirko } 817ea6eb3fSJiri Pirko 827ea6eb3fSJiri Pirko static void switchdev_trans_items_destroy(struct switchdev_trans *trans) 837ea6eb3fSJiri Pirko { 847ea6eb3fSJiri Pirko struct switchdev_trans_item *tritem; 857ea6eb3fSJiri Pirko 867ea6eb3fSJiri Pirko while ((tritem = __switchdev_trans_item_dequeue(trans))) 877ea6eb3fSJiri Pirko tritem->destructor(tritem->data); 887ea6eb3fSJiri Pirko } 897ea6eb3fSJiri Pirko 907ea6eb3fSJiri Pirko static void switchdev_trans_items_warn_destroy(struct net_device *dev, 917ea6eb3fSJiri Pirko struct switchdev_trans *trans) 927ea6eb3fSJiri Pirko { 937ea6eb3fSJiri Pirko WARN(!list_empty(&trans->item_list), "%s: transaction item queue is not empty.\n", 947ea6eb3fSJiri Pirko dev->name); 957ea6eb3fSJiri Pirko switchdev_trans_items_destroy(trans); 967ea6eb3fSJiri Pirko } 977ea6eb3fSJiri Pirko 98793f4014SJiri Pirko static LIST_HEAD(deferred); 99793f4014SJiri Pirko static DEFINE_SPINLOCK(deferred_lock); 100793f4014SJiri Pirko 101793f4014SJiri Pirko typedef void switchdev_deferred_func_t(struct net_device *dev, 102793f4014SJiri Pirko const void *data); 103793f4014SJiri Pirko 104793f4014SJiri Pirko struct switchdev_deferred_item { 105793f4014SJiri Pirko struct list_head list; 106793f4014SJiri Pirko struct net_device *dev; 107793f4014SJiri Pirko switchdev_deferred_func_t *func; 108793f4014SJiri Pirko unsigned long data[0]; 109793f4014SJiri Pirko }; 110793f4014SJiri Pirko 111793f4014SJiri Pirko static struct switchdev_deferred_item *switchdev_deferred_dequeue(void) 112793f4014SJiri Pirko { 113793f4014SJiri Pirko struct switchdev_deferred_item *dfitem; 114793f4014SJiri Pirko 115793f4014SJiri Pirko spin_lock_bh(&deferred_lock); 116793f4014SJiri Pirko if (list_empty(&deferred)) { 117793f4014SJiri Pirko dfitem = NULL; 118793f4014SJiri Pirko goto unlock; 119793f4014SJiri Pirko } 120793f4014SJiri Pirko dfitem = list_first_entry(&deferred, 121793f4014SJiri Pirko struct switchdev_deferred_item, list); 122793f4014SJiri Pirko list_del(&dfitem->list); 123793f4014SJiri Pirko unlock: 124793f4014SJiri Pirko spin_unlock_bh(&deferred_lock); 125793f4014SJiri Pirko return dfitem; 126793f4014SJiri Pirko } 127793f4014SJiri Pirko 128793f4014SJiri Pirko /** 129793f4014SJiri Pirko * switchdev_deferred_process - Process ops in deferred queue 130793f4014SJiri Pirko * 131793f4014SJiri Pirko * Called to flush the ops currently queued in deferred ops queue. 132793f4014SJiri Pirko * rtnl_lock must be held. 133793f4014SJiri Pirko */ 134793f4014SJiri Pirko void switchdev_deferred_process(void) 135793f4014SJiri Pirko { 136793f4014SJiri Pirko struct switchdev_deferred_item *dfitem; 137793f4014SJiri Pirko 138793f4014SJiri Pirko ASSERT_RTNL(); 139793f4014SJiri Pirko 140793f4014SJiri Pirko while ((dfitem = switchdev_deferred_dequeue())) { 141793f4014SJiri Pirko dfitem->func(dfitem->dev, dfitem->data); 142793f4014SJiri Pirko dev_put(dfitem->dev); 143793f4014SJiri Pirko kfree(dfitem); 144793f4014SJiri Pirko } 145793f4014SJiri Pirko } 146793f4014SJiri Pirko EXPORT_SYMBOL_GPL(switchdev_deferred_process); 147793f4014SJiri Pirko 148793f4014SJiri Pirko static void switchdev_deferred_process_work(struct work_struct *work) 149793f4014SJiri Pirko { 150793f4014SJiri Pirko rtnl_lock(); 151793f4014SJiri Pirko switchdev_deferred_process(); 152793f4014SJiri Pirko rtnl_unlock(); 153793f4014SJiri Pirko } 154793f4014SJiri Pirko 155793f4014SJiri Pirko static DECLARE_WORK(deferred_process_work, switchdev_deferred_process_work); 156793f4014SJiri Pirko 157793f4014SJiri Pirko static int switchdev_deferred_enqueue(struct net_device *dev, 158793f4014SJiri Pirko const void *data, size_t data_len, 159793f4014SJiri Pirko switchdev_deferred_func_t *func) 160793f4014SJiri Pirko { 161793f4014SJiri Pirko struct switchdev_deferred_item *dfitem; 162793f4014SJiri Pirko 163793f4014SJiri Pirko dfitem = kmalloc(sizeof(*dfitem) + data_len, GFP_ATOMIC); 164793f4014SJiri Pirko if (!dfitem) 165793f4014SJiri Pirko return -ENOMEM; 166793f4014SJiri Pirko dfitem->dev = dev; 167793f4014SJiri Pirko dfitem->func = func; 168793f4014SJiri Pirko memcpy(dfitem->data, data, data_len); 169793f4014SJiri Pirko dev_hold(dev); 170793f4014SJiri Pirko spin_lock_bh(&deferred_lock); 171793f4014SJiri Pirko list_add_tail(&dfitem->list, &deferred); 172793f4014SJiri Pirko spin_unlock_bh(&deferred_lock); 173793f4014SJiri Pirko schedule_work(&deferred_process_work); 174793f4014SJiri Pirko return 0; 175793f4014SJiri Pirko } 176793f4014SJiri Pirko 1773094333dSScott Feldman static int __switchdev_port_attr_set(struct net_device *dev, 178f7fadf30SJiri Pirko const struct switchdev_attr *attr, 1797ea6eb3fSJiri Pirko struct switchdev_trans *trans) 1803094333dSScott Feldman { 1813094333dSScott Feldman const struct switchdev_ops *ops = dev->switchdev_ops; 1823094333dSScott Feldman struct net_device *lower_dev; 1833094333dSScott Feldman struct list_head *iter; 1843094333dSScott Feldman int err = -EOPNOTSUPP; 1853094333dSScott Feldman 1860c63d80cSJiri Pirko if (ops && ops->switchdev_port_attr_set) { 1870c63d80cSJiri Pirko err = ops->switchdev_port_attr_set(dev, attr, trans); 1880c63d80cSJiri Pirko goto done; 1890c63d80cSJiri Pirko } 1903094333dSScott Feldman 1913094333dSScott Feldman if (attr->flags & SWITCHDEV_F_NO_RECURSE) 192464314eaSScott Feldman goto done; 1933094333dSScott Feldman 1943094333dSScott Feldman /* Switch device port(s) may be stacked under 1953094333dSScott Feldman * bond/team/vlan dev, so recurse down to set attr on 1963094333dSScott Feldman * each port. 1973094333dSScott Feldman */ 1983094333dSScott Feldman 1993094333dSScott Feldman netdev_for_each_lower_dev(dev, lower_dev, iter) { 2007ea6eb3fSJiri Pirko err = __switchdev_port_attr_set(lower_dev, attr, trans); 2013094333dSScott Feldman if (err) 2023094333dSScott Feldman break; 2033094333dSScott Feldman } 2043094333dSScott Feldman 205464314eaSScott Feldman done: 206464314eaSScott Feldman if (err == -EOPNOTSUPP && attr->flags & SWITCHDEV_F_SKIP_EOPNOTSUPP) 207464314eaSScott Feldman err = 0; 208464314eaSScott Feldman 2093094333dSScott Feldman return err; 2103094333dSScott Feldman } 2113094333dSScott Feldman 2120bc05d58SJiri Pirko static int switchdev_port_attr_set_now(struct net_device *dev, 213f7fadf30SJiri Pirko const struct switchdev_attr *attr) 2143094333dSScott Feldman { 2157ea6eb3fSJiri Pirko struct switchdev_trans trans; 2163094333dSScott Feldman int err; 2173094333dSScott Feldman 2187ea6eb3fSJiri Pirko switchdev_trans_init(&trans); 2197ea6eb3fSJiri Pirko 2203094333dSScott Feldman /* Phase I: prepare for attr set. Driver/device should fail 2213094333dSScott Feldman * here if there are going to be issues in the commit phase, 2223094333dSScott Feldman * such as lack of resources or support. The driver/device 2233094333dSScott Feldman * should reserve resources needed for the commit phase here, 2243094333dSScott Feldman * but should not commit the attr. 2253094333dSScott Feldman */ 2263094333dSScott Feldman 227f623ab7fSJiri Pirko trans.ph_prepare = true; 2287ea6eb3fSJiri Pirko err = __switchdev_port_attr_set(dev, attr, &trans); 2293094333dSScott Feldman if (err) { 2303094333dSScott Feldman /* Prepare phase failed: abort the transaction. Any 2313094333dSScott Feldman * resources reserved in the prepare phase are 2323094333dSScott Feldman * released. 2333094333dSScott Feldman */ 2343094333dSScott Feldman 2359f6467cfSJiri Pirko if (err != -EOPNOTSUPP) 2367ea6eb3fSJiri Pirko switchdev_trans_items_destroy(&trans); 2373094333dSScott Feldman 2383094333dSScott Feldman return err; 2393094333dSScott Feldman } 2403094333dSScott Feldman 2413094333dSScott Feldman /* Phase II: commit attr set. This cannot fail as a fault 2423094333dSScott Feldman * of driver/device. If it does, it's a bug in the driver/device 2433094333dSScott Feldman * because the driver said everythings was OK in phase I. 2443094333dSScott Feldman */ 2453094333dSScott Feldman 246f623ab7fSJiri Pirko trans.ph_prepare = false; 2477ea6eb3fSJiri Pirko err = __switchdev_port_attr_set(dev, attr, &trans); 248e9fdaec0SScott Feldman WARN(err, "%s: Commit of attribute (id=%d) failed.\n", 249e9fdaec0SScott Feldman dev->name, attr->id); 2507ea6eb3fSJiri Pirko switchdev_trans_items_warn_destroy(dev, &trans); 2513094333dSScott Feldman 2523094333dSScott Feldman return err; 2533094333dSScott Feldman } 2540bc05d58SJiri Pirko 2550bc05d58SJiri Pirko static void switchdev_port_attr_set_deferred(struct net_device *dev, 2560bc05d58SJiri Pirko const void *data) 2570bc05d58SJiri Pirko { 2580bc05d58SJiri Pirko const struct switchdev_attr *attr = data; 2590bc05d58SJiri Pirko int err; 2600bc05d58SJiri Pirko 2610bc05d58SJiri Pirko err = switchdev_port_attr_set_now(dev, attr); 2620bc05d58SJiri Pirko if (err && err != -EOPNOTSUPP) 2630bc05d58SJiri Pirko netdev_err(dev, "failed (err=%d) to set attribute (id=%d)\n", 2640bc05d58SJiri Pirko err, attr->id); 2657ceb2afbSElad Raz if (attr->complete) 2667ceb2afbSElad Raz attr->complete(dev, err, attr->complete_priv); 2670bc05d58SJiri Pirko } 2680bc05d58SJiri Pirko 2690bc05d58SJiri Pirko static int switchdev_port_attr_set_defer(struct net_device *dev, 2700bc05d58SJiri Pirko const struct switchdev_attr *attr) 2710bc05d58SJiri Pirko { 2720bc05d58SJiri Pirko return switchdev_deferred_enqueue(dev, attr, sizeof(*attr), 2730bc05d58SJiri Pirko switchdev_port_attr_set_deferred); 2740bc05d58SJiri Pirko } 2750bc05d58SJiri Pirko 2760bc05d58SJiri Pirko /** 2770bc05d58SJiri Pirko * switchdev_port_attr_set - Set port attribute 2780bc05d58SJiri Pirko * 2790bc05d58SJiri Pirko * @dev: port device 2800bc05d58SJiri Pirko * @attr: attribute to set 2810bc05d58SJiri Pirko * 2820bc05d58SJiri Pirko * Use a 2-phase prepare-commit transaction model to ensure 2830bc05d58SJiri Pirko * system is not left in a partially updated state due to 2840bc05d58SJiri Pirko * failure from driver/device. 2850bc05d58SJiri Pirko * 2860bc05d58SJiri Pirko * rtnl_lock must be held and must not be in atomic section, 2870bc05d58SJiri Pirko * in case SWITCHDEV_F_DEFER flag is not set. 2880bc05d58SJiri Pirko */ 2890bc05d58SJiri Pirko int switchdev_port_attr_set(struct net_device *dev, 2900bc05d58SJiri Pirko const struct switchdev_attr *attr) 2910bc05d58SJiri Pirko { 2920bc05d58SJiri Pirko if (attr->flags & SWITCHDEV_F_DEFER) 2930bc05d58SJiri Pirko return switchdev_port_attr_set_defer(dev, attr); 2940bc05d58SJiri Pirko ASSERT_RTNL(); 2950bc05d58SJiri Pirko return switchdev_port_attr_set_now(dev, attr); 2960bc05d58SJiri Pirko } 2973094333dSScott Feldman EXPORT_SYMBOL_GPL(switchdev_port_attr_set); 2983094333dSScott Feldman 299e258d919SScott Feldman static size_t switchdev_obj_size(const struct switchdev_obj *obj) 300e258d919SScott Feldman { 301e258d919SScott Feldman switch (obj->id) { 302e258d919SScott Feldman case SWITCHDEV_OBJ_ID_PORT_VLAN: 303e258d919SScott Feldman return sizeof(struct switchdev_obj_port_vlan); 3044d41e125SElad Raz case SWITCHDEV_OBJ_ID_PORT_MDB: 3054d41e125SElad Raz return sizeof(struct switchdev_obj_port_mdb); 30647d5b6dbSAndrew Lunn case SWITCHDEV_OBJ_ID_HOST_MDB: 30747d5b6dbSAndrew Lunn return sizeof(struct switchdev_obj_port_mdb); 308e258d919SScott Feldman default: 309e258d919SScott Feldman BUG(); 310e258d919SScott Feldman } 311e258d919SScott Feldman return 0; 312e258d919SScott Feldman } 313e258d919SScott Feldman 314d17d9f5eSPetr Machata static int switchdev_port_obj_notify(enum switchdev_notifier_type nt, 315d17d9f5eSPetr Machata struct net_device *dev, 316648b4a99SJiri Pirko const struct switchdev_obj *obj, 31769b7320eSPetr Machata struct switchdev_trans *trans, 31869b7320eSPetr Machata struct netlink_ext_ack *extack) 319491d0f15SScott Feldman { 320d17d9f5eSPetr Machata int rc; 321d17d9f5eSPetr Machata int err; 322491d0f15SScott Feldman 323d17d9f5eSPetr Machata struct switchdev_notifier_port_obj_info obj_info = { 324d17d9f5eSPetr Machata .obj = obj, 325d17d9f5eSPetr Machata .trans = trans, 326d17d9f5eSPetr Machata .handled = false, 327d17d9f5eSPetr Machata }; 328491d0f15SScott Feldman 329479c86dcSPetr Machata rc = call_switchdev_blocking_notifiers(nt, dev, &obj_info.info, extack); 330d17d9f5eSPetr Machata err = notifier_to_errno(rc); 331d17d9f5eSPetr Machata if (err) { 332d17d9f5eSPetr Machata WARN_ON(!obj_info.handled); 333491d0f15SScott Feldman return err; 334491d0f15SScott Feldman } 335d17d9f5eSPetr Machata if (!obj_info.handled) 336d17d9f5eSPetr Machata return -EOPNOTSUPP; 337d17d9f5eSPetr Machata return 0; 338d17d9f5eSPetr Machata } 339491d0f15SScott Feldman 3404d429c5dSJiri Pirko static int switchdev_port_obj_add_now(struct net_device *dev, 34169b7320eSPetr Machata const struct switchdev_obj *obj, 34269b7320eSPetr Machata struct netlink_ext_ack *extack) 343491d0f15SScott Feldman { 3447ea6eb3fSJiri Pirko struct switchdev_trans trans; 345491d0f15SScott Feldman int err; 346491d0f15SScott Feldman 347491d0f15SScott Feldman ASSERT_RTNL(); 348491d0f15SScott Feldman 3497ea6eb3fSJiri Pirko switchdev_trans_init(&trans); 3507ea6eb3fSJiri Pirko 351491d0f15SScott Feldman /* Phase I: prepare for obj add. Driver/device should fail 352491d0f15SScott Feldman * here if there are going to be issues in the commit phase, 353491d0f15SScott Feldman * such as lack of resources or support. The driver/device 354491d0f15SScott Feldman * should reserve resources needed for the commit phase here, 355491d0f15SScott Feldman * but should not commit the obj. 356491d0f15SScott Feldman */ 357491d0f15SScott Feldman 358f623ab7fSJiri Pirko trans.ph_prepare = true; 359d17d9f5eSPetr Machata err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD, 36069b7320eSPetr Machata dev, obj, &trans, extack); 361491d0f15SScott Feldman if (err) { 362491d0f15SScott Feldman /* Prepare phase failed: abort the transaction. Any 363491d0f15SScott Feldman * resources reserved in the prepare phase are 364491d0f15SScott Feldman * released. 365491d0f15SScott Feldman */ 366491d0f15SScott Feldman 3679f6467cfSJiri Pirko if (err != -EOPNOTSUPP) 3687ea6eb3fSJiri Pirko switchdev_trans_items_destroy(&trans); 369491d0f15SScott Feldman 370491d0f15SScott Feldman return err; 371491d0f15SScott Feldman } 372491d0f15SScott Feldman 373491d0f15SScott Feldman /* Phase II: commit obj add. This cannot fail as a fault 374491d0f15SScott Feldman * of driver/device. If it does, it's a bug in the driver/device 375491d0f15SScott Feldman * because the driver said everythings was OK in phase I. 376491d0f15SScott Feldman */ 377491d0f15SScott Feldman 378f623ab7fSJiri Pirko trans.ph_prepare = false; 379d17d9f5eSPetr Machata err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD, 38069b7320eSPetr Machata dev, obj, &trans, extack); 3819e8f4a54SJiri Pirko WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); 3827ea6eb3fSJiri Pirko switchdev_trans_items_warn_destroy(dev, &trans); 383491d0f15SScott Feldman 384491d0f15SScott Feldman return err; 385491d0f15SScott Feldman } 3864d429c5dSJiri Pirko 3874d429c5dSJiri Pirko static void switchdev_port_obj_add_deferred(struct net_device *dev, 3884d429c5dSJiri Pirko const void *data) 3894d429c5dSJiri Pirko { 3904d429c5dSJiri Pirko const struct switchdev_obj *obj = data; 3914d429c5dSJiri Pirko int err; 3924d429c5dSJiri Pirko 39369b7320eSPetr Machata err = switchdev_port_obj_add_now(dev, obj, NULL); 3944d429c5dSJiri Pirko if (err && err != -EOPNOTSUPP) 3954d429c5dSJiri Pirko netdev_err(dev, "failed (err=%d) to add object (id=%d)\n", 3964d429c5dSJiri Pirko err, obj->id); 3977ceb2afbSElad Raz if (obj->complete) 3987ceb2afbSElad Raz obj->complete(dev, err, obj->complete_priv); 3994d429c5dSJiri Pirko } 4004d429c5dSJiri Pirko 4014d429c5dSJiri Pirko static int switchdev_port_obj_add_defer(struct net_device *dev, 4024d429c5dSJiri Pirko const struct switchdev_obj *obj) 4034d429c5dSJiri Pirko { 404e258d919SScott Feldman return switchdev_deferred_enqueue(dev, obj, switchdev_obj_size(obj), 4054d429c5dSJiri Pirko switchdev_port_obj_add_deferred); 4064d429c5dSJiri Pirko } 407491d0f15SScott Feldman 408491d0f15SScott Feldman /** 4094d429c5dSJiri Pirko * switchdev_port_obj_add - Add port object 410491d0f15SScott Feldman * 411491d0f15SScott Feldman * @dev: port device 412ab069002SVivien Didelot * @id: object ID 4134d429c5dSJiri Pirko * @obj: object to add 4144d429c5dSJiri Pirko * 4154d429c5dSJiri Pirko * Use a 2-phase prepare-commit transaction model to ensure 4164d429c5dSJiri Pirko * system is not left in a partially updated state due to 4174d429c5dSJiri Pirko * failure from driver/device. 4184d429c5dSJiri Pirko * 4194d429c5dSJiri Pirko * rtnl_lock must be held and must not be in atomic section, 4204d429c5dSJiri Pirko * in case SWITCHDEV_F_DEFER flag is not set. 421491d0f15SScott Feldman */ 4224d429c5dSJiri Pirko int switchdev_port_obj_add(struct net_device *dev, 42369b7320eSPetr Machata const struct switchdev_obj *obj, 42469b7320eSPetr Machata struct netlink_ext_ack *extack) 4254d429c5dSJiri Pirko { 4264d429c5dSJiri Pirko if (obj->flags & SWITCHDEV_F_DEFER) 4274d429c5dSJiri Pirko return switchdev_port_obj_add_defer(dev, obj); 4284d429c5dSJiri Pirko ASSERT_RTNL(); 42969b7320eSPetr Machata return switchdev_port_obj_add_now(dev, obj, extack); 4304d429c5dSJiri Pirko } 4314d429c5dSJiri Pirko EXPORT_SYMBOL_GPL(switchdev_port_obj_add); 4324d429c5dSJiri Pirko 4334d429c5dSJiri Pirko static int switchdev_port_obj_del_now(struct net_device *dev, 434648b4a99SJiri Pirko const struct switchdev_obj *obj) 435491d0f15SScott Feldman { 436d17d9f5eSPetr Machata return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_DEL, 43769b7320eSPetr Machata dev, obj, NULL, NULL); 438491d0f15SScott Feldman } 4394d429c5dSJiri Pirko 4404d429c5dSJiri Pirko static void switchdev_port_obj_del_deferred(struct net_device *dev, 4414d429c5dSJiri Pirko const void *data) 4424d429c5dSJiri Pirko { 4434d429c5dSJiri Pirko const struct switchdev_obj *obj = data; 4444d429c5dSJiri Pirko int err; 4454d429c5dSJiri Pirko 4464d429c5dSJiri Pirko err = switchdev_port_obj_del_now(dev, obj); 4474d429c5dSJiri Pirko if (err && err != -EOPNOTSUPP) 4484d429c5dSJiri Pirko netdev_err(dev, "failed (err=%d) to del object (id=%d)\n", 4494d429c5dSJiri Pirko err, obj->id); 4507ceb2afbSElad Raz if (obj->complete) 4517ceb2afbSElad Raz obj->complete(dev, err, obj->complete_priv); 4524d429c5dSJiri Pirko } 4534d429c5dSJiri Pirko 4544d429c5dSJiri Pirko static int switchdev_port_obj_del_defer(struct net_device *dev, 4554d429c5dSJiri Pirko const struct switchdev_obj *obj) 4564d429c5dSJiri Pirko { 457e258d919SScott Feldman return switchdev_deferred_enqueue(dev, obj, switchdev_obj_size(obj), 4584d429c5dSJiri Pirko switchdev_port_obj_del_deferred); 4594d429c5dSJiri Pirko } 4604d429c5dSJiri Pirko 4614d429c5dSJiri Pirko /** 4624d429c5dSJiri Pirko * switchdev_port_obj_del - Delete port object 4634d429c5dSJiri Pirko * 4644d429c5dSJiri Pirko * @dev: port device 4654d429c5dSJiri Pirko * @id: object ID 4664d429c5dSJiri Pirko * @obj: object to delete 4674d429c5dSJiri Pirko * 4684d429c5dSJiri Pirko * rtnl_lock must be held and must not be in atomic section, 4694d429c5dSJiri Pirko * in case SWITCHDEV_F_DEFER flag is not set. 4704d429c5dSJiri Pirko */ 4714d429c5dSJiri Pirko int switchdev_port_obj_del(struct net_device *dev, 4724d429c5dSJiri Pirko const struct switchdev_obj *obj) 4734d429c5dSJiri Pirko { 4744d429c5dSJiri Pirko if (obj->flags & SWITCHDEV_F_DEFER) 4754d429c5dSJiri Pirko return switchdev_port_obj_del_defer(dev, obj); 4764d429c5dSJiri Pirko ASSERT_RTNL(); 4774d429c5dSJiri Pirko return switchdev_port_obj_del_now(dev, obj); 4784d429c5dSJiri Pirko } 479491d0f15SScott Feldman EXPORT_SYMBOL_GPL(switchdev_port_obj_del); 480491d0f15SScott Feldman 481ff5cf100SArkadi Sharshevsky static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain); 482a93e3b17SPetr Machata static BLOCKING_NOTIFIER_HEAD(switchdev_blocking_notif_chain); 48303bf0c28SJiri Pirko 48403bf0c28SJiri Pirko /** 485ebb9a03aSJiri Pirko * register_switchdev_notifier - Register notifier 48603bf0c28SJiri Pirko * @nb: notifier_block 48703bf0c28SJiri Pirko * 488ff5cf100SArkadi Sharshevsky * Register switch device notifier. 48903bf0c28SJiri Pirko */ 490ebb9a03aSJiri Pirko int register_switchdev_notifier(struct notifier_block *nb) 49103bf0c28SJiri Pirko { 492ff5cf100SArkadi Sharshevsky return atomic_notifier_chain_register(&switchdev_notif_chain, nb); 49303bf0c28SJiri Pirko } 494ebb9a03aSJiri Pirko EXPORT_SYMBOL_GPL(register_switchdev_notifier); 49503bf0c28SJiri Pirko 49603bf0c28SJiri Pirko /** 497ebb9a03aSJiri Pirko * unregister_switchdev_notifier - Unregister notifier 49803bf0c28SJiri Pirko * @nb: notifier_block 49903bf0c28SJiri Pirko * 50003bf0c28SJiri Pirko * Unregister switch device notifier. 50103bf0c28SJiri Pirko */ 502ebb9a03aSJiri Pirko int unregister_switchdev_notifier(struct notifier_block *nb) 50303bf0c28SJiri Pirko { 504ff5cf100SArkadi Sharshevsky return atomic_notifier_chain_unregister(&switchdev_notif_chain, nb); 50503bf0c28SJiri Pirko } 506ebb9a03aSJiri Pirko EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); 50703bf0c28SJiri Pirko 50803bf0c28SJiri Pirko /** 509ebb9a03aSJiri Pirko * call_switchdev_notifiers - Call notifiers 51003bf0c28SJiri Pirko * @val: value passed unmodified to notifier function 51103bf0c28SJiri Pirko * @dev: port device 51203bf0c28SJiri Pirko * @info: notifier information data 51303bf0c28SJiri Pirko * 514ff5cf100SArkadi Sharshevsky * Call all network notifier blocks. 51503bf0c28SJiri Pirko */ 516ebb9a03aSJiri Pirko int call_switchdev_notifiers(unsigned long val, struct net_device *dev, 5176685987cSPetr Machata struct switchdev_notifier_info *info, 5186685987cSPetr Machata struct netlink_ext_ack *extack) 51903bf0c28SJiri Pirko { 52003bf0c28SJiri Pirko info->dev = dev; 5216685987cSPetr Machata info->extack = extack; 522ff5cf100SArkadi Sharshevsky return atomic_notifier_call_chain(&switchdev_notif_chain, val, info); 52303bf0c28SJiri Pirko } 524ebb9a03aSJiri Pirko EXPORT_SYMBOL_GPL(call_switchdev_notifiers); 5258a44dbb2SRoopa Prabhu 526a93e3b17SPetr Machata int register_switchdev_blocking_notifier(struct notifier_block *nb) 527a93e3b17SPetr Machata { 528a93e3b17SPetr Machata struct blocking_notifier_head *chain = &switchdev_blocking_notif_chain; 529a93e3b17SPetr Machata 530a93e3b17SPetr Machata return blocking_notifier_chain_register(chain, nb); 531a93e3b17SPetr Machata } 532a93e3b17SPetr Machata EXPORT_SYMBOL_GPL(register_switchdev_blocking_notifier); 533a93e3b17SPetr Machata 534a93e3b17SPetr Machata int unregister_switchdev_blocking_notifier(struct notifier_block *nb) 535a93e3b17SPetr Machata { 536a93e3b17SPetr Machata struct blocking_notifier_head *chain = &switchdev_blocking_notif_chain; 537a93e3b17SPetr Machata 538a93e3b17SPetr Machata return blocking_notifier_chain_unregister(chain, nb); 539a93e3b17SPetr Machata } 540a93e3b17SPetr Machata EXPORT_SYMBOL_GPL(unregister_switchdev_blocking_notifier); 541a93e3b17SPetr Machata 542a93e3b17SPetr Machata int call_switchdev_blocking_notifiers(unsigned long val, struct net_device *dev, 543479c86dcSPetr Machata struct switchdev_notifier_info *info, 544479c86dcSPetr Machata struct netlink_ext_ack *extack) 545a93e3b17SPetr Machata { 546a93e3b17SPetr Machata info->dev = dev; 547479c86dcSPetr Machata info->extack = extack; 548a93e3b17SPetr Machata return blocking_notifier_call_chain(&switchdev_blocking_notif_chain, 549a93e3b17SPetr Machata val, info); 550a93e3b17SPetr Machata } 551a93e3b17SPetr Machata EXPORT_SYMBOL_GPL(call_switchdev_blocking_notifiers); 552a93e3b17SPetr Machata 553f30f0601SPetr Machata static int __switchdev_handle_port_obj_add(struct net_device *dev, 554f30f0601SPetr Machata struct switchdev_notifier_port_obj_info *port_obj_info, 555f30f0601SPetr Machata bool (*check_cb)(const struct net_device *dev), 556f30f0601SPetr Machata int (*add_cb)(struct net_device *dev, 557f30f0601SPetr Machata const struct switchdev_obj *obj, 55869213513SPetr Machata struct switchdev_trans *trans, 55969213513SPetr Machata struct netlink_ext_ack *extack)) 560f30f0601SPetr Machata { 56169213513SPetr Machata struct netlink_ext_ack *extack; 562f30f0601SPetr Machata struct net_device *lower_dev; 563f30f0601SPetr Machata struct list_head *iter; 564f30f0601SPetr Machata int err = -EOPNOTSUPP; 565f30f0601SPetr Machata 56669213513SPetr Machata extack = switchdev_notifier_info_to_extack(&port_obj_info->info); 56769213513SPetr Machata 568f30f0601SPetr Machata if (check_cb(dev)) { 569f30f0601SPetr Machata /* This flag is only checked if the return value is success. */ 570f30f0601SPetr Machata port_obj_info->handled = true; 57169213513SPetr Machata return add_cb(dev, port_obj_info->obj, port_obj_info->trans, 57269213513SPetr Machata extack); 573f30f0601SPetr Machata } 574f30f0601SPetr Machata 575f30f0601SPetr Machata /* Switch ports might be stacked under e.g. a LAG. Ignore the 576f30f0601SPetr Machata * unsupported devices, another driver might be able to handle them. But 577f30f0601SPetr Machata * propagate to the callers any hard errors. 578f30f0601SPetr Machata * 579f30f0601SPetr Machata * If the driver does its own bookkeeping of stacked ports, it's not 580f30f0601SPetr Machata * necessary to go through this helper. 581f30f0601SPetr Machata */ 582f30f0601SPetr Machata netdev_for_each_lower_dev(dev, lower_dev, iter) { 583f30f0601SPetr Machata err = __switchdev_handle_port_obj_add(lower_dev, port_obj_info, 584f30f0601SPetr Machata check_cb, add_cb); 585f30f0601SPetr Machata if (err && err != -EOPNOTSUPP) 586f30f0601SPetr Machata return err; 587f30f0601SPetr Machata } 588f30f0601SPetr Machata 589f30f0601SPetr Machata return err; 590f30f0601SPetr Machata } 591f30f0601SPetr Machata 592f30f0601SPetr Machata int switchdev_handle_port_obj_add(struct net_device *dev, 593f30f0601SPetr Machata struct switchdev_notifier_port_obj_info *port_obj_info, 594f30f0601SPetr Machata bool (*check_cb)(const struct net_device *dev), 595f30f0601SPetr Machata int (*add_cb)(struct net_device *dev, 596f30f0601SPetr Machata const struct switchdev_obj *obj, 59769213513SPetr Machata struct switchdev_trans *trans, 59869213513SPetr Machata struct netlink_ext_ack *extack)) 599f30f0601SPetr Machata { 600f30f0601SPetr Machata int err; 601f30f0601SPetr Machata 602f30f0601SPetr Machata err = __switchdev_handle_port_obj_add(dev, port_obj_info, check_cb, 603f30f0601SPetr Machata add_cb); 604f30f0601SPetr Machata if (err == -EOPNOTSUPP) 605f30f0601SPetr Machata err = 0; 606f30f0601SPetr Machata return err; 607f30f0601SPetr Machata } 608f30f0601SPetr Machata EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_add); 609f30f0601SPetr Machata 610f30f0601SPetr Machata static int __switchdev_handle_port_obj_del(struct net_device *dev, 611f30f0601SPetr Machata struct switchdev_notifier_port_obj_info *port_obj_info, 612f30f0601SPetr Machata bool (*check_cb)(const struct net_device *dev), 613f30f0601SPetr Machata int (*del_cb)(struct net_device *dev, 614f30f0601SPetr Machata const struct switchdev_obj *obj)) 615f30f0601SPetr Machata { 616f30f0601SPetr Machata struct net_device *lower_dev; 617f30f0601SPetr Machata struct list_head *iter; 618f30f0601SPetr Machata int err = -EOPNOTSUPP; 619f30f0601SPetr Machata 620f30f0601SPetr Machata if (check_cb(dev)) { 621f30f0601SPetr Machata /* This flag is only checked if the return value is success. */ 622f30f0601SPetr Machata port_obj_info->handled = true; 623f30f0601SPetr Machata return del_cb(dev, port_obj_info->obj); 624f30f0601SPetr Machata } 625f30f0601SPetr Machata 626f30f0601SPetr Machata /* Switch ports might be stacked under e.g. a LAG. Ignore the 627f30f0601SPetr Machata * unsupported devices, another driver might be able to handle them. But 628f30f0601SPetr Machata * propagate to the callers any hard errors. 629f30f0601SPetr Machata * 630f30f0601SPetr Machata * If the driver does its own bookkeeping of stacked ports, it's not 631f30f0601SPetr Machata * necessary to go through this helper. 632f30f0601SPetr Machata */ 633f30f0601SPetr Machata netdev_for_each_lower_dev(dev, lower_dev, iter) { 634f30f0601SPetr Machata err = __switchdev_handle_port_obj_del(lower_dev, port_obj_info, 635f30f0601SPetr Machata check_cb, del_cb); 636f30f0601SPetr Machata if (err && err != -EOPNOTSUPP) 637f30f0601SPetr Machata return err; 638f30f0601SPetr Machata } 639f30f0601SPetr Machata 640f30f0601SPetr Machata return err; 641f30f0601SPetr Machata } 642f30f0601SPetr Machata 643f30f0601SPetr Machata int switchdev_handle_port_obj_del(struct net_device *dev, 644f30f0601SPetr Machata struct switchdev_notifier_port_obj_info *port_obj_info, 645f30f0601SPetr Machata bool (*check_cb)(const struct net_device *dev), 646f30f0601SPetr Machata int (*del_cb)(struct net_device *dev, 647f30f0601SPetr Machata const struct switchdev_obj *obj)) 648f30f0601SPetr Machata { 649f30f0601SPetr Machata int err; 650f30f0601SPetr Machata 651f30f0601SPetr Machata err = __switchdev_handle_port_obj_del(dev, port_obj_info, check_cb, 652f30f0601SPetr Machata del_cb); 653f30f0601SPetr Machata if (err == -EOPNOTSUPP) 654f30f0601SPetr Machata err = 0; 655f30f0601SPetr Machata return err; 656f30f0601SPetr Machata } 657f30f0601SPetr Machata EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del); 658*1cb33af1SFlorian Fainelli 659*1cb33af1SFlorian Fainelli static int __switchdev_handle_port_attr_set(struct net_device *dev, 660*1cb33af1SFlorian Fainelli struct switchdev_notifier_port_attr_info *port_attr_info, 661*1cb33af1SFlorian Fainelli bool (*check_cb)(const struct net_device *dev), 662*1cb33af1SFlorian Fainelli int (*set_cb)(struct net_device *dev, 663*1cb33af1SFlorian Fainelli const struct switchdev_attr *attr, 664*1cb33af1SFlorian Fainelli struct switchdev_trans *trans)) 665*1cb33af1SFlorian Fainelli { 666*1cb33af1SFlorian Fainelli struct net_device *lower_dev; 667*1cb33af1SFlorian Fainelli struct list_head *iter; 668*1cb33af1SFlorian Fainelli int err = -EOPNOTSUPP; 669*1cb33af1SFlorian Fainelli 670*1cb33af1SFlorian Fainelli if (check_cb(dev)) { 671*1cb33af1SFlorian Fainelli port_attr_info->handled = true; 672*1cb33af1SFlorian Fainelli return set_cb(dev, port_attr_info->attr, 673*1cb33af1SFlorian Fainelli port_attr_info->trans); 674*1cb33af1SFlorian Fainelli } 675*1cb33af1SFlorian Fainelli 676*1cb33af1SFlorian Fainelli /* Switch ports might be stacked under e.g. a LAG. Ignore the 677*1cb33af1SFlorian Fainelli * unsupported devices, another driver might be able to handle them. But 678*1cb33af1SFlorian Fainelli * propagate to the callers any hard errors. 679*1cb33af1SFlorian Fainelli * 680*1cb33af1SFlorian Fainelli * If the driver does its own bookkeeping of stacked ports, it's not 681*1cb33af1SFlorian Fainelli * necessary to go through this helper. 682*1cb33af1SFlorian Fainelli */ 683*1cb33af1SFlorian Fainelli netdev_for_each_lower_dev(dev, lower_dev, iter) { 684*1cb33af1SFlorian Fainelli err = __switchdev_handle_port_attr_set(lower_dev, port_attr_info, 685*1cb33af1SFlorian Fainelli check_cb, set_cb); 686*1cb33af1SFlorian Fainelli if (err && err != -EOPNOTSUPP) 687*1cb33af1SFlorian Fainelli return err; 688*1cb33af1SFlorian Fainelli } 689*1cb33af1SFlorian Fainelli 690*1cb33af1SFlorian Fainelli return err; 691*1cb33af1SFlorian Fainelli } 692*1cb33af1SFlorian Fainelli 693*1cb33af1SFlorian Fainelli int switchdev_handle_port_attr_set(struct net_device *dev, 694*1cb33af1SFlorian Fainelli struct switchdev_notifier_port_attr_info *port_attr_info, 695*1cb33af1SFlorian Fainelli bool (*check_cb)(const struct net_device *dev), 696*1cb33af1SFlorian Fainelli int (*set_cb)(struct net_device *dev, 697*1cb33af1SFlorian Fainelli const struct switchdev_attr *attr, 698*1cb33af1SFlorian Fainelli struct switchdev_trans *trans)) 699*1cb33af1SFlorian Fainelli { 700*1cb33af1SFlorian Fainelli int err; 701*1cb33af1SFlorian Fainelli 702*1cb33af1SFlorian Fainelli err = __switchdev_handle_port_attr_set(dev, port_attr_info, check_cb, 703*1cb33af1SFlorian Fainelli set_cb); 704*1cb33af1SFlorian Fainelli if (err == -EOPNOTSUPP) 705*1cb33af1SFlorian Fainelli err = 0; 706*1cb33af1SFlorian Fainelli return err; 707*1cb33af1SFlorian Fainelli } 708*1cb33af1SFlorian Fainelli EXPORT_SYMBOL_GPL(switchdev_handle_port_attr_set); 709