diff options
author | Thomas Graf <tgraf@suug.ch> | 2010-11-11 15:18:53 (GMT) |
---|---|---|
committer | Thomas Graf <tgraf@suug.ch> | 2010-11-11 15:18:53 (GMT) |
commit | 67aeb7474f3242bf9dc2e43b860643aa1da41a6e (patch) | |
tree | a8e9631280428bef2a19a7f46199d48c3762d6bc /lib/route | |
parent | 800013b787cfb464d674caec96163a5e66de3c71 (diff) | |
download | libnl-67aeb7474f3242bf9dc2e43b860643aa1da41a6e.zip libnl-67aeb7474f3242bf9dc2e43b860643aa1da41a6e.tar.gz libnl-67aeb7474f3242bf9dc2e43b860643aa1da41a6e.tar.bz2 |
link/api: Convert link info ops to use nl_list_head
rtnl_link_info_ops_lookup() now returns a pointer with refcnt increment,
you must return it using rtnl_link_info_ops_put()
Diffstat (limited to 'lib/route')
-rw-r--r-- | lib/route/link.c | 3 | ||||
-rw-r--r-- | lib/route/link/api.c | 87 |
2 files changed, 71 insertions, 19 deletions
diff --git a/lib/route/link.c b/lib/route/link.c index 2082d6e..7aed708 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -266,8 +266,8 @@ static void release_link_info(struct rtnl_link *link) struct rtnl_link_info_ops *io = link->l_info_ops; if (io != NULL) { - io->io_refcnt--; io->io_free(link); + rtnl_link_info_ops_put(io); link->l_info_ops = NULL; } } @@ -562,7 +562,6 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, kind = nla_get_string(li[IFLA_INFO_KIND]); ops = rtnl_link_info_ops_lookup(kind); if (ops != NULL) { - ops->io_refcnt++; link->l_info_ops = ops; err = ops->io_parse(link, li[IFLA_INFO_DATA], li[IFLA_INFO_XSTATS]); diff --git a/lib/route/link/api.c b/lib/route/link/api.c index 9e14e4b..1830fe3 100644 --- a/lib/route/link/api.c +++ b/lib/route/link/api.c @@ -45,53 +45,106 @@ #include <netlink/route/link.h> #include <netlink/route/link/api.h> -static struct rtnl_link_info_ops *info_ops; +static NL_LIST_HEAD(info_ops); -struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) +static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name) { struct rtnl_link_info_ops *ops; - for (ops = info_ops; ops; ops = ops->io_next) + nl_list_for_each_entry(ops, &info_ops, io_list) if (!strcmp(ops->io_name, name)) return ops; return NULL; } +/** + * Return operations of a specific link info type + * @arg name Name of link info type. + * + * @note The returned pointer must be given back using rtnl_link_info_ops_put() + * + * @return Pointer to operations or NULL if unavailable. + */ +struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) +{ + struct rtnl_link_info_ops *ops; + + if ((ops = __rtnl_link_info_ops_lookup(name))) + ops->io_refcnt++; + + return ops; +} + +/** + * Give back reference to a set of operations. + * @arg ops Link info operations. + */ +void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops) +{ + if (ops) + ops->io_refcnt--; +} + +/** + * Register operations for a link info type + * @arg ops Link info operations + * + * This function must be called by modules implementing a specific link + * info type. It will make the operations implemented by the module + * available for everyone else. + * + * @return 0 on success or a negative error code. + * @return -NLE_INVAL Link info name not specified. + * @return -NLE_EXIST Operations for address family already registered. + */ int rtnl_link_register_info(struct rtnl_link_info_ops *ops) { if (ops->io_name == NULL) return -NLE_INVAL; - if (rtnl_link_info_ops_lookup(ops->io_name)) + if (__rtnl_link_info_ops_lookup(ops->io_name)) return -NLE_EXIST; NL_DBG(1, "Registered link info operations %s\n", ops->io_name); - ops->io_next = info_ops; - info_ops = ops; + nl_list_add_tail(&ops->io_list, &info_ops); return 0; } +/** + * Unregister operations for a link info type + * @arg ops Link info operations + * + * This function must be called if a module implementing a specific link + * info type is unloaded or becomes unavailable. It must provide a + * set of operations which have previously been registered using + * rtnl_link_register_info(). + * + * @return 0 on success or a negative error code + * @return _NLE_OPNOTSUPP Link info operations not registered. + * @return -NLE_BUSY Link info operations still in use. + */ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops) { - struct rtnl_link_info_ops *t, **tp; + struct rtnl_link_info_ops *t; - for (tp = &info_ops; (t=*tp) != NULL; tp = &t->io_next) - if (t == ops) - break; + nl_list_for_each_entry(t, &info_ops, io_list) { + if (t == ops) { + if (t->io_refcnt > 0) + return -NLE_BUSY; - if (!t) - return -NLE_OPNOTSUPP; + nl_list_del(&t->io_list); - if (t->io_refcnt > 0) - return -NLE_BUSY; + NL_DBG(1, "Unregistered link info operations %s\n", + ops->io_name); - NL_DBG(1, "Unregistered link info perations %s\n", ops->io_name); + return 0; + } + } - *tp = t->io_next; - return 0; + return -NLE_OPNOTSUPP; } static struct rtnl_link_af_ops *af_ops[AF_MAX]; |