|
@@ -843,7 +843,10 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev,
|
|
size += nla_total_size(num_vfs * sizeof(struct nlattr));
|
|
size += nla_total_size(num_vfs * sizeof(struct nlattr));
|
|
size += num_vfs *
|
|
size += num_vfs *
|
|
(nla_total_size(sizeof(struct ifla_vf_mac)) +
|
|
(nla_total_size(sizeof(struct ifla_vf_mac)) +
|
|
- nla_total_size(sizeof(struct ifla_vf_vlan)) +
|
|
|
|
|
|
+ nla_total_size(MAX_VLAN_LIST_LEN *
|
|
|
|
+ sizeof(struct nlattr)) +
|
|
|
|
+ nla_total_size(MAX_VLAN_LIST_LEN *
|
|
|
|
+ sizeof(struct ifla_vf_vlan_info)) +
|
|
nla_total_size(sizeof(struct ifla_vf_spoofchk)) +
|
|
nla_total_size(sizeof(struct ifla_vf_spoofchk)) +
|
|
nla_total_size(sizeof(struct ifla_vf_rate)) +
|
|
nla_total_size(sizeof(struct ifla_vf_rate)) +
|
|
nla_total_size(sizeof(struct ifla_vf_link_state)) +
|
|
nla_total_size(sizeof(struct ifla_vf_link_state)) +
|
|
@@ -1111,14 +1114,15 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
|
|
struct nlattr *vfinfo)
|
|
struct nlattr *vfinfo)
|
|
{
|
|
{
|
|
struct ifla_vf_rss_query_en vf_rss_query_en;
|
|
struct ifla_vf_rss_query_en vf_rss_query_en;
|
|
|
|
+ struct nlattr *vf, *vfstats, *vfvlanlist;
|
|
struct ifla_vf_link_state vf_linkstate;
|
|
struct ifla_vf_link_state vf_linkstate;
|
|
|
|
+ struct ifla_vf_vlan_info vf_vlan_info;
|
|
struct ifla_vf_spoofchk vf_spoofchk;
|
|
struct ifla_vf_spoofchk vf_spoofchk;
|
|
struct ifla_vf_tx_rate vf_tx_rate;
|
|
struct ifla_vf_tx_rate vf_tx_rate;
|
|
struct ifla_vf_stats vf_stats;
|
|
struct ifla_vf_stats vf_stats;
|
|
struct ifla_vf_trust vf_trust;
|
|
struct ifla_vf_trust vf_trust;
|
|
struct ifla_vf_vlan vf_vlan;
|
|
struct ifla_vf_vlan vf_vlan;
|
|
struct ifla_vf_rate vf_rate;
|
|
struct ifla_vf_rate vf_rate;
|
|
- struct nlattr *vf, *vfstats;
|
|
|
|
struct ifla_vf_mac vf_mac;
|
|
struct ifla_vf_mac vf_mac;
|
|
struct ifla_vf_info ivi;
|
|
struct ifla_vf_info ivi;
|
|
|
|
|
|
@@ -1135,11 +1139,14 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
|
|
* IFLA_VF_LINK_STATE_AUTO which equals zero
|
|
* IFLA_VF_LINK_STATE_AUTO which equals zero
|
|
*/
|
|
*/
|
|
ivi.linkstate = 0;
|
|
ivi.linkstate = 0;
|
|
|
|
+ /* VLAN Protocol by default is 802.1Q */
|
|
|
|
+ ivi.vlan_proto = htons(ETH_P_8021Q);
|
|
if (dev->netdev_ops->ndo_get_vf_config(dev, vfs_num, &ivi))
|
|
if (dev->netdev_ops->ndo_get_vf_config(dev, vfs_num, &ivi))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
vf_mac.vf =
|
|
vf_mac.vf =
|
|
vf_vlan.vf =
|
|
vf_vlan.vf =
|
|
|
|
+ vf_vlan_info.vf =
|
|
vf_rate.vf =
|
|
vf_rate.vf =
|
|
vf_tx_rate.vf =
|
|
vf_tx_rate.vf =
|
|
vf_spoofchk.vf =
|
|
vf_spoofchk.vf =
|
|
@@ -1150,6 +1157,9 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
|
|
memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
|
|
memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
|
|
vf_vlan.vlan = ivi.vlan;
|
|
vf_vlan.vlan = ivi.vlan;
|
|
vf_vlan.qos = ivi.qos;
|
|
vf_vlan.qos = ivi.qos;
|
|
|
|
+ vf_vlan_info.vlan = ivi.vlan;
|
|
|
|
+ vf_vlan_info.qos = ivi.qos;
|
|
|
|
+ vf_vlan_info.vlan_proto = ivi.vlan_proto;
|
|
vf_tx_rate.rate = ivi.max_tx_rate;
|
|
vf_tx_rate.rate = ivi.max_tx_rate;
|
|
vf_rate.min_tx_rate = ivi.min_tx_rate;
|
|
vf_rate.min_tx_rate = ivi.min_tx_rate;
|
|
vf_rate.max_tx_rate = ivi.max_tx_rate;
|
|
vf_rate.max_tx_rate = ivi.max_tx_rate;
|
|
@@ -1158,10 +1168,8 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
|
|
vf_rss_query_en.setting = ivi.rss_query_en;
|
|
vf_rss_query_en.setting = ivi.rss_query_en;
|
|
vf_trust.setting = ivi.trusted;
|
|
vf_trust.setting = ivi.trusted;
|
|
vf = nla_nest_start(skb, IFLA_VF_INFO);
|
|
vf = nla_nest_start(skb, IFLA_VF_INFO);
|
|
- if (!vf) {
|
|
|
|
- nla_nest_cancel(skb, vfinfo);
|
|
|
|
- return -EMSGSIZE;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!vf)
|
|
|
|
+ goto nla_put_vfinfo_failure;
|
|
if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
|
|
if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
|
|
nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
|
|
nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
|
|
nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
|
|
nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
|
|
@@ -1177,17 +1185,23 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
|
|
&vf_rss_query_en) ||
|
|
&vf_rss_query_en) ||
|
|
nla_put(skb, IFLA_VF_TRUST,
|
|
nla_put(skb, IFLA_VF_TRUST,
|
|
sizeof(vf_trust), &vf_trust))
|
|
sizeof(vf_trust), &vf_trust))
|
|
- return -EMSGSIZE;
|
|
|
|
|
|
+ goto nla_put_vf_failure;
|
|
|
|
+ vfvlanlist = nla_nest_start(skb, IFLA_VF_VLAN_LIST);
|
|
|
|
+ if (!vfvlanlist)
|
|
|
|
+ goto nla_put_vf_failure;
|
|
|
|
+ if (nla_put(skb, IFLA_VF_VLAN_INFO, sizeof(vf_vlan_info),
|
|
|
|
+ &vf_vlan_info)) {
|
|
|
|
+ nla_nest_cancel(skb, vfvlanlist);
|
|
|
|
+ goto nla_put_vf_failure;
|
|
|
|
+ }
|
|
|
|
+ nla_nest_end(skb, vfvlanlist);
|
|
memset(&vf_stats, 0, sizeof(vf_stats));
|
|
memset(&vf_stats, 0, sizeof(vf_stats));
|
|
if (dev->netdev_ops->ndo_get_vf_stats)
|
|
if (dev->netdev_ops->ndo_get_vf_stats)
|
|
dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num,
|
|
dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num,
|
|
&vf_stats);
|
|
&vf_stats);
|
|
vfstats = nla_nest_start(skb, IFLA_VF_STATS);
|
|
vfstats = nla_nest_start(skb, IFLA_VF_STATS);
|
|
- if (!vfstats) {
|
|
|
|
- nla_nest_cancel(skb, vf);
|
|
|
|
- nla_nest_cancel(skb, vfinfo);
|
|
|
|
- return -EMSGSIZE;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!vfstats)
|
|
|
|
+ goto nla_put_vf_failure;
|
|
if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS,
|
|
if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS,
|
|
vf_stats.rx_packets, IFLA_VF_STATS_PAD) ||
|
|
vf_stats.rx_packets, IFLA_VF_STATS_PAD) ||
|
|
nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS,
|
|
nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS,
|
|
@@ -1199,11 +1213,19 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
|
|
nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST,
|
|
nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST,
|
|
vf_stats.broadcast, IFLA_VF_STATS_PAD) ||
|
|
vf_stats.broadcast, IFLA_VF_STATS_PAD) ||
|
|
nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST,
|
|
nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST,
|
|
- vf_stats.multicast, IFLA_VF_STATS_PAD))
|
|
|
|
- return -EMSGSIZE;
|
|
|
|
|
|
+ vf_stats.multicast, IFLA_VF_STATS_PAD)) {
|
|
|
|
+ nla_nest_cancel(skb, vfstats);
|
|
|
|
+ goto nla_put_vf_failure;
|
|
|
|
+ }
|
|
nla_nest_end(skb, vfstats);
|
|
nla_nest_end(skb, vfstats);
|
|
nla_nest_end(skb, vf);
|
|
nla_nest_end(skb, vf);
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+nla_put_vf_failure:
|
|
|
|
+ nla_nest_cancel(skb, vf);
|
|
|
|
+nla_put_vfinfo_failure:
|
|
|
|
+ nla_nest_cancel(skb, vfinfo);
|
|
|
|
+ return -EMSGSIZE;
|
|
}
|
|
}
|
|
|
|
|
|
static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
|
|
static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
|
|
@@ -1448,6 +1470,7 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
|
|
static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
|
|
static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
|
|
[IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) },
|
|
[IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) },
|
|
[IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) },
|
|
[IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) },
|
|
|
|
+ [IFLA_VF_VLAN_LIST] = { .type = NLA_NESTED },
|
|
[IFLA_VF_TX_RATE] = { .len = sizeof(struct ifla_vf_tx_rate) },
|
|
[IFLA_VF_TX_RATE] = { .len = sizeof(struct ifla_vf_tx_rate) },
|
|
[IFLA_VF_SPOOFCHK] = { .len = sizeof(struct ifla_vf_spoofchk) },
|
|
[IFLA_VF_SPOOFCHK] = { .len = sizeof(struct ifla_vf_spoofchk) },
|
|
[IFLA_VF_RATE] = { .len = sizeof(struct ifla_vf_rate) },
|
|
[IFLA_VF_RATE] = { .len = sizeof(struct ifla_vf_rate) },
|
|
@@ -1704,7 +1727,34 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr **tb)
|
|
err = -EOPNOTSUPP;
|
|
err = -EOPNOTSUPP;
|
|
if (ops->ndo_set_vf_vlan)
|
|
if (ops->ndo_set_vf_vlan)
|
|
err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan,
|
|
err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan,
|
|
- ivv->qos);
|
|
|
|
|
|
+ ivv->qos,
|
|
|
|
+ htons(ETH_P_8021Q));
|
|
|
|
+ if (err < 0)
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tb[IFLA_VF_VLAN_LIST]) {
|
|
|
|
+ struct ifla_vf_vlan_info *ivvl[MAX_VLAN_LIST_LEN];
|
|
|
|
+ struct nlattr *attr;
|
|
|
|
+ int rem, len = 0;
|
|
|
|
+
|
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
|
+ if (!ops->ndo_set_vf_vlan)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ nla_for_each_nested(attr, tb[IFLA_VF_VLAN_LIST], rem) {
|
|
|
|
+ if (nla_type(attr) != IFLA_VF_VLAN_INFO ||
|
|
|
|
+ nla_len(attr) < NLA_HDRLEN) {
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ if (len >= MAX_VLAN_LIST_LEN)
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+ ivvl[len] = nla_data(attr);
|
|
|
|
+
|
|
|
|
+ len++;
|
|
|
|
+ }
|
|
|
|
+ err = ops->ndo_set_vf_vlan(dev, ivvl[0]->vf, ivvl[0]->vlan,
|
|
|
|
+ ivvl[0]->qos, ivvl[0]->vlan_proto);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|