diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r-- | net/switchdev/switchdev.c | 435 |
1 files changed, 0 insertions, 435 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 3d32981b9aa1..0531b41d1f2d 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -343,8 +343,6 @@ static size_t switchdev_obj_size(const struct switchdev_obj *obj) | |||
343 | switch (obj->id) { | 343 | switch (obj->id) { |
344 | case SWITCHDEV_OBJ_ID_PORT_VLAN: | 344 | case SWITCHDEV_OBJ_ID_PORT_VLAN: |
345 | return sizeof(struct switchdev_obj_port_vlan); | 345 | return sizeof(struct switchdev_obj_port_vlan); |
346 | case SWITCHDEV_OBJ_ID_PORT_FDB: | ||
347 | return sizeof(struct switchdev_obj_port_fdb); | ||
348 | case SWITCHDEV_OBJ_ID_PORT_MDB: | 346 | case SWITCHDEV_OBJ_ID_PORT_MDB: |
349 | return sizeof(struct switchdev_obj_port_mdb); | 347 | return sizeof(struct switchdev_obj_port_mdb); |
350 | default: | 348 | default: |
@@ -534,43 +532,6 @@ int switchdev_port_obj_del(struct net_device *dev, | |||
534 | } | 532 | } |
535 | EXPORT_SYMBOL_GPL(switchdev_port_obj_del); | 533 | EXPORT_SYMBOL_GPL(switchdev_port_obj_del); |
536 | 534 | ||
537 | /** | ||
538 | * switchdev_port_obj_dump - Dump port objects | ||
539 | * | ||
540 | * @dev: port device | ||
541 | * @id: object ID | ||
542 | * @obj: object to dump | ||
543 | * @cb: function to call with a filled object | ||
544 | * | ||
545 | * rtnl_lock must be held. | ||
546 | */ | ||
547 | int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, | ||
548 | switchdev_obj_dump_cb_t *cb) | ||
549 | { | ||
550 | const struct switchdev_ops *ops = dev->switchdev_ops; | ||
551 | struct net_device *lower_dev; | ||
552 | struct list_head *iter; | ||
553 | int err = -EOPNOTSUPP; | ||
554 | |||
555 | ASSERT_RTNL(); | ||
556 | |||
557 | if (ops && ops->switchdev_port_obj_dump) | ||
558 | return ops->switchdev_port_obj_dump(dev, obj, cb); | ||
559 | |||
560 | /* Switch device port(s) may be stacked under | ||
561 | * bond/team/vlan dev, so recurse down to dump objects on | ||
562 | * first port at bottom of stack. | ||
563 | */ | ||
564 | |||
565 | netdev_for_each_lower_dev(dev, lower_dev, iter) { | ||
566 | err = switchdev_port_obj_dump(lower_dev, obj, cb); | ||
567 | break; | ||
568 | } | ||
569 | |||
570 | return err; | ||
571 | } | ||
572 | EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); | ||
573 | |||
574 | static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain); | 535 | static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain); |
575 | 536 | ||
576 | /** | 537 | /** |
@@ -613,402 +574,6 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, | |||
613 | } | 574 | } |
614 | EXPORT_SYMBOL_GPL(call_switchdev_notifiers); | 575 | EXPORT_SYMBOL_GPL(call_switchdev_notifiers); |
615 | 576 | ||
616 | struct switchdev_vlan_dump { | ||
617 | struct switchdev_obj_port_vlan vlan; | ||
618 | struct sk_buff *skb; | ||
619 | u32 filter_mask; | ||
620 | u16 flags; | ||
621 | u16 begin; | ||
622 | u16 end; | ||
623 | }; | ||
624 | |||
625 | static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) | ||
626 | { | ||
627 | struct bridge_vlan_info vinfo; | ||
628 | |||
629 | vinfo.flags = dump->flags; | ||
630 | |||
631 | if (dump->begin == 0 && dump->end == 0) { | ||
632 | return 0; | ||
633 | } else if (dump->begin == dump->end) { | ||
634 | vinfo.vid = dump->begin; | ||
635 | if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO, | ||
636 | sizeof(vinfo), &vinfo)) | ||
637 | return -EMSGSIZE; | ||
638 | } else { | ||
639 | vinfo.vid = dump->begin; | ||
640 | vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; | ||
641 | if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO, | ||
642 | sizeof(vinfo), &vinfo)) | ||
643 | return -EMSGSIZE; | ||
644 | vinfo.vid = dump->end; | ||
645 | vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; | ||
646 | vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END; | ||
647 | if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO, | ||
648 | sizeof(vinfo), &vinfo)) | ||
649 | return -EMSGSIZE; | ||
650 | } | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int switchdev_port_vlan_dump_cb(struct switchdev_obj *obj) | ||
656 | { | ||
657 | struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); | ||
658 | struct switchdev_vlan_dump *dump = | ||
659 | container_of(vlan, struct switchdev_vlan_dump, vlan); | ||
660 | int err = 0; | ||
661 | |||
662 | if (vlan->vid_begin > vlan->vid_end) | ||
663 | return -EINVAL; | ||
664 | |||
665 | if (dump->filter_mask & RTEXT_FILTER_BRVLAN) { | ||
666 | dump->flags = vlan->flags; | ||
667 | for (dump->begin = dump->end = vlan->vid_begin; | ||
668 | dump->begin <= vlan->vid_end; | ||
669 | dump->begin++, dump->end++) { | ||
670 | err = switchdev_port_vlan_dump_put(dump); | ||
671 | if (err) | ||
672 | return err; | ||
673 | } | ||
674 | } else if (dump->filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) { | ||
675 | if (dump->begin > vlan->vid_begin && | ||
676 | dump->begin >= vlan->vid_end) { | ||
677 | if ((dump->begin - 1) == vlan->vid_end && | ||
678 | dump->flags == vlan->flags) { | ||
679 | /* prepend */ | ||
680 | dump->begin = vlan->vid_begin; | ||
681 | } else { | ||
682 | err = switchdev_port_vlan_dump_put(dump); | ||
683 | dump->flags = vlan->flags; | ||
684 | dump->begin = vlan->vid_begin; | ||
685 | dump->end = vlan->vid_end; | ||
686 | } | ||
687 | } else if (dump->end <= vlan->vid_begin && | ||
688 | dump->end < vlan->vid_end) { | ||
689 | if ((dump->end + 1) == vlan->vid_begin && | ||
690 | dump->flags == vlan->flags) { | ||
691 | /* append */ | ||
692 | dump->end = vlan->vid_end; | ||
693 | } else { | ||
694 | err = switchdev_port_vlan_dump_put(dump); | ||
695 | dump->flags = vlan->flags; | ||
696 | dump->begin = vlan->vid_begin; | ||
697 | dump->end = vlan->vid_end; | ||
698 | } | ||
699 | } else { | ||
700 | err = -EINVAL; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | return err; | ||
705 | } | ||
706 | |||
707 | static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, | ||
708 | u32 filter_mask) | ||
709 | { | ||
710 | struct switchdev_vlan_dump dump = { | ||
711 | .vlan.obj.orig_dev = dev, | ||
712 | .vlan.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, | ||
713 | .skb = skb, | ||
714 | .filter_mask = filter_mask, | ||
715 | }; | ||
716 | int err = 0; | ||
717 | |||
718 | if ((filter_mask & RTEXT_FILTER_BRVLAN) || | ||
719 | (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { | ||
720 | err = switchdev_port_obj_dump(dev, &dump.vlan.obj, | ||
721 | switchdev_port_vlan_dump_cb); | ||
722 | if (err) | ||
723 | goto err_out; | ||
724 | if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) | ||
725 | /* last one */ | ||
726 | err = switchdev_port_vlan_dump_put(&dump); | ||
727 | } | ||
728 | |||
729 | err_out: | ||
730 | return err == -EOPNOTSUPP ? 0 : err; | ||
731 | } | ||
732 | |||
733 | /** | ||
734 | * switchdev_port_bridge_getlink - Get bridge port attributes | ||
735 | * | ||
736 | * @dev: port device | ||
737 | * | ||
738 | * Called for SELF on rtnl_bridge_getlink to get bridge port | ||
739 | * attributes. | ||
740 | */ | ||
741 | int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, | ||
742 | struct net_device *dev, u32 filter_mask, | ||
743 | int nlflags) | ||
744 | { | ||
745 | struct switchdev_attr attr = { | ||
746 | .orig_dev = dev, | ||
747 | .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, | ||
748 | }; | ||
749 | u16 mode = BRIDGE_MODE_UNDEF; | ||
750 | u32 mask = BR_LEARNING | BR_LEARNING_SYNC | BR_FLOOD; | ||
751 | int err; | ||
752 | |||
753 | if (!netif_is_bridge_port(dev)) | ||
754 | return -EOPNOTSUPP; | ||
755 | |||
756 | err = switchdev_port_attr_get(dev, &attr); | ||
757 | if (err && err != -EOPNOTSUPP) | ||
758 | return err; | ||
759 | |||
760 | return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, | ||
761 | attr.u.brport_flags, mask, nlflags, | ||
762 | filter_mask, switchdev_port_vlan_fill); | ||
763 | } | ||
764 | EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink); | ||
765 | |||
766 | static int switchdev_port_br_setflag(struct net_device *dev, | ||
767 | struct nlattr *nlattr, | ||
768 | unsigned long brport_flag) | ||
769 | { | ||
770 | struct switchdev_attr attr = { | ||
771 | .orig_dev = dev, | ||
772 | .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, | ||
773 | }; | ||
774 | u8 flag = nla_get_u8(nlattr); | ||
775 | int err; | ||
776 | |||
777 | err = switchdev_port_attr_get(dev, &attr); | ||
778 | if (err) | ||
779 | return err; | ||
780 | |||
781 | if (flag) | ||
782 | attr.u.brport_flags |= brport_flag; | ||
783 | else | ||
784 | attr.u.brport_flags &= ~brport_flag; | ||
785 | |||
786 | return switchdev_port_attr_set(dev, &attr); | ||
787 | } | ||
788 | |||
789 | static const struct nla_policy | ||
790 | switchdev_port_bridge_policy[IFLA_BRPORT_MAX + 1] = { | ||
791 | [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, | ||
792 | [IFLA_BRPORT_COST] = { .type = NLA_U32 }, | ||
793 | [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, | ||
794 | [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, | ||
795 | [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, | ||
796 | [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, | ||
797 | [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 }, | ||
798 | [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, | ||
799 | [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 }, | ||
800 | [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, | ||
801 | }; | ||
802 | |||
803 | static int switchdev_port_br_setlink_protinfo(struct net_device *dev, | ||
804 | struct nlattr *protinfo) | ||
805 | { | ||
806 | struct nlattr *attr; | ||
807 | int rem; | ||
808 | int err; | ||
809 | |||
810 | err = nla_validate_nested(protinfo, IFLA_BRPORT_MAX, | ||
811 | switchdev_port_bridge_policy, NULL); | ||
812 | if (err) | ||
813 | return err; | ||
814 | |||
815 | nla_for_each_nested(attr, protinfo, rem) { | ||
816 | switch (nla_type(attr)) { | ||
817 | case IFLA_BRPORT_LEARNING: | ||
818 | err = switchdev_port_br_setflag(dev, attr, | ||
819 | BR_LEARNING); | ||
820 | break; | ||
821 | case IFLA_BRPORT_LEARNING_SYNC: | ||
822 | err = switchdev_port_br_setflag(dev, attr, | ||
823 | BR_LEARNING_SYNC); | ||
824 | break; | ||
825 | case IFLA_BRPORT_UNICAST_FLOOD: | ||
826 | err = switchdev_port_br_setflag(dev, attr, BR_FLOOD); | ||
827 | break; | ||
828 | default: | ||
829 | err = -EOPNOTSUPP; | ||
830 | break; | ||
831 | } | ||
832 | if (err) | ||
833 | return err; | ||
834 | } | ||
835 | |||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static int switchdev_port_br_afspec(struct net_device *dev, | ||
840 | struct nlattr *afspec, | ||
841 | int (*f)(struct net_device *dev, | ||
842 | const struct switchdev_obj *obj)) | ||
843 | { | ||
844 | struct nlattr *attr; | ||
845 | struct bridge_vlan_info *vinfo; | ||
846 | struct switchdev_obj_port_vlan vlan = { | ||
847 | .obj.orig_dev = dev, | ||
848 | .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, | ||
849 | }; | ||
850 | int rem; | ||
851 | int err; | ||
852 | |||
853 | nla_for_each_nested(attr, afspec, rem) { | ||
854 | if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO) | ||
855 | continue; | ||
856 | if (nla_len(attr) != sizeof(struct bridge_vlan_info)) | ||
857 | return -EINVAL; | ||
858 | vinfo = nla_data(attr); | ||
859 | if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) | ||
860 | return -EINVAL; | ||
861 | vlan.flags = vinfo->flags; | ||
862 | if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { | ||
863 | if (vlan.vid_begin) | ||
864 | return -EINVAL; | ||
865 | vlan.vid_begin = vinfo->vid; | ||
866 | /* don't allow range of pvids */ | ||
867 | if (vlan.flags & BRIDGE_VLAN_INFO_PVID) | ||
868 | return -EINVAL; | ||
869 | } else if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) { | ||
870 | if (!vlan.vid_begin) | ||
871 | return -EINVAL; | ||
872 | vlan.vid_end = vinfo->vid; | ||
873 | if (vlan.vid_end <= vlan.vid_begin) | ||
874 | return -EINVAL; | ||
875 | err = f(dev, &vlan.obj); | ||
876 | if (err) | ||
877 | return err; | ||
878 | vlan.vid_begin = 0; | ||
879 | } else { | ||
880 | if (vlan.vid_begin) | ||
881 | return -EINVAL; | ||
882 | vlan.vid_begin = vinfo->vid; | ||
883 | vlan.vid_end = vinfo->vid; | ||
884 | err = f(dev, &vlan.obj); | ||
885 | if (err) | ||
886 | return err; | ||
887 | vlan.vid_begin = 0; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | /** | ||
895 | * switchdev_port_bridge_setlink - Set bridge port attributes | ||
896 | * | ||
897 | * @dev: port device | ||
898 | * @nlh: netlink header | ||
899 | * @flags: netlink flags | ||
900 | * | ||
901 | * Called for SELF on rtnl_bridge_setlink to set bridge port | ||
902 | * attributes. | ||
903 | */ | ||
904 | int switchdev_port_bridge_setlink(struct net_device *dev, | ||
905 | struct nlmsghdr *nlh, u16 flags) | ||
906 | { | ||
907 | struct nlattr *protinfo; | ||
908 | struct nlattr *afspec; | ||
909 | int err = 0; | ||
910 | |||
911 | if (!netif_is_bridge_port(dev)) | ||
912 | return -EOPNOTSUPP; | ||
913 | |||
914 | protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), | ||
915 | IFLA_PROTINFO); | ||
916 | if (protinfo) { | ||
917 | err = switchdev_port_br_setlink_protinfo(dev, protinfo); | ||
918 | if (err) | ||
919 | return err; | ||
920 | } | ||
921 | |||
922 | afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), | ||
923 | IFLA_AF_SPEC); | ||
924 | if (afspec) | ||
925 | err = switchdev_port_br_afspec(dev, afspec, | ||
926 | switchdev_port_obj_add); | ||
927 | |||
928 | return err; | ||
929 | } | ||
930 | EXPORT_SYMBOL_GPL(switchdev_port_bridge_setlink); | ||
931 | |||
932 | /** | ||
933 | * switchdev_port_bridge_dellink - Set bridge port attributes | ||
934 | * | ||
935 | * @dev: port device | ||
936 | * @nlh: netlink header | ||
937 | * @flags: netlink flags | ||
938 | * | ||
939 | * Called for SELF on rtnl_bridge_dellink to set bridge port | ||
940 | * attributes. | ||
941 | */ | ||
942 | int switchdev_port_bridge_dellink(struct net_device *dev, | ||
943 | struct nlmsghdr *nlh, u16 flags) | ||
944 | { | ||
945 | struct nlattr *afspec; | ||
946 | |||
947 | if (!netif_is_bridge_port(dev)) | ||
948 | return -EOPNOTSUPP; | ||
949 | |||
950 | afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), | ||
951 | IFLA_AF_SPEC); | ||
952 | if (afspec) | ||
953 | return switchdev_port_br_afspec(dev, afspec, | ||
954 | switchdev_port_obj_del); | ||
955 | |||
956 | return 0; | ||
957 | } | ||
958 | EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); | ||
959 | |||
960 | /** | ||
961 | * switchdev_port_fdb_add - Add FDB (MAC/VLAN) entry to port | ||
962 | * | ||
963 | * @ndmsg: netlink hdr | ||
964 | * @nlattr: netlink attributes | ||
965 | * @dev: port device | ||
966 | * @addr: MAC address to add | ||
967 | * @vid: VLAN to add | ||
968 | * | ||
969 | * Add FDB entry to switch device. | ||
970 | */ | ||
971 | int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | ||
972 | struct net_device *dev, const unsigned char *addr, | ||
973 | u16 vid, u16 nlm_flags) | ||
974 | { | ||
975 | struct switchdev_obj_port_fdb fdb = { | ||
976 | .obj.orig_dev = dev, | ||
977 | .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, | ||
978 | .vid = vid, | ||
979 | }; | ||
980 | |||
981 | ether_addr_copy(fdb.addr, addr); | ||
982 | return switchdev_port_obj_add(dev, &fdb.obj); | ||
983 | } | ||
984 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); | ||
985 | |||
986 | /** | ||
987 | * switchdev_port_fdb_del - Delete FDB (MAC/VLAN) entry from port | ||
988 | * | ||
989 | * @ndmsg: netlink hdr | ||
990 | * @nlattr: netlink attributes | ||
991 | * @dev: port device | ||
992 | * @addr: MAC address to delete | ||
993 | * @vid: VLAN to delete | ||
994 | * | ||
995 | * Delete FDB entry from switch device. | ||
996 | */ | ||
997 | int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | ||
998 | struct net_device *dev, const unsigned char *addr, | ||
999 | u16 vid) | ||
1000 | { | ||
1001 | struct switchdev_obj_port_fdb fdb = { | ||
1002 | .obj.orig_dev = dev, | ||
1003 | .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, | ||
1004 | .vid = vid, | ||
1005 | }; | ||
1006 | |||
1007 | ether_addr_copy(fdb.addr, addr); | ||
1008 | return switchdev_port_obj_del(dev, &fdb.obj); | ||
1009 | } | ||
1010 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); | ||
1011 | |||
1012 | bool switchdev_port_same_parent_id(struct net_device *a, | 577 | bool switchdev_port_same_parent_id(struct net_device *a, |
1013 | struct net_device *b) | 578 | struct net_device *b) |
1014 | { | 579 | { |