aboutsummaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r--net/switchdev/switchdev.c100
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}
623EXPORT_SYMBOL_GPL(switchdev_port_same_parent_id); 623EXPORT_SYMBOL_GPL(switchdev_port_same_parent_id);
624
625static 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
659int 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}
674EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_add);
675
676static 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
709int 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}
723EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del);