summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-11-11 14:50:49 (GMT)
committerThomas Graf <tgraf@suug.ch>2010-11-11 14:50:49 (GMT)
commit3fa6a6b4104729e8e6bc07be61e04ee25b8d3611 (patch)
treeec5a9d3e73f2b44d20d4bb026cf3002ea1d01018 /lib
parentfd857eeb9fb17509563657a25312aafa562e90c2 (diff)
downloadlibnl-3fa6a6b4104729e8e6bc07be61e04ee25b8d3611.zip
libnl-3fa6a6b4104729e8e6bc07be61e04ee25b8d3611.tar.gz
libnl-3fa6a6b4104729e8e6bc07be61e04ee25b8d3611.tar.bz2
link: API for address family specific link data
Introduces a new API to handle address familiy specific link data such as IFLA_PROTINFO. It provides entry hooks for parsing IFLA_PROTINFO attributes and allows to include the parsed data when a link object is dumped.
Diffstat (limited to 'lib')
-rw-r--r--lib/route/link.c130
-rw-r--r--lib/route/link/api.c94
-rw-r--r--lib/route/link/vlan.c4
3 files changed, 215 insertions, 13 deletions
diff --git a/lib/route/link.c b/lib/route/link.c
index 6aa3c77..2082d6e 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -154,7 +154,7 @@
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
-#include <netlink/route/link/info-api.h>
+#include <netlink/route/link/api.h>
/** @cond SKIP */
#define LINK_ATTR_MTU 0x0001
@@ -183,6 +183,84 @@ static struct nl_cache_ops rtnl_link_ops;
static struct nl_object_ops link_obj_ops;
/** @endcond */
+static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+ void *data, void *arg)
+{
+ if (ops->ao_free)
+ ops->ao_free(link, data);
+
+ rtnl_link_af_ops_put(ops);
+
+ return 0;
+}
+
+static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+ void *data, void *arg)
+{
+ struct rtnl_link *dst = arg;
+
+ if (ops->ao_clone &&
+ !(dst->l_af_data[ops->ao_family] = ops->ao_clone(link, data)))
+ return -NLE_NOMEM;
+
+ return 0;
+}
+
+static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+ void *data, void *arg)
+{
+ struct nl_dump_params *p = arg;
+
+ if (ops->ao_dump[NL_DUMP_LINE])
+ ops->ao_dump[NL_DUMP_LINE](link, p, data);
+
+ return 0;
+}
+
+static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+ void *data, void *arg)
+{
+ struct nl_dump_params *p = arg;
+
+ if (ops->ao_dump[NL_DUMP_DETAILS])
+ ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
+
+ return 0;
+}
+
+static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+ void *data, void *arg)
+{
+ struct nl_dump_params *p = arg;
+
+ if (ops->ao_dump[NL_DUMP_STATS])
+ ops->ao_dump[NL_DUMP_STATS](link, p, data);
+
+ return 0;
+}
+
+static int do_foreach_af(struct rtnl_link *link,
+ int (*cb)(struct rtnl_link *,
+ struct rtnl_link_af_ops *, void *, void *),
+ void *arg)
+{
+ int i, err;
+
+ for (i = 0; i < AF_MAX; i++) {
+ if (link->l_af_data[i]) {
+ struct rtnl_link_af_ops *ops;
+
+ if (!(ops = rtnl_link_af_ops_lookup(i)))
+ BUG();
+
+ if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static void release_link_info(struct rtnl_link *link)
{
struct rtnl_link_info_ops *io = link->l_info_ops;
@@ -208,6 +286,8 @@ static void link_free_data(struct nl_object *c)
nl_addr_put(link->l_bcast);
free(link->l_ifalias);
+
+ do_foreach_af(link, af_free, NULL);
}
}
@@ -235,6 +315,9 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
return err;
}
+ if ((err = do_foreach_af(src, af_clone, dst)) < 0)
+ return err;
+
return 0;
}
@@ -270,6 +353,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct rtnl_link *link;
struct ifinfomsg *ifi;
struct nlattr *tb[IFLA_MAX+1];
+ struct rtnl_link_af_ops *af_ops = NULL;
int err;
link = rtnl_link_alloc();
@@ -280,6 +364,27 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link->ce_msgtype = n->nlmsg_type;
+ if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
+ return -NLE_MSG_TOOSHORT;
+
+ ifi = nlmsg_data(n);
+ link->l_family = ifi->ifi_family;
+ link->l_arptype = ifi->ifi_type;
+ link->l_index = ifi->ifi_index;
+ link->l_flags = ifi->ifi_flags;
+ link->l_change = ifi->ifi_change;
+ link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
+ LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
+ LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
+
+ if ((af_ops = rtnl_link_af_ops_lookup(ifi->ifi_family))) {
+ if (af_ops->ao_protinfo_policy) {
+ memcpy(&link_policy[IFLA_PROTINFO],
+ af_ops->ao_protinfo_policy,
+ sizeof(struct nla_policy));
+ }
+ }
+
err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
if (err < 0)
goto errout;
@@ -291,15 +396,6 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
- ifi = nlmsg_data(n);
- link->l_family = ifi->ifi_family;
- link->l_arptype = ifi->ifi_type;
- link->l_index = ifi->ifi_index;
- link->l_flags = ifi->ifi_flags;
- link->l_change = ifi->ifi_change;
- link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
- LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
- LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
if (tb[IFLA_STATS]) {
struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
@@ -478,8 +574,16 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
}
+ if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
+ err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
+ link->l_af_data[link->l_family]);
+ if (err < 0)
+ goto errout;
+ }
+
err = pp->pp_cb((struct nl_object *) link, pp);
errout:
+ rtnl_link_af_ops_put(af_ops);
rtnl_link_put(link);
return err;
}
@@ -522,6 +626,8 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
+ do_foreach_af(link, af_dump_line, p);
+
nl_dump(p, "\n");
}
@@ -570,6 +676,8 @@ static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
+
+ do_foreach_af(link, af_dump_details, p);
}
static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
@@ -633,6 +741,8 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
+
+ do_foreach_af(link, af_dump_stats, p);
}
#if 0
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
index a0e7679..2a8dd1d 100644
--- a/lib/route/link/api.c
+++ b/lib/route/link/api.c
@@ -43,7 +43,7 @@
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/link.h>
-#include <netlink/route/link/info-api.h>
+#include <netlink/route/link/api.h>
static struct rtnl_link_info_ops *info_ops;
@@ -94,5 +94,97 @@ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
return 0;
}
+static struct rtnl_link_af_ops *af_ops[AF_MAX];
+
+/**
+ * Return operations of a specific link address family
+ * @arg family Address family
+ *
+ * @note The returned pointer must be given back using rtnl_link_af_ops_put()
+ *
+ * @return Pointer to operations or NULL if unavailable.
+ */
+struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
+{
+ if (family == AF_UNSPEC || family >= AF_MAX)
+ return NULL;
+
+ if (af_ops[family])
+ af_ops[family]->ao_refcnt++;
+
+ return af_ops[family];
+}
+
+/**
+ * Give back reference to a set of operations.
+ * @arg ops Address family operations.
+ */
+void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
+{
+ ops->ao_refcnt--;
+}
+
+/**
+ * Register operations for a link address family
+ * @arg ops Address family operations
+ *
+ * This function must be called by modules implementing a specific link
+ * address family. 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 Address family is out of range (0..AF_MAX)
+ * @return -NLE_EXIST Operations for address family already registered.
+ */
+int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
+{
+ if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
+ return -NLE_INVAL;
+
+ if (af_ops[ops->ao_family])
+ return -NLE_EXIST;
+
+ ops->ao_refcnt = 0;
+ af_ops[ops->ao_family] = ops;
+
+ NL_DBG(1, "Registered link address family operations %u\n",
+ ops->ao_family);
+
+ return 0;
+}
+
+/**
+ * Unregister operations for a link address family
+ * @arg ops Address family operations
+ *
+ * This function must be called if a module implementing a specific link
+ * address family is unloaded or becomes unavailable. It must provide a
+ * set of operations which have previously been registered using
+ * rtnl_link_af_register().
+ *
+ * @return 0 on success or a negative error code
+ * @return -NLE_INVAL ops is NULL
+ * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
+ * @return -NLE_BUSY Address family operations still in use.
+ */
+int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
+{
+ if (!ops)
+ return -NLE_INVAL;
+
+ if (!af_ops[ops->ao_family])
+ return -NLE_OBJ_NOTFOUND;
+
+ if (ops->ao_refcnt > 0)
+ return -NLE_BUSY;
+
+ af_ops[ops->ao_family] = NULL;
+
+ NL_DBG(1, "Unregistered link address family operations %u\n",
+ ops->ao_family);
+
+ return 0;
+}
+
/** @} */
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
index c466afe..a76cb83 100644
--- a/lib/route/link/vlan.c
+++ b/lib/route/link/vlan.c
@@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
*/
/**
@@ -23,7 +23,7 @@
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
-#include <netlink/route/link/info-api.h>
+#include <netlink/route/link/api.h>
#include <netlink/route/link/vlan.h>
#include <linux/if_vlan.h>