diff options
author | Chris Wright <chrisw@sous-sol.org> | 2010-05-16 04:05:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-16 04:05:45 -0400 |
commit | c02db8c6290bb992442fec1407643c94cc414375 (patch) | |
tree | 05ec7bdd7efc005cd9e3905e0d6f6469bf08668b | |
parent | 55fa0cfd7c3ac2ae34cac7dca2e3fbcfe661e6c3 (diff) |
rtnetlink: make SR-IOV VF interface symmetric
Now we have a set of nested attributes:
IFLA_VFINFO_LIST (NESTED)
IFLA_VF_INFO (NESTED)
IFLA_VF_MAC
IFLA_VF_VLAN
IFLA_VF_TX_RATE
This allows a single set to operate on multiple attributes if desired.
Among other things, it means a dump can be replayed to set state.
The current interface has yet to be released, so this seems like
something to consider for 2.6.34.
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/if_link.h | 23 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 159 |
2 files changed, 129 insertions, 53 deletions
diff --git a/include/linux/if_link.h b/include/linux/if_link.h index c9bf92cd7653..d94963b379d9 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h | |||
@@ -79,10 +79,7 @@ enum { | |||
79 | IFLA_NET_NS_PID, | 79 | IFLA_NET_NS_PID, |
80 | IFLA_IFALIAS, | 80 | IFLA_IFALIAS, |
81 | IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ | 81 | IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ |
82 | IFLA_VF_MAC, /* Hardware queue specific attributes */ | 82 | IFLA_VFINFO_LIST, |
83 | IFLA_VF_VLAN, | ||
84 | IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */ | ||
85 | IFLA_VFINFO, | ||
86 | __IFLA_MAX | 83 | __IFLA_MAX |
87 | }; | 84 | }; |
88 | 85 | ||
@@ -203,6 +200,24 @@ enum macvlan_mode { | |||
203 | 200 | ||
204 | /* SR-IOV virtual function managment section */ | 201 | /* SR-IOV virtual function managment section */ |
205 | 202 | ||
203 | enum { | ||
204 | IFLA_VF_INFO_UNSPEC, | ||
205 | IFLA_VF_INFO, | ||
206 | __IFLA_VF_INFO_MAX, | ||
207 | }; | ||
208 | |||
209 | #define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1) | ||
210 | |||
211 | enum { | ||
212 | IFLA_VF_UNSPEC, | ||
213 | IFLA_VF_MAC, /* Hardware queue specific attributes */ | ||
214 | IFLA_VF_VLAN, | ||
215 | IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */ | ||
216 | __IFLA_VF_MAX, | ||
217 | }; | ||
218 | |||
219 | #define IFLA_VF_MAX (__IFLA_VF_MAX - 1) | ||
220 | |||
206 | struct ifla_vf_mac { | 221 | struct ifla_vf_mac { |
207 | __u32 vf; | 222 | __u32 vf; |
208 | __u8 mac[32]; /* MAX_ADDR_LEN */ | 223 | __u8 mac[32]; /* MAX_ADDR_LEN */ |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index fe776c9ddeca..31e85d327aa2 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -602,12 +602,19 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | |||
602 | a->tx_compressed = b->tx_compressed; | 602 | a->tx_compressed = b->tx_compressed; |
603 | }; | 603 | }; |
604 | 604 | ||
605 | /* All VF info */ | ||
605 | static inline int rtnl_vfinfo_size(const struct net_device *dev) | 606 | static inline int rtnl_vfinfo_size(const struct net_device *dev) |
606 | { | 607 | { |
607 | if (dev->dev.parent && dev_is_pci(dev->dev.parent)) | 608 | if (dev->dev.parent && dev_is_pci(dev->dev.parent)) { |
608 | return dev_num_vf(dev->dev.parent) * | 609 | |
609 | sizeof(struct ifla_vf_info); | 610 | int num_vfs = dev_num_vf(dev->dev.parent); |
610 | else | 611 | size_t size = nlmsg_total_size(sizeof(struct nlattr)); |
612 | size += nlmsg_total_size(num_vfs * sizeof(struct nlattr)); | ||
613 | size += num_vfs * (sizeof(struct ifla_vf_mac) + | ||
614 | sizeof(struct ifla_vf_vlan) + | ||
615 | sizeof(struct ifla_vf_tx_rate)); | ||
616 | return size; | ||
617 | } else | ||
611 | return 0; | 618 | return 0; |
612 | } | 619 | } |
613 | 620 | ||
@@ -629,7 +636,7 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) | |||
629 | + nla_total_size(1) /* IFLA_OPERSTATE */ | 636 | + nla_total_size(1) /* IFLA_OPERSTATE */ |
630 | + nla_total_size(1) /* IFLA_LINKMODE */ | 637 | + nla_total_size(1) /* IFLA_LINKMODE */ |
631 | + nla_total_size(4) /* IFLA_NUM_VF */ | 638 | + nla_total_size(4) /* IFLA_NUM_VF */ |
632 | + nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */ | 639 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ |
633 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 640 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ |
634 | } | 641 | } |
635 | 642 | ||
@@ -700,14 +707,37 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
700 | 707 | ||
701 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { | 708 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { |
702 | int i; | 709 | int i; |
703 | struct ifla_vf_info ivi; | ||
704 | 710 | ||
705 | NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); | 711 | struct nlattr *vfinfo, *vf; |
706 | for (i = 0; i < dev_num_vf(dev->dev.parent); i++) { | 712 | int num_vfs = dev_num_vf(dev->dev.parent); |
713 | |||
714 | NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs); | ||
715 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); | ||
716 | if (!vfinfo) | ||
717 | goto nla_put_failure; | ||
718 | for (i = 0; i < num_vfs; i++) { | ||
719 | struct ifla_vf_info ivi; | ||
720 | struct ifla_vf_mac vf_mac; | ||
721 | struct ifla_vf_vlan vf_vlan; | ||
722 | struct ifla_vf_tx_rate vf_tx_rate; | ||
707 | if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) | 723 | if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) |
708 | break; | 724 | break; |
709 | NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi); | 725 | vf_mac.vf = vf_vlan.vf = vf_tx_rate.vf = ivi.vf; |
726 | memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); | ||
727 | vf_vlan.vlan = ivi.vlan; | ||
728 | vf_vlan.qos = ivi.qos; | ||
729 | vf_tx_rate.rate = ivi.tx_rate; | ||
730 | vf = nla_nest_start(skb, IFLA_VF_INFO); | ||
731 | if (!vf) { | ||
732 | nla_nest_cancel(skb, vfinfo); | ||
733 | goto nla_put_failure; | ||
734 | } | ||
735 | NLA_PUT(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac); | ||
736 | NLA_PUT(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan); | ||
737 | NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate), &vf_tx_rate); | ||
738 | nla_nest_end(skb, vf); | ||
710 | } | 739 | } |
740 | nla_nest_end(skb, vfinfo); | ||
711 | } | 741 | } |
712 | if (dev->rtnl_link_ops) { | 742 | if (dev->rtnl_link_ops) { |
713 | if (rtnl_link_fill(skb, dev) < 0) | 743 | if (rtnl_link_fill(skb, dev) < 0) |
@@ -769,12 +799,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
769 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | 799 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, |
770 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 800 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
771 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 801 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
772 | [IFLA_VF_MAC] = { .type = NLA_BINARY, | 802 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
773 | .len = sizeof(struct ifla_vf_mac) }, | ||
774 | [IFLA_VF_VLAN] = { .type = NLA_BINARY, | ||
775 | .len = sizeof(struct ifla_vf_vlan) }, | ||
776 | [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, | ||
777 | .len = sizeof(struct ifla_vf_tx_rate) }, | ||
778 | }; | 803 | }; |
779 | EXPORT_SYMBOL(ifla_policy); | 804 | EXPORT_SYMBOL(ifla_policy); |
780 | 805 | ||
@@ -783,6 +808,19 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { | |||
783 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, | 808 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, |
784 | }; | 809 | }; |
785 | 810 | ||
811 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { | ||
812 | [IFLA_VF_INFO] = { .type = NLA_NESTED }, | ||
813 | }; | ||
814 | |||
815 | static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { | ||
816 | [IFLA_VF_MAC] = { .type = NLA_BINARY, | ||
817 | .len = sizeof(struct ifla_vf_mac) }, | ||
818 | [IFLA_VF_VLAN] = { .type = NLA_BINARY, | ||
819 | .len = sizeof(struct ifla_vf_vlan) }, | ||
820 | [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, | ||
821 | .len = sizeof(struct ifla_vf_tx_rate) }, | ||
822 | }; | ||
823 | |||
786 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | 824 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) |
787 | { | 825 | { |
788 | struct net *net; | 826 | struct net *net; |
@@ -812,6 +850,52 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | |||
812 | return 0; | 850 | return 0; |
813 | } | 851 | } |
814 | 852 | ||
853 | static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) | ||
854 | { | ||
855 | int rem, err = -EINVAL; | ||
856 | struct nlattr *vf; | ||
857 | const struct net_device_ops *ops = dev->netdev_ops; | ||
858 | |||
859 | nla_for_each_nested(vf, attr, rem) { | ||
860 | switch (nla_type(vf)) { | ||
861 | case IFLA_VF_MAC: { | ||
862 | struct ifla_vf_mac *ivm; | ||
863 | ivm = nla_data(vf); | ||
864 | err = -EOPNOTSUPP; | ||
865 | if (ops->ndo_set_vf_mac) | ||
866 | err = ops->ndo_set_vf_mac(dev, ivm->vf, | ||
867 | ivm->mac); | ||
868 | break; | ||
869 | } | ||
870 | case IFLA_VF_VLAN: { | ||
871 | struct ifla_vf_vlan *ivv; | ||
872 | ivv = nla_data(vf); | ||
873 | err = -EOPNOTSUPP; | ||
874 | if (ops->ndo_set_vf_vlan) | ||
875 | err = ops->ndo_set_vf_vlan(dev, ivv->vf, | ||
876 | ivv->vlan, | ||
877 | ivv->qos); | ||
878 | break; | ||
879 | } | ||
880 | case IFLA_VF_TX_RATE: { | ||
881 | struct ifla_vf_tx_rate *ivt; | ||
882 | ivt = nla_data(vf); | ||
883 | err = -EOPNOTSUPP; | ||
884 | if (ops->ndo_set_vf_tx_rate) | ||
885 | err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, | ||
886 | ivt->rate); | ||
887 | break; | ||
888 | } | ||
889 | default: | ||
890 | err = -EINVAL; | ||
891 | break; | ||
892 | } | ||
893 | if (err) | ||
894 | break; | ||
895 | } | ||
896 | return err; | ||
897 | } | ||
898 | |||
815 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | 899 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, |
816 | struct nlattr **tb, char *ifname, int modified) | 900 | struct nlattr **tb, char *ifname, int modified) |
817 | { | 901 | { |
@@ -942,40 +1026,17 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
942 | write_unlock_bh(&dev_base_lock); | 1026 | write_unlock_bh(&dev_base_lock); |
943 | } | 1027 | } |
944 | 1028 | ||
945 | if (tb[IFLA_VF_MAC]) { | 1029 | if (tb[IFLA_VFINFO_LIST]) { |
946 | struct ifla_vf_mac *ivm; | 1030 | struct nlattr *attr; |
947 | ivm = nla_data(tb[IFLA_VF_MAC]); | 1031 | int rem; |
948 | err = -EOPNOTSUPP; | 1032 | nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { |
949 | if (ops->ndo_set_vf_mac) | 1033 | if (nla_type(attr) != IFLA_VF_INFO) |
950 | err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac); | 1034 | goto errout; |
951 | if (err < 0) | 1035 | err = do_setvfinfo(dev, attr); |
952 | goto errout; | 1036 | if (err < 0) |
953 | modified = 1; | 1037 | goto errout; |
954 | } | 1038 | modified = 1; |
955 | 1039 | } | |
956 | if (tb[IFLA_VF_VLAN]) { | ||
957 | struct ifla_vf_vlan *ivv; | ||
958 | ivv = nla_data(tb[IFLA_VF_VLAN]); | ||
959 | err = -EOPNOTSUPP; | ||
960 | if (ops->ndo_set_vf_vlan) | ||
961 | err = ops->ndo_set_vf_vlan(dev, ivv->vf, | ||
962 | ivv->vlan, | ||
963 | ivv->qos); | ||
964 | if (err < 0) | ||
965 | goto errout; | ||
966 | modified = 1; | ||
967 | } | ||
968 | err = 0; | ||
969 | |||
970 | if (tb[IFLA_VF_TX_RATE]) { | ||
971 | struct ifla_vf_tx_rate *ivt; | ||
972 | ivt = nla_data(tb[IFLA_VF_TX_RATE]); | ||
973 | err = -EOPNOTSUPP; | ||
974 | if (ops->ndo_set_vf_tx_rate) | ||
975 | err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate); | ||
976 | if (err < 0) | ||
977 | goto errout; | ||
978 | modified = 1; | ||
979 | } | 1040 | } |
980 | err = 0; | 1041 | err = 0; |
981 | 1042 | ||