diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r-- | net/switchdev/switchdev.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 362413c9b389..3560c19aa7e2 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -655,3 +655,54 @@ int switchdev_handle_port_obj_del(struct net_device *dev, | |||
655 | return err; | 655 | return err; |
656 | } | 656 | } |
657 | EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del); | 657 | EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del); |
658 | |||
659 | static int __switchdev_handle_port_attr_set(struct net_device *dev, | ||
660 | struct switchdev_notifier_port_attr_info *port_attr_info, | ||
661 | bool (*check_cb)(const struct net_device *dev), | ||
662 | int (*set_cb)(struct net_device *dev, | ||
663 | const struct switchdev_attr *attr, | ||
664 | struct switchdev_trans *trans)) | ||
665 | { | ||
666 | struct net_device *lower_dev; | ||
667 | struct list_head *iter; | ||
668 | int err = -EOPNOTSUPP; | ||
669 | |||
670 | if (check_cb(dev)) { | ||
671 | port_attr_info->handled = true; | ||
672 | return set_cb(dev, port_attr_info->attr, | ||
673 | port_attr_info->trans); | ||
674 | } | ||
675 | |||
676 | /* Switch ports might be stacked under e.g. a LAG. Ignore the | ||
677 | * unsupported devices, another driver might be able to handle them. But | ||
678 | * propagate to the callers any hard errors. | ||
679 | * | ||
680 | * If the driver does its own bookkeeping of stacked ports, it's not | ||
681 | * necessary to go through this helper. | ||
682 | */ | ||
683 | netdev_for_each_lower_dev(dev, lower_dev, iter) { | ||
684 | err = __switchdev_handle_port_attr_set(lower_dev, port_attr_info, | ||
685 | check_cb, set_cb); | ||
686 | if (err && err != -EOPNOTSUPP) | ||
687 | return err; | ||
688 | } | ||
689 | |||
690 | return err; | ||
691 | } | ||
692 | |||
693 | int switchdev_handle_port_attr_set(struct net_device *dev, | ||
694 | struct switchdev_notifier_port_attr_info *port_attr_info, | ||
695 | bool (*check_cb)(const struct net_device *dev), | ||
696 | int (*set_cb)(struct net_device *dev, | ||
697 | const struct switchdev_attr *attr, | ||
698 | struct switchdev_trans *trans)) | ||
699 | { | ||
700 | int err; | ||
701 | |||
702 | err = __switchdev_handle_port_attr_set(dev, port_attr_info, check_cb, | ||
703 | set_cb); | ||
704 | if (err == -EOPNOTSUPP) | ||
705 | err = 0; | ||
706 | return err; | ||
707 | } | ||
708 | EXPORT_SYMBOL_GPL(switchdev_handle_port_attr_set); | ||