diff mbox series

[iproute2-next,4/4] iplink: render IFLA_VF_STATS from IFLA_VFSTATS_LIST

Message ID 20210123045351.2797433-4-edwin.peer@broadcom.com (mailing list archive)
State Rejected
Delegated to: David Ahern
Headers show
Series [iproute2-next,1/4] uapi: update kernel headers from upstream | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Edwin Peer Jan. 23, 2021, 4:53 a.m. UTC
The maximum possible length of a netlink attribute is 64KB, but the
IFLA_VFINFO_LIST exceeds this when stats are included and more than
about 220 VFs are present (each VF consumes approximately 300 bytes,
depending on alignment and optional fields). Exceeding the limit will
cause the list to be truncated by the kernel's nla_nest_end().

A recent ABI fix moves the VF stats into an independent list when
requested, thus avoiding the problem. Send requests using the new
RTEXT_FILTER_VF_SEPARATE_STATS filter and render the stats from
the alternate list instead.

Signed-off-by: Edwin Peer <edwin.peer@broadcom.com>
---
 ip/ipaddress.c   | 14 +++++++++++---
 ip/iplink.c      |  1 +
 lib/libnetlink.c |  3 ++-
 3 files changed, 14 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 75511881050d..a048b3db601c 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1200,12 +1200,20 @@  int print_linkinfo(struct nlmsghdr *n, void *arg)
 
 	if ((do_link || show_details) && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) {
 		struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST];
-		int rem = RTA_PAYLOAD(vflist), count = 0;
+		struct rtattr *j, *vfstats = tb[IFLA_VFSTATS_LIST];
+		int rem_stats, rem = RTA_PAYLOAD(vflist), count = 0;
 
+		j = vfstats ? RTA_DATA(vfstats) : NULL;
+		rem_stats = vfstats ? RTA_PAYLOAD(vfstats) : 0;
 		open_json_array(PRINT_JSON, "vfinfo_list");
 		for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 			open_json_object(NULL);
 			print_vfinfo(fp, ifi, i);
+			if (show_stats && j) {
+				print_vf_stats64(fp, j);
+				j = RTA_OK(j, rem_stats) ?
+					RTA_NEXT(j, rem_stats) : NULL;
+			}
 			close_json_object();
 			count++;
 		}
@@ -1885,7 +1893,7 @@  static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
 	__u32 filt_mask;
 	int err;
 
-	filt_mask = RTEXT_FILTER_VF;
+	filt_mask = RTEXT_FILTER_VF | RTEXT_FILTER_VF_SEPARATE_STATS;
 	if (!show_stats)
 		filt_mask |= RTEXT_FILTER_SKIP_STATS;
 	err = addattr32(nlh, reqlen, IFLA_EXT_MASK, filt_mask);
@@ -1923,7 +1931,7 @@  static int ipaddr_link_get(int index, struct nlmsg_chain *linfo)
 		.i.ifi_family = filter.family,
 		.i.ifi_index = index,
 	};
-	__u32 filt_mask = RTEXT_FILTER_VF;
+	__u32 filt_mask = RTEXT_FILTER_VF | RTEXT_FILTER_VF_SEPARATE_STATS;
 	struct nlmsghdr *answer;
 
 	if (!show_stats)
diff --git a/ip/iplink.c b/ip/iplink.c
index 6a973213dc11..3cce8aa2a0b7 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -1117,6 +1117,7 @@  int iplink_get(char *name, __u32 filt_mask)
 			  name, strlen(name) + 1);
 	}
 
+	filt_mask |= RTEXT_FILTER_VF_SEPARATE_STATS;
 	if (!show_stats)
 		filt_mask |= RTEXT_FILTER_SKIP_STATS;
 	addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index b1f07d4570cf..b4aa9d16b446 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -486,7 +486,8 @@  static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
 int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
 {
 	if (family == AF_UNSPEC)
-		return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
+		return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF |
+						RTEXT_FILTER_VF_SEPARATE_STATS);
 
 	return __rtnl_linkdump_req(rth, family);
 }