summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-11-11 15:50:49 +0100
committerThomas Graf <tgraf@suug.ch>2010-11-11 15:50:49 +0100
commit3fa6a6b4104729e8e6bc07be61e04ee25b8d3611 (patch)
treeec5a9d3e73f2b44d20d4bb026cf3002ea1d01018
parentfd857eeb9fb17509563657a25312aafa562e90c2 (diff)
downloadlibnl-3fa6a6b4104729e8e6bc07be61e04ee25b8d3611.tar.gz
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.
-rw-r--r--include/netlink-types.h48
-rw-r--r--include/netlink/route/link/api.h115
-rw-r--r--include/netlink/route/link/info-api.h59
-rw-r--r--lib/route/link.c130
-rw-r--r--lib/route/link/api.c94
-rw-r--r--lib/route/link/vlan.c4
6 files changed, 358 insertions, 92 deletions
diff --git a/include/netlink-types.h b/include/netlink-types.h
index 5b0ec5f..24911b9 100644
--- a/include/netlink-types.h
+++ b/include/netlink-types.h
@@ -150,31 +150,31 @@ struct rtnl_link
{
NLHDR_COMMON
- char l_name[IFNAMSIZ];
-
- uint32_t l_family;
- uint32_t l_arptype;
- uint32_t l_index;
- uint32_t l_flags;
- uint32_t l_change;
- uint32_t l_mtu;
- uint32_t l_link;
- uint32_t l_txqlen;
- uint32_t l_weight;
- uint32_t l_master;
- struct nl_addr *l_addr;
- struct nl_addr *l_bcast;
- char l_qdisc[IFQDISCSIZ];
- struct rtnl_link_map l_map;
- uint64_t l_stats[RTNL_LINK_STATS_MAX+1];
- uint32_t l_flag_mask;
- uint32_t l_num_vf;
- uint8_t l_operstate;
- uint8_t l_linkmode;
+ char l_name[IFNAMSIZ];
+ uint32_t l_family;
+ uint32_t l_arptype;
+ uint32_t l_index;
+ uint32_t l_flags;
+ uint32_t l_change;
+ uint32_t l_mtu;
+ uint32_t l_link;
+ uint32_t l_txqlen;
+ uint32_t l_weight;
+ uint32_t l_master;
+ struct nl_addr * l_addr;
+ struct nl_addr * l_bcast;
+ char l_qdisc[IFQDISCSIZ];
+ struct rtnl_link_map l_map;
+ uint64_t l_stats[RTNL_LINK_STATS_MAX+1];
+ uint32_t l_flag_mask;
+ uint32_t l_num_vf;
+ uint8_t l_operstate;
+ uint8_t l_linkmode;
/* 2 byte hole */
- struct rtnl_link_info_ops *l_info_ops;
- void * l_info;
- char * l_ifalias;
+ struct rtnl_link_info_ops * l_info_ops;
+ void * l_af_data[AF_MAX];
+ void * l_info;
+ char * l_ifalias;
};
struct rtnl_ncacheinfo
diff --git a/include/netlink/route/link/api.h b/include/netlink/route/link/api.h
new file mode 100644
index 0000000..ae5af59
--- /dev/null
+++ b/include/netlink/route/link/api.h
@@ -0,0 +1,115 @@
+/*
+ * netlink/route/link/api.h Link Modules API
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_API_H_
+#define NETLINK_LINK_API_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup link_info
+ *
+ * Link info operations
+ */
+struct rtnl_link_info_ops
+{
+ /** Name of operations, must match name on kernel side */
+ char * io_name;
+
+ /** Reference count (internal, do not use) */
+ int io_refcnt;
+
+ /** Called to assign an info type to a link.
+ * Has to allocate enough resources to hold attributes. Can
+ * use link->l_info to store a pointer. */
+ int (*io_alloc)(struct rtnl_link *);
+
+ /** Called to parse the link info attribute.
+ * Must parse the attribute and assign all values to the link.
+ */
+ int (*io_parse)(struct rtnl_link *,
+ struct nlattr *,
+ struct nlattr *);
+
+ /** Called when the link object is dumped.
+ * Must dump the info type specific attributes. */
+ void (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
+ struct nl_dump_params *);
+
+ /** Called when a link object is cloned.
+ * Must clone all info type specific attributes. */
+ int (*io_clone)(struct rtnl_link *, struct rtnl_link *);
+
+ /** Called when construction a link netlink message.
+ * Must append all info type specific attributes to the message. */
+ int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *);
+
+ /** Called to release all resources previously allocated
+ * in either io_alloc() or io_parse(). */
+ void (*io_free)(struct rtnl_link *);
+
+ struct rtnl_link_info_ops * io_next;
+};
+
+extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *);
+
+extern int rtnl_link_register_info(struct rtnl_link_info_ops *);
+extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *);
+
+
+struct rtnl_link_af_ops
+{
+ /** The address family this operations set implements */
+ const unsigned int ao_family;
+
+ /** Number of users of this operations, DO NOT MODIFY. */
+ int ao_refcnt;
+
+ /** Validation policy for IFLA_PROTINFO attribute. This pointer
+ * can be set to a nla_policy structure describing the minimal
+ * requirements the attribute must meet. Failure of meeting these
+ * requirements will result in a parsing error. */
+ const struct nla_policy *ao_protinfo_policy;
+
+ /** Called after address family has been assigned to link. Must
+ * allocate data buffer to hold address family specific data and
+ * store it in link->l_af_data. */
+ void * (*ao_alloc)(struct rtnl_link *);
+
+ /** Called when the link is cloned, must allocate a clone of the
+ * address family specific buffer and return it. */
+ void * (*ao_clone)(struct rtnl_link *, void *);
+
+ /** Called when the link gets freed. Must free all allocated data */
+ void (*ao_free)(struct rtnl_link *, void *);
+
+ /** Called if a IFLA_PROTINFO attribute needs to be parsed. Typically
+ * stores the parsed data in the address family specific buffer. */
+ int (*ao_parse_protinfo)(struct rtnl_link *,
+ struct nlattr *, void *);
+
+ /** Dump address family specific link attributes */
+ void (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
+ struct nl_dump_params *,
+ void *);
+};
+
+extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int);
+extern void rtnl_link_af_ops_put(struct rtnl_link_af_ops *);
+extern int rtnl_link_af_register(struct rtnl_link_af_ops *);
+extern int rtnl_link_af_unregister(struct rtnl_link_af_ops *);
+
+
+#endif
diff --git a/include/netlink/route/link/info-api.h b/include/netlink/route/link/info-api.h
index 7e18e31..4750e18 100644
--- a/include/netlink/route/link/info-api.h
+++ b/include/netlink/route/link/info-api.h
@@ -6,66 +6,15 @@
* 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>
*/
#ifndef NETLINK_LINK_INFO_API_H_
#define NETLINK_LINK_INFO_API_H_
-#include <netlink/netlink.h>
+#warning "<netlink/route/link/info-api.h> is obsolete and may be removed in the future."
+#warning "include <netlink/route/link/api.h> instead.
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @ingroup link_info
- *
- * Link info operations
- */
-struct rtnl_link_info_ops
-{
- /** Name of operations, must match name on kernel side */
- char * io_name;
-
- /** Reference count (internal, do not use) */
- int io_refcnt;
-
- /** Called to assign an info type to a link.
- * Has to allocate enough resources to hold attributes. Can
- * use link->l_info to store a pointer. */
- int (*io_alloc)(struct rtnl_link *);
-
- /** Called to parse the link info attribute.
- * Must parse the attribute and assign all values to the link.
- */
- int (*io_parse)(struct rtnl_link *,
- struct nlattr *,
- struct nlattr *);
-
- /** Called when the link object is dumped.
- * Must dump the info type specific attributes. */
- void (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
- struct nl_dump_params *);
-
- /** Called when a link object is cloned.
- * Must clone all info type specific attributes. */
- int (*io_clone)(struct rtnl_link *, struct rtnl_link *);
-
- /** Called when construction a link netlink message.
- * Must append all info type specific attributes to the message. */
- int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *);
-
- /** Called to release all resources previously allocated
- * in either io_alloc() or io_parse(). */
- void (*io_free)(struct rtnl_link *);
-
- struct rtnl_link_info_ops * io_next;
-};
-
-extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *);
-
-extern int rtnl_link_register_info(struct rtnl_link_info_ops *);
-extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *);
+#include <netlink/route/link/api.h>
#endif
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>