diff options
author | David S. Miller <davem@davemloft.net> | 2010-05-17 01:26:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-17 01:26:58 -0400 |
commit | 6811d58fc148c393f80a9f5a9db49d7e75cdc546 (patch) | |
tree | c25d5b0e49ec848943d35f819e748d157ccb492e /net/core | |
parent | c4949f074332a64baeb2ead6ab9319ca37642f96 (diff) | |
parent | c02db8c6290bb992442fec1407643c94cc414375 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
include/linux/if_link.h
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/rtnetlink.c | 159 |
1 files changed, 110 insertions, 49 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 23a71cb21273..66db1201da9b 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -644,12 +644,19 @@ static void copy_rtnl_link_stats64(void *v, const struct net_device_stats *b) | |||
644 | memcpy(v, &a, sizeof(a)); | 644 | memcpy(v, &a, sizeof(a)); |
645 | } | 645 | } |
646 | 646 | ||
647 | /* All VF info */ | ||
647 | static inline int rtnl_vfinfo_size(const struct net_device *dev) | 648 | static inline int rtnl_vfinfo_size(const struct net_device *dev) |
648 | { | 649 | { |
649 | if (dev->dev.parent && dev_is_pci(dev->dev.parent)) | 650 | if (dev->dev.parent && dev_is_pci(dev->dev.parent)) { |
650 | return dev_num_vf(dev->dev.parent) * | 651 | |
651 | sizeof(struct ifla_vf_info); | 652 | int num_vfs = dev_num_vf(dev->dev.parent); |
652 | else | 653 | size_t size = nlmsg_total_size(sizeof(struct nlattr)); |
654 | size += nlmsg_total_size(num_vfs * sizeof(struct nlattr)); | ||
655 | size += num_vfs * (sizeof(struct ifla_vf_mac) + | ||
656 | sizeof(struct ifla_vf_vlan) + | ||
657 | sizeof(struct ifla_vf_tx_rate)); | ||
658 | return size; | ||
659 | } else | ||
653 | return 0; | 660 | return 0; |
654 | } | 661 | } |
655 | 662 | ||
@@ -672,7 +679,7 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) | |||
672 | + nla_total_size(1) /* IFLA_OPERSTATE */ | 679 | + nla_total_size(1) /* IFLA_OPERSTATE */ |
673 | + nla_total_size(1) /* IFLA_LINKMODE */ | 680 | + nla_total_size(1) /* IFLA_LINKMODE */ |
674 | + nla_total_size(4) /* IFLA_NUM_VF */ | 681 | + nla_total_size(4) /* IFLA_NUM_VF */ |
675 | + nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */ | 682 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ |
676 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 683 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ |
677 | } | 684 | } |
678 | 685 | ||
@@ -749,14 +756,37 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
749 | 756 | ||
750 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { | 757 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { |
751 | int i; | 758 | int i; |
752 | struct ifla_vf_info ivi; | ||
753 | 759 | ||
754 | NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); | 760 | struct nlattr *vfinfo, *vf; |
755 | for (i = 0; i < dev_num_vf(dev->dev.parent); i++) { | 761 | int num_vfs = dev_num_vf(dev->dev.parent); |
762 | |||
763 | NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs); | ||
764 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); | ||
765 | if (!vfinfo) | ||
766 | goto nla_put_failure; | ||
767 | for (i = 0; i < num_vfs; i++) { | ||
768 | struct ifla_vf_info ivi; | ||
769 | struct ifla_vf_mac vf_mac; | ||
770 | struct ifla_vf_vlan vf_vlan; | ||
771 | struct ifla_vf_tx_rate vf_tx_rate; | ||
756 | if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) | 772 | if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) |
757 | break; | 773 | break; |
758 | NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi); | 774 | vf_mac.vf = vf_vlan.vf = vf_tx_rate.vf = ivi.vf; |
775 | memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); | ||
776 | vf_vlan.vlan = ivi.vlan; | ||
777 | vf_vlan.qos = ivi.qos; | ||
778 | vf_tx_rate.rate = ivi.tx_rate; | ||
779 | vf = nla_nest_start(skb, IFLA_VF_INFO); | ||
780 | if (!vf) { | ||
781 | nla_nest_cancel(skb, vfinfo); | ||
782 | goto nla_put_failure; | ||
783 | } | ||
784 | NLA_PUT(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac); | ||
785 | NLA_PUT(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan); | ||
786 | NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate), &vf_tx_rate); | ||
787 | nla_nest_end(skb, vf); | ||
759 | } | 788 | } |
789 | nla_nest_end(skb, vfinfo); | ||
760 | } | 790 | } |
761 | if (dev->rtnl_link_ops) { | 791 | if (dev->rtnl_link_ops) { |
762 | if (rtnl_link_fill(skb, dev) < 0) | 792 | if (rtnl_link_fill(skb, dev) < 0) |
@@ -818,12 +848,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
818 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | 848 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, |
819 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 849 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
820 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 850 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
821 | [IFLA_VF_MAC] = { .type = NLA_BINARY, | 851 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
822 | .len = sizeof(struct ifla_vf_mac) }, | ||
823 | [IFLA_VF_VLAN] = { .type = NLA_BINARY, | ||
824 | .len = sizeof(struct ifla_vf_vlan) }, | ||
825 | [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, | ||
826 | .len = sizeof(struct ifla_vf_tx_rate) }, | ||
827 | }; | 852 | }; |
828 | EXPORT_SYMBOL(ifla_policy); | 853 | EXPORT_SYMBOL(ifla_policy); |
829 | 854 | ||
@@ -832,6 +857,19 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { | |||
832 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, | 857 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, |
833 | }; | 858 | }; |
834 | 859 | ||
860 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { | ||
861 | [IFLA_VF_INFO] = { .type = NLA_NESTED }, | ||
862 | }; | ||
863 | |||
864 | static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { | ||
865 | [IFLA_VF_MAC] = { .type = NLA_BINARY, | ||
866 | .len = sizeof(struct ifla_vf_mac) }, | ||
867 | [IFLA_VF_VLAN] = { .type = NLA_BINARY, | ||
868 | .len = sizeof(struct ifla_vf_vlan) }, | ||
869 | [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, | ||
870 | .len = sizeof(struct ifla_vf_tx_rate) }, | ||
871 | }; | ||
872 | |||
835 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | 873 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) |
836 | { | 874 | { |
837 | struct net *net; | 875 | struct net *net; |
@@ -861,6 +899,52 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | |||
861 | return 0; | 899 | return 0; |
862 | } | 900 | } |
863 | 901 | ||
902 | static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) | ||
903 | { | ||
904 | int rem, err = -EINVAL; | ||
905 | struct nlattr *vf; | ||
906 | const struct net_device_ops *ops = dev->netdev_ops; | ||
907 | |||
908 | nla_for_each_nested(vf, attr, rem) { | ||
909 | switch (nla_type(vf)) { | ||
910 | case IFLA_VF_MAC: { | ||
911 | struct ifla_vf_mac *ivm; | ||
912 | ivm = nla_data(vf); | ||
913 | err = -EOPNOTSUPP; | ||
914 | if (ops->ndo_set_vf_mac) | ||
915 | err = ops->ndo_set_vf_mac(dev, ivm->vf, | ||
916 | ivm->mac); | ||
917 | break; | ||
918 | } | ||
919 | case IFLA_VF_VLAN: { | ||
920 | struct ifla_vf_vlan *ivv; | ||
921 | ivv = nla_data(vf); | ||
922 | err = -EOPNOTSUPP; | ||
923 | if (ops->ndo_set_vf_vlan) | ||
924 | err = ops->ndo_set_vf_vlan(dev, ivv->vf, | ||
925 | ivv->vlan, | ||
926 | ivv->qos); | ||
927 | break; | ||
928 | } | ||
929 | case IFLA_VF_TX_RATE: { | ||
930 | struct ifla_vf_tx_rate *ivt; | ||
931 | ivt = nla_data(vf); | ||
932 | err = -EOPNOTSUPP; | ||
933 | if (ops->ndo_set_vf_tx_rate) | ||
934 | err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, | ||
935 | ivt->rate); | ||
936 | break; | ||
937 | } | ||
938 | default: | ||
939 | err = -EINVAL; | ||
940 | break; | ||
941 | } | ||
942 | if (err) | ||
943 | break; | ||
944 | } | ||
945 | return err; | ||
946 | } | ||
947 | |||
864 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | 948 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, |
865 | struct nlattr **tb, char *ifname, int modified) | 949 | struct nlattr **tb, char *ifname, int modified) |
866 | { | 950 | { |
@@ -991,40 +1075,17 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
991 | write_unlock_bh(&dev_base_lock); | 1075 | write_unlock_bh(&dev_base_lock); |
992 | } | 1076 | } |
993 | 1077 | ||
994 | if (tb[IFLA_VF_MAC]) { | 1078 | if (tb[IFLA_VFINFO_LIST]) { |
995 | struct ifla_vf_mac *ivm; | 1079 | struct nlattr *attr; |
996 | ivm = nla_data(tb[IFLA_VF_MAC]); | 1080 | int rem; |
997 | err = -EOPNOTSUPP; | 1081 | nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { |
998 | if (ops->ndo_set_vf_mac) | 1082 | if (nla_type(attr) != IFLA_VF_INFO) |
999 | err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac); | 1083 | goto errout; |
1000 | if (err < 0) | 1084 | err = do_setvfinfo(dev, attr); |
1001 | goto errout; | 1085 | if (err < 0) |
1002 | modified = 1; | 1086 | goto errout; |
1003 | } | 1087 | modified = 1; |
1004 | 1088 | } | |
1005 | if (tb[IFLA_VF_VLAN]) { | ||
1006 | struct ifla_vf_vlan *ivv; | ||
1007 | ivv = nla_data(tb[IFLA_VF_VLAN]); | ||
1008 | err = -EOPNOTSUPP; | ||
1009 | if (ops->ndo_set_vf_vlan) | ||
1010 | err = ops->ndo_set_vf_vlan(dev, ivv->vf, | ||
1011 | ivv->vlan, | ||
1012 | ivv->qos); | ||
1013 | if (err < 0) | ||
1014 | goto errout; | ||
1015 | modified = 1; | ||
1016 | } | ||
1017 | err = 0; | ||
1018 | |||
1019 | if (tb[IFLA_VF_TX_RATE]) { | ||
1020 | struct ifla_vf_tx_rate *ivt; | ||
1021 | ivt = nla_data(tb[IFLA_VF_TX_RATE]); | ||
1022 | err = -EOPNOTSUPP; | ||
1023 | if (ops->ndo_set_vf_tx_rate) | ||
1024 | err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate); | ||
1025 | if (err < 0) | ||
1026 | goto errout; | ||
1027 | modified = 1; | ||
1028 | } | 1089 | } |
1029 | err = 0; | 1090 | err = 0; |
1030 | 1091 | ||