aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Schmidt <mschmidt@redhat.com>2014-05-28 08:15:19 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-12 14:07:42 -0400
commite5eca6d41f53db48edd8cf88a3f59d2c30227f8e (patch)
tree50c7e303026871c65ffbfd8480a8aa20524cee98
parentbef1909ee3ed1ca39231b260a8d3b4544ecd0c8f (diff)
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 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>
-rw-r--r--net/core/rtnetlink.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 233b5ae87583..1063996f8317 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1244,6 +1244,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1244 struct nlattr *tb[IFLA_MAX+1]; 1244 struct nlattr *tb[IFLA_MAX+1];
1245 u32 ext_filter_mask = 0; 1245 u32 ext_filter_mask = 0;
1246 int err; 1246 int err;
1247 int hdrlen;
1247 1248
1248 s_h = cb->args[0]; 1249 s_h = cb->args[0];
1249 s_idx = cb->args[1]; 1250 s_idx = cb->args[1];
@@ -1251,8 +1252,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1251 rcu_read_lock(); 1252 rcu_read_lock();
1252 cb->seq = net->dev_base_seq; 1253 cb->seq = net->dev_base_seq;
1253 1254
1254 if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, 1255 /* A hack to preserve kernel<->userspace interface.
1255 ifla_policy) >= 0) { 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) {
1256 1266
1257 if (tb[IFLA_EXT_MASK]) 1267 if (tb[IFLA_EXT_MASK])
1258 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); 1268 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)
2126 struct nlattr *tb[IFLA_MAX+1]; 2136 struct nlattr *tb[IFLA_MAX+1];
2127 u32 ext_filter_mask = 0; 2137 u32 ext_filter_mask = 0;
2128 u16 min_ifinfo_dump_size = 0; 2138 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);
2129 2144
2130 if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, 2145 if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
2131 ifla_policy) >= 0) {
2132 if (tb[IFLA_EXT_MASK]) 2146 if (tb[IFLA_EXT_MASK])
2133 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); 2147 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
2134 } 2148 }