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 | ||
