summaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r--net/switchdev/switchdev.c67
1 files changed, 25 insertions, 42 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 099434ec7996..fe23fac4dc4b 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -353,30 +353,29 @@ static size_t switchdev_obj_size(const struct switchdev_obj *obj)
353 return 0; 353 return 0;
354} 354}
355 355
356static int __switchdev_port_obj_add(struct net_device *dev, 356static int switchdev_port_obj_notify(enum switchdev_notifier_type nt,
357 const struct switchdev_obj *obj, 357 struct net_device *dev,
358 struct switchdev_trans *trans) 358 const struct switchdev_obj *obj,
359 struct switchdev_trans *trans)
359{ 360{
360 const struct switchdev_ops *ops = dev->switchdev_ops; 361 int rc;
361 struct net_device *lower_dev; 362 int err;
362 struct list_head *iter;
363 int err = -EOPNOTSUPP;
364
365 if (ops && ops->switchdev_port_obj_add)
366 return ops->switchdev_port_obj_add(dev, obj, trans);
367 363
368 /* Switch device port(s) may be stacked under 364 struct switchdev_notifier_port_obj_info obj_info = {
369 * bond/team/vlan dev, so recurse down to add object on 365 .obj = obj,
370 * each port. 366 .trans = trans,
371 */ 367 .handled = false,
368 };
372 369
373 netdev_for_each_lower_dev(dev, lower_dev, iter) { 370 rc = call_switchdev_blocking_notifiers(nt, dev, &obj_info.info);
374 err = __switchdev_port_obj_add(lower_dev, obj, trans); 371 err = notifier_to_errno(rc);
375 if (err) 372 if (err) {
376 break; 373 WARN_ON(!obj_info.handled);
374 return err;
377 } 375 }
378 376 if (!obj_info.handled)
379 return err; 377 return -EOPNOTSUPP;
378 return 0;
380} 379}
381 380
382static int switchdev_port_obj_add_now(struct net_device *dev, 381static int switchdev_port_obj_add_now(struct net_device *dev,
@@ -397,7 +396,8 @@ static int switchdev_port_obj_add_now(struct net_device *dev,
397 */ 396 */
398 397
399 trans.ph_prepare = true; 398 trans.ph_prepare = true;
400 err = __switchdev_port_obj_add(dev, obj, &trans); 399 err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
400 dev, obj, &trans);
401 if (err) { 401 if (err) {
402 /* Prepare phase failed: abort the transaction. Any 402 /* Prepare phase failed: abort the transaction. Any
403 * resources reserved in the prepare phase are 403 * resources reserved in the prepare phase are
@@ -416,7 +416,8 @@ static int switchdev_port_obj_add_now(struct net_device *dev,
416 */ 416 */
417 417
418 trans.ph_prepare = false; 418 trans.ph_prepare = false;
419 err = __switchdev_port_obj_add(dev, obj, &trans); 419 err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
420 dev, obj, &trans);
420 WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); 421 WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id);
421 switchdev_trans_items_warn_destroy(dev, &trans); 422 switchdev_trans_items_warn_destroy(dev, &trans);
422 423
@@ -471,26 +472,8 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
471static int switchdev_port_obj_del_now(struct net_device *dev, 472static int switchdev_port_obj_del_now(struct net_device *dev,
472 const struct switchdev_obj *obj) 473 const struct switchdev_obj *obj)
473{ 474{
474 const struct switchdev_ops *ops = dev->switchdev_ops; 475 return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_DEL,
475 struct net_device *lower_dev; 476 dev, obj, NULL);
476 struct list_head *iter;
477 int err = -EOPNOTSUPP;
478
479 if (ops && ops->switchdev_port_obj_del)
480 return ops->switchdev_port_obj_del(dev, obj);
481
482 /* Switch device port(s) may be stacked under
483 * bond/team/vlan dev, so recurse down to delete object on
484 * each port.
485 */
486
487 netdev_for_each_lower_dev(dev, lower_dev, iter) {
488 err = switchdev_port_obj_del_now(lower_dev, obj);
489 if (err)
490 break;
491 }
492
493 return err;
494} 477}
495 478
496static void switchdev_port_obj_del_deferred(struct net_device *dev, 479static void switchdev_port_obj_del_deferred(struct net_device *dev,