Separating the VF stats out of IFLA_VF_INFO appears to be the least impact way of resolving the nlattr overflow bug in IFLA_VFINFO_LIST.
Since changing the hierarchy does constitute an ABI change, it must be explicitly requested via RTEXT_FILTER_VF_SEPARATE_STATS. Otherwise, the old location is maintained for compatibility. A new container type, namely IFLA_VFSTATS_LIST, is introduced to group the stats objects into an ordered list that corresponds with the order of VFs in IFLA_VFINFO_LIST. Fixes: 3b766cd83232 ("net/core: Add reading VF statistics through the PF netdevice") Fixes: c5a9f6f0ab40 ("net/core: Add drop counters to VF statistics") Signed-off-by: Edwin Peer <edwin.p...@broadcom.com> --- include/uapi/linux/if_link.h | 1 + include/uapi/linux/rtnetlink.h | 1 + net/core/rtnetlink.c | 24 +++++++++++++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 2bd0d8bbcdb2..db12ffd2bffd 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -341,6 +341,7 @@ enum { IFLA_ALT_IFNAME, /* Alternative ifname */ IFLA_PERM_ADDRESS, IFLA_PROTO_DOWN_REASON, + IFLA_VFSTATS_LIST, __IFLA_MAX }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index b841caa4657e..f2f4f9b4d595 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -789,6 +789,7 @@ enum { #define RTEXT_FILTER_MRP (1 << 4) #define RTEXT_FILTER_CFM_CONFIG (1 << 5) #define RTEXT_FILTER_CFM_STATUS (1 << 6) +#define RTEXT_FILTER_VF_SEPARATE_STATS (1 << 7) /* End of information exported to user level */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 95564fd12f24..cddd3945bc11 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -933,6 +933,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, nla_total_size(sizeof(struct ifla_vf_rss_query_en)) + nla_total_size(sizeof(struct ifla_vf_trust))); if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS) { + if (ext_filter_mask & RTEXT_FILTER_VF_SEPARATE_STATS) + size += nla_total_size(0); /* IFLA_VFSTATS_LIST */ size += num_vfs * (nla_total_size(0) + /* nest IFLA_VF_STATS */ /* IFLA_VF_STATS_RX_PACKETS */ @@ -1368,7 +1370,8 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, goto nla_put_vf_failure; } nla_nest_end(skb, vfvlanlist); - if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS) { + if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS && + ~ext_filter_mask & RTEXT_FILTER_VF_SEPARATE_STATS) { if (rtnl_fill_vfstats(skb, dev, vfs_num)) goto nla_put_vf_failure; } @@ -1386,7 +1389,7 @@ static noinline_for_stack int rtnl_fill_vf(struct sk_buff *skb, struct net_device *dev, u32 ext_filter_mask) { - struct nlattr *vfinfo; + struct nlattr *vfinfo, *vfstats; int i, num_vfs; if (!dev->dev.parent || ((ext_filter_mask & RTEXT_FILTER_VF) == 0)) @@ -1407,8 +1410,23 @@ static noinline_for_stack int rtnl_fill_vf(struct sk_buff *skb, if (rtnl_fill_vfinfo(skb, dev, i, vfinfo, ext_filter_mask)) return -EMSGSIZE; } - nla_nest_end(skb, vfinfo); + + if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS && + ext_filter_mask & RTEXT_FILTER_VF_SEPARATE_STATS) { + vfstats = nla_nest_start_noflag(skb, IFLA_VFSTATS_LIST); + if (!vfstats) + return -EMSGSIZE; + + for (i = 0; i < num_vfs; i++) { + if (rtnl_fill_vfstats(skb, dev, i)) { + nla_nest_cancel(skb, vfstats); + return -EMSGSIZE; + } + } + nla_nest_end(skb, vfstats); + } + return 0; } -- 2.30.0
smime.p7s
Description: S/MIME Cryptographic Signature