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.c435
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}
535EXPORT_SYMBOL_GPL(switchdev_port_obj_del); 533EXPORT_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 */
547int 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}
572EXPORT_SYMBOL_GPL(switchdev_port_obj_dump);
573
574static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain); 535static 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}
614EXPORT_SYMBOL_GPL(call_switchdev_notifiers); 575EXPORT_SYMBOL_GPL(call_switchdev_notifiers);
615 576
616struct 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
625static 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
655static 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
707static 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
729err_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 */
741int 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}
764EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink);
765
766static 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
789static const struct nla_policy
790switchdev_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
803static 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
839static 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 */
904int 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}
930EXPORT_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 */
942int 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}
958EXPORT_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 */
971int 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}
984EXPORT_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 */
997int 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}
1010EXPORT_SYMBOL_GPL(switchdev_port_fdb_del);
1011
1012bool switchdev_port_same_parent_id(struct net_device *a, 577bool switchdev_port_same_parent_id(struct net_device *a,
1013 struct net_device *b) 578 struct net_device *b)
1014{ 579{