[RFC PATCH] rtnetlink: Add filter for VF info dump requests
From: Greg Rose <hidden>
Date: 2012-02-07 22:51:52
Add a 256 bit filter to allow the user to filter which VFs' info will get displayed during the dump info request. This is to fix a bug in which a an info dump request on a device with many VFs would overflow the recvmsg buffer which is allocated to max(8192, PAGE_SIZE). A complimentary patch to the iproute2 ip tool will allow the user to set/clear individual VF filters. Signed-off-by: Greg Rose <redacted> --- include/linux/if_link.h | 6 ++++++ include/linux/netdevice.h | 2 ++ net/core/rtnetlink.c | 40 +++++++++++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index c52d4b5..052c240 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h@@ -280,6 +280,7 @@ enum { IFLA_VF_VLAN, IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */ IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */ + IFLA_VF_INFOFILTER, /* Filter vfinfo on dumps */ __IFLA_VF_MAX, };
@@ -305,6 +306,11 @@ struct ifla_vf_spoofchk { __u32 vf; __u32 setting; }; + +struct ifla_vf_infofilter { + __u32 vf; + __u32 filter; +}; #ifdef __KERNEL__ /* We don't want this structure exposed to user space */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0eac07c..dd30b5d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h@@ -1298,6 +1298,8 @@ struct net_device { /* group the device belongs to */ int group; + /* VF info display filter - Number of VFs max is 256 */ + unsigned long show_vfinfo_filter[BITS_TO_LONGS(256)]; }; #define to_net_dev(d) container_of(d, struct net_device, dev)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 39aa20b..4fd78dd 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c@@ -727,9 +727,13 @@ static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b) static inline int rtnl_vfinfo_size(const struct net_device *dev) { if (dev->dev.parent && dev_is_pci(dev->dev.parent)) { - - int num_vfs = dev_num_vf(dev->dev.parent); + int j; + int num_vfs = 0; size_t size = nla_total_size(sizeof(struct nlattr)); + for (j = 0; j < 256; j++) { + if (test_bit(j, dev->show_vfinfo_filter)) + num_vfs++; + } size += nla_total_size(num_vfs * sizeof(struct nlattr)); size += num_vfs * (nla_total_size(sizeof(struct ifla_vf_mac)) +
@@ -876,6 +880,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, const struct rtnl_link_stats64 *stats; struct nlattr *attr, *af_spec; struct rtnl_af_ops *af_ops; + u32 num_vf_filters_set = 0; ASSERT_RTNL(); nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -941,10 +946,18 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, goto nla_put_failure; copy_rtnl_link_stats64(nla_data(attr), stats); - if (dev->dev.parent) - NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); + if (dev->dev.parent) { + int j; + for (j = 0; j < 256; j++) { + if (test_bit(j, dev->show_vfinfo_filter)) + num_vf_filters_set++; + } + if (num_vf_filters_set) + NLA_PUT_U32(skb, IFLA_NUM_VF, num_vf_filters_set); + } - if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { + if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent && + num_vf_filters_set) { int i; struct nlattr *vfinfo, *vf;
@@ -960,6 +973,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, struct ifla_vf_tx_rate vf_tx_rate; struct ifla_vf_spoofchk vf_spoofchk; + if (!test_bit(i, dev->show_vfinfo_filter)) + continue; + /* * Not all SR-IOV capable drivers support the * spoofcheck query. Preset to -1 so the user
@@ -1234,6 +1250,20 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) ivs->setting); break; } + case IFLA_VF_INFOFILTER: { + struct ifla_vf_infofilter *ivf; + ivf = nla_data(vf); + if (ivf->vf < dev_num_vf(dev->dev.parent)) { + if (ivf->filter) + set_bit(ivf->vf, + dev->show_vfinfo_filter); + else + clear_bit(ivf->vf, + dev->show_vfinfo_filter); + err = 0; + } + break; + } default: err = -EINVAL; break;