[PATCH 3/3] route/link: indicate failure of rtnl_link_get_kernel() for old kernels

Thomas Haller thaller at redhat.com
Wed Nov 26 09:13:38 PST 2014


Older kernels without patch a3d1289126e7b14307074b76bf1677015ea5036f do
not support rtnl_getlink() by ifname. Allow user space to better detect
this situation by setting errno to ENOSUP.

Signed-off-by: Thomas Haller <thaller at redhat.com>
---
 include/netlink/utils.h |  8 ++++++++
 lib/route/link.c        | 22 +++++++++++++++++++++-
 lib/utils.c             |  2 +-
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/include/netlink/utils.h b/include/netlink/utils.h
index 6b4b787..4fd9b53 100644
--- a/include/netlink/utils.h
+++ b/include/netlink/utils.h
@@ -113,6 +113,14 @@ enum {
 	NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE = 4,
 #define NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE
 
+	/**
+	 * Indicate that rtnl_link_get_kernel() sets errno to ENOSUP when older
+	 * kernel fail to lookup by name. In this case, the command fails with
+	 * -NLE_EINVAL.
+	 */
+	NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_SET_ENOTSUP = 5,
+#define NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_SET_ENOTSUP NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_SET_ENOTSUP
+
 	__NL_CAPABILITY_MAX
 #define NL_CAPABILITY_MAX                               (__NL_CAPABILITY_MAX - 1)
 };
diff --git a/lib/route/link.c b/lib/route/link.c
index 7a53532..c81d9d0 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -1160,6 +1160,15 @@ nla_put_failure:
  * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
  * found.
  *
+ * Older kernels do not support lookup by name. In that case, the function
+ * returns -NLE_INVAL. This failure reason is a bit unclear, hence newer
+ * versions of libnl with capability 5 (NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_SET_ENOTSUP)
+ * set errno additionaly to ENOTSUP (or set errno to zero).
+ * If you experince this failure due to missing kernel support, you can workaround
+ * it by fetching all links and search the matching ifindex by hand.
+ * The correct way to check whether the call failed due to missing kernel support is
+ *   if (err == -NLE_INVAL && (!nl_has_capability(5) || errno == ENOTSUP))
+ *
  * @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
  * @return 0 on success or a negative error code.
  */
@@ -1169,6 +1178,7 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
 	struct nl_msg *msg = NULL;
 	struct nl_object *obj;
 	int err;
+	int syserr;
 
 	if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
 		return err;
@@ -1178,8 +1188,18 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
 	if (err < 0)
 		return err;
 
-	if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
+	if ((err = nl_pickup_keep_syserr(sk, link_msg_parser, &obj, &syserr)) < 0) {
+		if (err == -NLE_INVAL) {
+			/* Older kernels do not support lookup by ifname. This was added
+			 * by commit kernel a3d1289126e7b14307074b76bf1677015ea5036f .
+			 */
+			if (syserr == -EINVAL && ifindex <= 0 && name && *name)
+				errno = ENOTSUP;
+			else
+				errno = 0;
+		}
 		return err;
+	}
 
 	/* We have used link_msg_parser(), object is definitely a link */
 	*result = (struct rtnl_link *) obj;
diff --git a/lib/utils.c b/lib/utils.c
index 67612bd..629c416 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1148,7 +1148,7 @@ int nl_has_capability (int capability)
 			NL_CAPABILITY_ROUTE_LINK_VETH_GET_PEER_OWN_REFERENCE,
 			NL_CAPABILITY_ROUTE_LINK_CLS_ADD_ACT_OWN_REFERENCE,
 			NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE,
-			0,
+			NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_SET_ENOTSUP,
 			0,
 			0,
 			0),
-- 
1.9.3




More information about the libnl mailing list