From ef75c4edf0930b4d745da695c5fe0075c7b3afdd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 11 Nov 2011 14:56:16 +0100 Subject: [PATCH] link: allow to add/get linkinfo of unknown type 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 --- 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; } /** @} */