Skip to content

Commit e5eca6d

Browse files
michichdavem330
authored andcommitted
rtnetlink: fix userspace API breakage for iproute2 < v3.9.0
When running RHEL6 userspace on a current upstream kernel, "ip link" fails to show VF information. The reason is a kernel<->userspace API change introduced by commit 88c5b5c ("rtnetlink: Call nlmsg_parse() with correct header length"), after which the kernel does not see iproute2's IFLA_EXT_MASK attribute in the netlink request. iproute2 adjusted for the API change in its commit 63338dc ("libnetlink: Use ifinfomsg instead of rtgenmsg in rtnl_wilddump_req_filter"). The problem has been noticed before: http://marc.info/?l=linux-netdev&m=136692296022182&w=2 (Subject: Re: getting VF link info seems to be broken in 3.9-rc8) We can do better than tell those with old userspace to upgrade. We can recognize the old iproute2 in the kernel by checking the netlink message length. Even when including the IFLA_EXT_MASK attribute, its netlink message is shorter than struct ifinfomsg. With this patch "ip link" shows VF information in both old and new iproute2 versions. Signed-off-by: Michal Schmidt <mschmidt@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent bef1909 commit e5eca6d

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

net/core/rtnetlink.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,15 +1244,25 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
12441244
struct nlattr *tb[IFLA_MAX+1];
12451245
u32 ext_filter_mask = 0;
12461246
int err;
1247+
int hdrlen;
12471248

12481249
s_h = cb->args[0];
12491250
s_idx = cb->args[1];
12501251

12511252
rcu_read_lock();
12521253
cb->seq = net->dev_base_seq;
12531254

1254-
if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
1255-
ifla_policy) >= 0) {
1255+
/* A hack to preserve kernel<->userspace interface.
1256+
* The correct header is ifinfomsg. It is consistent with rtnl_getlink.
1257+
* However, before Linux v3.9 the code here assumed rtgenmsg and that's
1258+
* what iproute2 < v3.9.0 used.
1259+
* We can detect the old iproute2. Even including the IFLA_EXT_MASK
1260+
* attribute, its netlink message is shorter than struct ifinfomsg.
1261+
*/
1262+
hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ?
1263+
sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg);
1264+
1265+
if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
12561266

12571267
if (tb[IFLA_EXT_MASK])
12581268
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
@@ -2126,9 +2136,13 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
21262136
struct nlattr *tb[IFLA_MAX+1];
21272137
u32 ext_filter_mask = 0;
21282138
u16 min_ifinfo_dump_size = 0;
2139+
int hdrlen;
2140+
2141+
/* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */
2142+
hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ?
2143+
sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg);
21292144

2130-
if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
2131-
ifla_policy) >= 0) {
2145+
if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
21322146
if (tb[IFLA_EXT_MASK])
21332147
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
21342148
}

0 commit comments

Comments
 (0)