| From foo@baz Thu Jun 19 10:28:46 PDT 2014 |
| From: Michal Schmidt <mschmidt@redhat.com> |
| Date: Wed, 28 May 2014 14:15:19 +0200 |
| Subject: rtnetlink: fix userspace API breakage for iproute2 < |
| v3.9.0 |
| |
| From: Michal Schmidt <mschmidt@redhat.com> |
| |
| [ Upstream commit e5eca6d41f53db48edd8cf88a3f59d2c30227f8e ] |
| |
| 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 |
| 88c5b5ce5cb57 ("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 63338dca4513 |
| ("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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/core/rtnetlink.c | 22 ++++++++++++++++++---- |
| 1 file changed, 18 insertions(+), 4 deletions(-) |
| |
| --- a/net/core/rtnetlink.c |
| +++ b/net/core/rtnetlink.c |
| @@ -1166,6 +1166,7 @@ static int rtnl_dump_ifinfo(struct sk_bu |
| struct nlattr *tb[IFLA_MAX+1]; |
| u32 ext_filter_mask = 0; |
| int err; |
| + int hdrlen; |
| |
| s_h = cb->args[0]; |
| s_idx = cb->args[1]; |
| @@ -1173,8 +1174,17 @@ static int rtnl_dump_ifinfo(struct sk_bu |
| rcu_read_lock(); |
| cb->seq = net->dev_base_seq; |
| |
| - if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, |
| - ifla_policy) >= 0) { |
| + /* A hack to preserve kernel<->userspace interface. |
| + * The correct header is ifinfomsg. It is consistent with rtnl_getlink. |
| + * However, before Linux v3.9 the code here assumed rtgenmsg and that's |
| + * what iproute2 < v3.9.0 used. |
| + * We can detect the old iproute2. Even including the IFLA_EXT_MASK |
| + * attribute, its netlink message is shorter than struct ifinfomsg. |
| + */ |
| + hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ? |
| + sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
| + |
| + if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) { |
| |
| if (tb[IFLA_EXT_MASK]) |
| ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
| @@ -2085,9 +2095,13 @@ static u16 rtnl_calcit(struct sk_buff *s |
| struct nlattr *tb[IFLA_MAX+1]; |
| u32 ext_filter_mask = 0; |
| u16 min_ifinfo_dump_size = 0; |
| + int hdrlen; |
| + |
| + /* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */ |
| + hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? |
| + sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
| |
| - if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, |
| - ifla_policy) >= 0) { |
| + if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) { |
| if (tb[IFLA_EXT_MASK]) |
| ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
| } |