diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r-- | net/switchdev/switchdev.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index e109bb97ce3f..099434ec7996 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -621,3 +621,103 @@ bool switchdev_port_same_parent_id(struct net_device *a, | |||
621 | return netdev_phys_item_id_same(&a_attr.u.ppid, &b_attr.u.ppid); | 621 | return netdev_phys_item_id_same(&a_attr.u.ppid, &b_attr.u.ppid); |
622 | } | 622 | } |
623 | EXPORT_SYMBOL_GPL(switchdev_port_same_parent_id); | 623 | EXPORT_SYMBOL_GPL(switchdev_port_same_parent_id); |
624 | |||
625 | static int __switchdev_handle_port_obj_add(struct net_device *dev, | ||
626 | struct switchdev_notifier_port_obj_info *port_obj_info, | ||
627 | bool (*check_cb)(const struct net_device *dev), | ||
628 | int (*add_cb)(struct net_device *dev, | ||
629 | const struct switchdev_obj *obj, | ||
630 | struct switchdev_trans *trans)) | ||
631 | { | ||
632 | struct net_device *lower_dev; | ||
633 | struct list_head *iter; | ||
634 | int err = -EOPNOTSUPP; | ||
635 | |||
636 | if (check_cb(dev)) { | ||
637 | /* This flag is only checked if the return value is success. */ | ||
638 | port_obj_info->handled = true; | ||
639 | return add_cb(dev, port_obj_info->obj, port_obj_info->trans); | ||
640 | } | ||
641 | |||
642 | /* Switch ports might be stacked under e.g. a LAG. Ignore the | ||
643 | * unsupported devices, another driver might be able to handle them. But | ||
644 | * propagate to the callers any hard errors. | ||
645 | * | ||
646 | * If the driver does its own bookkeeping of stacked ports, it's not | ||
647 | * necessary to go through this helper. | ||
648 | */ | ||
649 | netdev_for_each_lower_dev(dev, lower_dev, iter) { | ||
650 | err = __switchdev_handle_port_obj_add(lower_dev, port_obj_info, | ||
651 | check_cb, add_cb); | ||
652 | if (err && err != -EOPNOTSUPP) | ||
653 | return err; | ||
654 | } | ||
655 | |||
656 | return err; | ||
657 | } | ||
658 | |||
659 | int switchdev_handle_port_obj_add(struct net_device *dev, | ||
660 | struct switchdev_notifier_port_obj_info *port_obj_info, | ||
661 | bool (*check_cb)(const struct net_device *dev), | ||
662 | int (*add_cb)(struct net_device *dev, | ||
663 | const struct switchdev_obj *obj, | ||
664 | struct switchdev_trans *trans)) | ||
665 | { | ||
666 | int err; | ||
667 | |||
668 | err = __switchdev_handle_port_obj_add(dev, port_obj_info, check_cb, | ||
669 | add_cb); | ||
670 | if (err == -EOPNOTSUPP) | ||
671 | err = 0; | ||
672 | return err; | ||
673 | } | ||
674 | EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_add); | ||
675 | |||
676 | static int __switchdev_handle_port_obj_del(struct net_device *dev, | ||
677 | struct switchdev_notifier_port_obj_info *port_obj_info, | ||
678 | bool (*check_cb)(const struct net_device *dev), | ||
679 | int (*del_cb)(struct net_device *dev, | ||
680 | const struct switchdev_obj *obj)) | ||
681 | { | ||
682 | struct net_device *lower_dev; | ||
683 | struct list_head *iter; | ||
684 | int err = -EOPNOTSUPP; | ||
685 | |||
686 | if (check_cb(dev)) { | ||
687 | /* This flag is only checked if the return value is success. */ | ||
688 | port_obj_info->handled = true; | ||
689 | return del_cb(dev, port_obj_info->obj); | ||
690 | } | ||
691 | |||
692 | /* Switch ports might be stacked under e.g. a LAG. Ignore the | ||
693 | * unsupported devices, another driver might be able to handle them. But | ||
694 | * propagate to the callers any hard errors. | ||
695 | * | ||
696 | * If the driver does its own bookkeeping of stacked ports, it's not | ||
697 | * necessary to go through this helper. | ||
698 | */ | ||
699 | netdev_for_each_lower_dev(dev, lower_dev, iter) { | ||
700 | err = __switchdev_handle_port_obj_del(lower_dev, port_obj_info, | ||
701 | check_cb, del_cb); | ||
702 | if (err && err != -EOPNOTSUPP) | ||
703 | return err; | ||
704 | } | ||
705 | |||
706 | return err; | ||
707 | } | ||
708 | |||
709 | int switchdev_handle_port_obj_del(struct net_device *dev, | ||
710 | struct switchdev_notifier_port_obj_info *port_obj_info, | ||
711 | bool (*check_cb)(const struct net_device *dev), | ||
712 | int (*del_cb)(struct net_device *dev, | ||
713 | const struct switchdev_obj *obj)) | ||
714 | { | ||
715 | int err; | ||
716 | |||
717 | err = __switchdev_handle_port_obj_del(dev, port_obj_info, check_cb, | ||
718 | del_cb); | ||
719 | if (err == -EOPNOTSUPP) | ||
720 | err = 0; | ||
721 | return err; | ||
722 | } | ||
723 | EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del); | ||