aboutsummaryrefslogtreecommitdiffstats
path: root/net/switchdev
diff options
context:
space:
mode:
authorPetr Machata <petrm@mellanox.com>2018-11-22 18:29:44 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-23 21:02:24 -0500
commitf30f0601eb934dda107decd2e57b37168096fd74 (patch)
treeeeaa348788148859c9d383a66916eb5a4b7087c2 /net/switchdev
parenta39b888863afef5d43d6262d14b2f153ccda3151 (diff)
switchdev: Add helpers to aid traversal through lower devices
After the transition from switchdev operations to notifier chain (which will take place in following patches), the onus is on the driver to find its own devices below possible layer of LAG or other uppers. The logic to do so is fairly repetitive: each driver is looking for its own devices among the lowers of the notified device. For those that it finds, it calls a handler. To indicate that the event was handled, struct switchdev_notifier_port_obj_info.handled is set. The differences lie only in what constitutes an "own" device and what handler to call. Therefore abstract this logic into two helpers, switchdev_handle_port_obj_add() and switchdev_handle_port_obj_del(). If a driver only supports physical ports under a bridge device, it will simply avoid this layer of indirection. One area where this helper diverges from the current switchdev behavior is the case of mixed lowers, some of which are switchdev ports and some of which are not. Previously, such scenario would fail with -EOPNOTSUPP. The helper could do that for lowers for which the passed-in predicate doesn't hold. That would however break the case that switchdev ports from several different drivers are stashed under one master, a scenario that switchdev currently happily supports. Therefore tolerate any and all unknown netdevices, whether they are backed by a switchdev driver or not. Signed-off-by: Petr Machata <petrm@mellanox.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev')
-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);