[patch libnl] link: allow to add/get linkinfo of unknown type

Jiri Pirko jpirko at redhat.com
Fri Nov 11 08:56:16 EST 2011


store type kind in rtnl_link independently. That would allow to use this
value even if type_ops are not present. This allows for example to
create devices of type unknown to libnl.

Signed-off-by: Jiri Pirko <jpirko at redhat.com>
---
 include/netlink-types.h |    1 +
 lib/route/link.c        |   76 +++++++++++++++++++++++++++++++++-------------
 2 files changed, 55 insertions(+), 22 deletions(-)

diff --git a/include/netlink-types.h b/include/netlink-types.h
index 750c897..82481b7 100644
--- a/include/netlink-types.h
+++ b/include/netlink-types.h
@@ -167,6 +167,7 @@ struct rtnl_link
 	uint8_t				l_operstate;
 	uint8_t				l_linkmode;
 	/* 2 byte hole */
+	char *				l_info_kind;
 	struct rtnl_link_info_ops *	l_info_ops;
 	void *				l_af_data[AF_MAX];
 	void *				l_info;
diff --git a/lib/route/link.c b/lib/route/link.c
index e486b3f..ad5fcbe 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -195,6 +195,7 @@ static void link_free_data(struct nl_object *c)
 		nl_addr_put(link->l_bcast);
 
 		free(link->l_ifalias);
+		free(link->l_info_kind);
 
 		do_foreach_af(link, af_free, NULL);
 	}
@@ -218,6 +219,10 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
 		if (!(dst->l_ifalias = strdup(src->l_ifalias)))
 			return -NLE_NOMEM;
 
+	if (src->l_info_kind)
+		if (!(dst->l_info_kind = strdup(src->l_info_kind)))
+			return -NLE_NOMEM;
+
 	if (src->l_info_ops && src->l_info_ops->io_clone) {
 		err = src->l_info_ops->io_clone(dst, src);
 		if (err < 0)
@@ -478,18 +483,27 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
 			struct rtnl_link_info_ops *ops;
 			char *kind;
 
-			kind = nla_get_string(li[IFLA_INFO_KIND]);
+			kind = nla_strdup(tb[IFLA_INFO_KIND]);
+			if (kind == NULL) {
+				err = -NLE_NOMEM;
+				goto errout;
+			}
+			link->l_info_kind = kind;
+			link->ce_mask |= LINK_ATTR_LINKINFO;
+
 			ops = rtnl_link_info_ops_lookup(kind);
 			link->l_info_ops = ops;
-			
-			if (ops && ops->io_parse &&
-			    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
-				err = ops->io_parse(link, li[IFLA_INFO_DATA],
-						    li[IFLA_INFO_XSTATS]);
-				if (err < 0)
-					goto errout;
-			} else {
-				/* XXX: Warn about unparsed info? */
+
+			if (ops) {
+				if (ops->io_parse &&
+				    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
+					err = ops->io_parse(link, li[IFLA_INFO_DATA],
+							    li[IFLA_INFO_XSTATS]);
+					if (err < 0)
+						goto errout;
+				} else {
+					/* XXX: Warn about unparsed info? */
+				}
 			}
 		}
 	}
@@ -1115,17 +1129,19 @@ static int build_link_msg(int cmd, struct ifinfomsg *hdr,
 	if (link->ce_mask & LINK_ATTR_MASTER)
 		NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
 
-	if ((link->ce_mask & LINK_ATTR_LINKINFO) && link->l_info_ops) {
+	if (link->ce_mask & LINK_ATTR_LINKINFO) {
 		struct nlattr *info;
 
 		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
 			goto nla_put_failure;
 
-		NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_ops->io_name);
+		NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
 
-		if (link->l_info_ops->io_put_attrs &&
-		    link->l_info_ops->io_put_attrs(msg, link) < 0)
-			goto nla_put_failure;
+		if (link->l_info_ops) {
+			if (link->l_info_ops->io_put_attrs &&
+			    link->l_info_ops->io_put_attrs(msg, link) < 0)
+				goto nla_put_failure;
+		}
 
 		nla_nest_end(msg, info);
 	}
@@ -1952,20 +1968,36 @@ int rtnl_link_set_type(struct rtnl_link *link, const char *type)
 {
 	struct rtnl_link_info_ops *io;
 	int err;
+	char *kind;
 
-	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
-		return -NLE_OPNOTSUPP;
-
+	free(link->l_info_kind);
+	link->ce_mask &= ~LINK_ATTR_LINKINFO;
 	if (link->l_info_ops)
 		release_link_info(link);
 
-	if (io->io_alloc && (err = io->io_alloc(link)) < 0)
-		return err;
+	if (!type)
+		return 0;
+
+	kind = strdup(type);
+	if (!kind)
+		return -NLE_NOMEM;
+
+	io = rtnl_link_info_ops_lookup(type);
+	if (io) {
+		if (io->io_alloc && (err = io->io_alloc(link)) < 0)
+			goto errout;
 
+		link->l_info_ops = io;
+	}
+
+	link->l_info_kind = kind;
 	link->ce_mask |= LINK_ATTR_LINKINFO;
-	link->l_info_ops = io;
 
 	return 0;
+
+errout:
+	free(kind);
+	return err;
 }
 
 /**
@@ -1977,7 +2009,7 @@ int rtnl_link_set_type(struct rtnl_link *link, const char *type)
  */
 char *rtnl_link_get_type(struct rtnl_link *link)
 {
-	return link->l_info_ops ? link->l_info_ops->io_name : NULL;
+	return link->l_info_kind;
 }
 
 /** @} */
-- 
1.7.6




More information about the libnl mailing list