diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/rtnetlink.c | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 66db1201da9b..e4b9870e4706 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -660,6 +660,31 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev) | |||
660 | return 0; | 660 | return 0; |
661 | } | 661 | } |
662 | 662 | ||
663 | static size_t rtnl_port_size(const struct net_device *dev) | ||
664 | { | ||
665 | size_t port_size = nla_total_size(4) /* PORT_VF */ | ||
666 | + nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */ | ||
667 | + nla_total_size(sizeof(struct ifla_port_vsi)) | ||
668 | /* PORT_VSI_TYPE */ | ||
669 | + nla_total_size(PORT_UUID_MAX) /* PORT_INSTANCE_UUID */ | ||
670 | + nla_total_size(PORT_UUID_MAX) /* PORT_HOST_UUID */ | ||
671 | + nla_total_size(1) /* PROT_VDP_REQUEST */ | ||
672 | + nla_total_size(2); /* PORT_VDP_RESPONSE */ | ||
673 | size_t vf_ports_size = nla_total_size(sizeof(struct nlattr)); | ||
674 | size_t vf_port_size = nla_total_size(sizeof(struct nlattr)) | ||
675 | + port_size; | ||
676 | size_t port_self_size = nla_total_size(sizeof(struct nlattr)) | ||
677 | + port_size; | ||
678 | |||
679 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent) | ||
680 | return 0; | ||
681 | if (dev_num_vf(dev->dev.parent)) | ||
682 | return port_self_size + vf_ports_size + | ||
683 | vf_port_size * dev_num_vf(dev->dev.parent); | ||
684 | else | ||
685 | return port_self_size; | ||
686 | } | ||
687 | |||
663 | static inline size_t if_nlmsg_size(const struct net_device *dev) | 688 | static inline size_t if_nlmsg_size(const struct net_device *dev) |
664 | { | 689 | { |
665 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 690 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
@@ -680,9 +705,82 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) | |||
680 | + nla_total_size(1) /* IFLA_LINKMODE */ | 705 | + nla_total_size(1) /* IFLA_LINKMODE */ |
681 | + nla_total_size(4) /* IFLA_NUM_VF */ | 706 | + nla_total_size(4) /* IFLA_NUM_VF */ |
682 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ | 707 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ |
708 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ | ||
683 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 709 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ |
684 | } | 710 | } |
685 | 711 | ||
712 | static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) | ||
713 | { | ||
714 | struct nlattr *vf_ports; | ||
715 | struct nlattr *vf_port; | ||
716 | int vf; | ||
717 | int err; | ||
718 | |||
719 | vf_ports = nla_nest_start(skb, IFLA_VF_PORTS); | ||
720 | if (!vf_ports) | ||
721 | return -EMSGSIZE; | ||
722 | |||
723 | for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) { | ||
724 | vf_port = nla_nest_start(skb, IFLA_VF_PORT); | ||
725 | if (!vf_port) { | ||
726 | nla_nest_cancel(skb, vf_ports); | ||
727 | return -EMSGSIZE; | ||
728 | } | ||
729 | NLA_PUT_U32(skb, IFLA_PORT_VF, vf); | ||
730 | err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb); | ||
731 | if (err) { | ||
732 | nla_put_failure: | ||
733 | nla_nest_cancel(skb, vf_port); | ||
734 | continue; | ||
735 | } | ||
736 | nla_nest_end(skb, vf_port); | ||
737 | } | ||
738 | |||
739 | nla_nest_end(skb, vf_ports); | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev) | ||
745 | { | ||
746 | struct nlattr *port_self; | ||
747 | int err; | ||
748 | |||
749 | port_self = nla_nest_start(skb, IFLA_PORT_SELF); | ||
750 | if (!port_self) | ||
751 | return -EMSGSIZE; | ||
752 | |||
753 | err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb); | ||
754 | if (err) { | ||
755 | nla_nest_cancel(skb, port_self); | ||
756 | return err; | ||
757 | } | ||
758 | |||
759 | nla_nest_end(skb, port_self); | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev) | ||
765 | { | ||
766 | int err; | ||
767 | |||
768 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent) | ||
769 | return 0; | ||
770 | |||
771 | err = rtnl_port_self_fill(skb, dev); | ||
772 | if (err) | ||
773 | return err; | ||
774 | |||
775 | if (dev_num_vf(dev->dev.parent)) { | ||
776 | err = rtnl_vf_ports_fill(skb, dev); | ||
777 | if (err) | ||
778 | return err; | ||
779 | } | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
686 | static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | 784 | static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, |
687 | int type, u32 pid, u32 seq, u32 change, | 785 | int type, u32 pid, u32 seq, u32 change, |
688 | unsigned int flags) | 786 | unsigned int flags) |
@@ -754,13 +852,15 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
754 | goto nla_put_failure; | 852 | goto nla_put_failure; |
755 | copy_rtnl_link_stats64(nla_data(attr), stats); | 853 | copy_rtnl_link_stats64(nla_data(attr), stats); |
756 | 854 | ||
855 | if (dev->dev.parent) | ||
856 | NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); | ||
857 | |||
757 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { | 858 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { |
758 | int i; | 859 | int i; |
759 | 860 | ||
760 | struct nlattr *vfinfo, *vf; | 861 | struct nlattr *vfinfo, *vf; |
761 | int num_vfs = dev_num_vf(dev->dev.parent); | 862 | int num_vfs = dev_num_vf(dev->dev.parent); |
762 | 863 | ||
763 | NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs); | ||
764 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); | 864 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); |
765 | if (!vfinfo) | 865 | if (!vfinfo) |
766 | goto nla_put_failure; | 866 | goto nla_put_failure; |
@@ -788,6 +888,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
788 | } | 888 | } |
789 | nla_nest_end(skb, vfinfo); | 889 | nla_nest_end(skb, vfinfo); |
790 | } | 890 | } |
891 | |||
892 | if (rtnl_port_fill(skb, dev)) | ||
893 | goto nla_put_failure; | ||
894 | |||
791 | if (dev->rtnl_link_ops) { | 895 | if (dev->rtnl_link_ops) { |
792 | if (rtnl_link_fill(skb, dev) < 0) | 896 | if (rtnl_link_fill(skb, dev) < 0) |
793 | goto nla_put_failure; | 897 | goto nla_put_failure; |
@@ -849,6 +953,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
849 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 953 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
850 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 954 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
851 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, | 955 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
956 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, | ||
957 | [IFLA_PORT_SELF] = { .type = NLA_NESTED }, | ||
852 | }; | 958 | }; |
853 | EXPORT_SYMBOL(ifla_policy); | 959 | EXPORT_SYMBOL(ifla_policy); |
854 | 960 | ||
@@ -870,6 +976,20 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { | |||
870 | .len = sizeof(struct ifla_vf_tx_rate) }, | 976 | .len = sizeof(struct ifla_vf_tx_rate) }, |
871 | }; | 977 | }; |
872 | 978 | ||
979 | static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = { | ||
980 | [IFLA_PORT_VF] = { .type = NLA_U32 }, | ||
981 | [IFLA_PORT_PROFILE] = { .type = NLA_STRING, | ||
982 | .len = PORT_PROFILE_MAX }, | ||
983 | [IFLA_PORT_VSI_TYPE] = { .type = NLA_BINARY, | ||
984 | .len = sizeof(struct ifla_port_vsi)}, | ||
985 | [IFLA_PORT_INSTANCE_UUID] = { .type = NLA_BINARY, | ||
986 | .len = PORT_UUID_MAX }, | ||
987 | [IFLA_PORT_HOST_UUID] = { .type = NLA_STRING, | ||
988 | .len = PORT_UUID_MAX }, | ||
989 | [IFLA_PORT_REQUEST] = { .type = NLA_U8, }, | ||
990 | [IFLA_PORT_RESPONSE] = { .type = NLA_U16, }, | ||
991 | }; | ||
992 | |||
873 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | 993 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) |
874 | { | 994 | { |
875 | struct net *net; | 995 | struct net *net; |
@@ -1089,6 +1209,53 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1089 | } | 1209 | } |
1090 | err = 0; | 1210 | err = 0; |
1091 | 1211 | ||
1212 | if (tb[IFLA_VF_PORTS]) { | ||
1213 | struct nlattr *port[IFLA_PORT_MAX+1]; | ||
1214 | struct nlattr *attr; | ||
1215 | int vf; | ||
1216 | int rem; | ||
1217 | |||
1218 | err = -EOPNOTSUPP; | ||
1219 | if (!ops->ndo_set_vf_port) | ||
1220 | goto errout; | ||
1221 | |||
1222 | nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) { | ||
1223 | if (nla_type(attr) != IFLA_VF_PORT) | ||
1224 | continue; | ||
1225 | err = nla_parse_nested(port, IFLA_PORT_MAX, | ||
1226 | attr, ifla_port_policy); | ||
1227 | if (err < 0) | ||
1228 | goto errout; | ||
1229 | if (!port[IFLA_PORT_VF]) { | ||
1230 | err = -EOPNOTSUPP; | ||
1231 | goto errout; | ||
1232 | } | ||
1233 | vf = nla_get_u32(port[IFLA_PORT_VF]); | ||
1234 | err = ops->ndo_set_vf_port(dev, vf, port); | ||
1235 | if (err < 0) | ||
1236 | goto errout; | ||
1237 | modified = 1; | ||
1238 | } | ||
1239 | } | ||
1240 | err = 0; | ||
1241 | |||
1242 | if (tb[IFLA_PORT_SELF]) { | ||
1243 | struct nlattr *port[IFLA_PORT_MAX+1]; | ||
1244 | |||
1245 | err = nla_parse_nested(port, IFLA_PORT_MAX, | ||
1246 | tb[IFLA_PORT_SELF], ifla_port_policy); | ||
1247 | if (err < 0) | ||
1248 | goto errout; | ||
1249 | |||
1250 | err = -EOPNOTSUPP; | ||
1251 | if (ops->ndo_set_vf_port) | ||
1252 | err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port); | ||
1253 | if (err < 0) | ||
1254 | goto errout; | ||
1255 | modified = 1; | ||
1256 | } | ||
1257 | err = 0; | ||
1258 | |||
1092 | errout: | 1259 | errout: |
1093 | if (err < 0 && modified && net_ratelimit()) | 1260 | if (err < 0 && modified && net_ratelimit()) |
1094 | printk(KERN_WARNING "A link change request failed with " | 1261 | printk(KERN_WARNING "A link change request failed with " |