summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2011-04-11 12:34:01 +0200
committerThomas Graf <tgraf@suug.ch>2011-04-11 12:34:01 +0200
commit48d543cfdf49aef75b9898ebea379f2303d3935d (patch)
treeea0a9aa79176d18d5d94a4e28c7a5d55e6bafefe
parent41fb241b7bb88d10300145778e401ab34e3bf46b (diff)
downloadlibnl-48d543cfdf49aef75b9898ebea379f2303d3935d.tar.gz
API to issue direct GET requests to the kernel
Provide nl_pickup() to pick up an answer from a netlink request and parse it using the supplied parser. Add rtnl_link_get_kernel() which sends an RTM_GETLINK to the kernel to fetch a single link directly from the kernel. This can be faster than dumping the whole table, especially if lots of links are configured.
-rw-r--r--include/netlink/netlink.h8
-rw-r--r--include/netlink/route/link.h4
-rw-r--r--lib/nl.c70
-rw-r--r--lib/route/link.c93
4 files changed, 174 insertions, 1 deletions
diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h
index a13c48f..0768708 100644
--- a/include/netlink/netlink.h
+++ b/include/netlink/netlink.h
@@ -31,6 +31,8 @@
#include <netlink/types.h>
#include <netlink/handlers.h>
#include <netlink/socket.h>
+#include <netlink/object.h>
+#include <netlink/cache-api.h>
#ifdef __cplusplus
extern "C" {
@@ -74,6 +76,12 @@ extern int nl_recvmsgs_default(struct nl_sock *);
extern int nl_wait_for_ack(struct nl_sock *);
+extern int nl_pickup(struct nl_sock *,
+ int (*parser)(struct nl_cache_ops *,
+ struct sockaddr_nl *,
+ struct nlmsghdr *,
+ struct nl_parser_param *),
+ struct nl_object **);
/* Netlink Family Translations */
extern char * nl_nlfamily2str(int, char *, size_t);
extern int nl_str2nlfamily(const char *);
diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h
index b9951d6..3790c09 100644
--- a/include/netlink/route/link.h
+++ b/include/netlink/route/link.h
@@ -105,6 +105,10 @@ extern int rtnl_link_change(struct nl_sock *, struct rtnl_link *,
extern int rtnl_link_build_delete_request(const struct rtnl_link *,
struct nl_msg **);
extern int rtnl_link_delete(struct nl_sock *, const struct rtnl_link *);
+extern int rtnl_link_build_get_request(int, const char *,
+ struct nl_msg **);
+extern int rtnl_link_get_kernel(struct nl_sock *, int, const char *,
+ struct rtnl_link **);
/* Name <-> Index Translations */
extern char * rtnl_link_i2name(struct nl_cache *, int, char *, size_t);
diff --git a/lib/nl.c b/lib/nl.c
index b70242c..f5f94e3 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -799,6 +799,76 @@ int nl_wait_for_ack(struct nl_sock *sk)
return err;
}
+/** @cond SKIP */
+struct pickup_param
+{
+ int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+ struct nlmsghdr *, struct nl_parser_param *);
+ struct nl_object *result;
+};
+
+static int __store_answer(struct nl_object *obj, struct nl_parser_param *p)
+{
+ struct pickup_param *pp = p->pp_arg;
+ /*
+ * the parser will put() the object at the end, expecting the cache
+ * to take the reference.
+ */
+ nl_object_get(obj);
+ pp->result = obj;
+
+ return 0;
+}
+
+static int __pickup_answer(struct nl_msg *msg, void *arg)
+{
+ struct pickup_param *pp = arg;
+ struct nl_parser_param parse_arg = {
+ .pp_cb = __store_answer,
+ .pp_arg = pp,
+ };
+
+ return pp->parser(NULL, &msg->nm_src, msg->nm_nlh, &parse_arg);
+}
+
+/** @endcond */
+
+/**
+ * Pickup netlink answer, parse is and return object
+ * @arg sk Netlink socket
+ * @arg parser Parser function to parse answer
+ * @arg result Result pointer to return parsed object
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_pickup(struct nl_sock *sk,
+ int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+ struct nlmsghdr *, struct nl_parser_param *),
+ struct nl_object **result)
+{
+ struct nl_cb *cb;
+ int err;
+ struct pickup_param pp = {
+ .parser = parser,
+ };
+
+ cb = nl_cb_clone(sk->s_cb);
+ if (cb == NULL)
+ return -NLE_NOMEM;
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __pickup_answer, &pp);
+
+ err = nl_recvmsgs(sk, cb);
+ if (err < 0)
+ goto errout;
+
+ *result = pp.result;
+errout:
+ nl_cb_put(cb);
+
+ return err;
+}
+
/** @} */
/** @} */
diff --git a/lib/route/link.c b/lib/route/link.c
index 6ecde1d..38b9d82 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -655,7 +655,6 @@ static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
{
char buf[128];
- struct nl_cache *cache = dp_cache(obj);
struct rtnl_link *link = (struct rtnl_link *) obj;
nl_dump_line(p, "%s %s ", link->l_name,
@@ -1244,6 +1243,98 @@ int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
return nl_send_sync(sk, msg);
}
+
+/**
+ * Build a netlink message requesting a link
+ * @arg ifindex Interface index
+ * @arg name Name of link
+ * @arg result Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_get_kernel()
+ * with the exception that it will not send the message but return it in
+ * the provided return pointer instead.
+ *
+ * @see rtnl_link_get_kernel()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_get_request(int ifindex, const char *name,
+ struct nl_msg **result)
+{
+ struct ifinfomsg ifi;
+ struct nl_msg *msg;
+
+ if (ifindex <= 0 && !name) {
+ APPBUG("ifindex or name must be specified");
+ return -NLE_MISSING_ATTR;
+ }
+
+ memset(&ifi, 0, sizeof(ifi));
+
+ if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0)))
+ return -NLE_NOMEM;
+
+ if (ifindex > 0)
+ ifi.ifi_index = ifindex;
+
+ if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (name)
+ NLA_PUT_STRING(msg, IFLA_IFNAME, name);
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * Get a link object directly from the kernel
+ * @arg sk Netlink socket
+ * @arg ifindex Interface index
+ * @arg name name of link
+ * @arg result result pointer to return link object
+ *
+ * This function builds a \c RTM_GETLINK netlink message to request
+ * a specific link directly from the kernel. The returned answer is
+ * parsed into a struct rtnl_link object and returned via the result
+ * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
+ * found.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ * this function to return immediately after sending. In this case,
+ * it is the responsibility of the caller to handle any error
+ * messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
+ struct rtnl_link **result)
+{
+ struct nl_msg *msg = NULL;
+ struct nl_object *obj;
+ int err;
+
+ if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
+ return err;
+
+ /* We have used link_msg_parser(), object is definitely a link */
+ *result = (struct rtnl_link *) obj;
+
+ return 0;
+}
+
/** @} */
/**