summaryrefslogtreecommitdiffstats
path: root/lib/route
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-11-11 15:18:53 (GMT)
committerThomas Graf <tgraf@suug.ch>2010-11-11 15:18:53 (GMT)
commit67aeb7474f3242bf9dc2e43b860643aa1da41a6e (patch)
treea8e9631280428bef2a19a7f46199d48c3762d6bc /lib/route
parent800013b787cfb464d674caec96163a5e66de3c71 (diff)
downloadlibnl-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.c3
-rw-r--r--lib/route/link/api.c87
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];