]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
API to issue direct GET requests to the kernel
authorThomas Graf <tgraf@suug.ch>
Mon, 11 Apr 2011 10:34:01 +0000 (12:34 +0200)
committerThomas Graf <tgraf@suug.ch>
Mon, 11 Apr 2011 10:34:01 +0000 (12:34 +0200)
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.

include/netlink/netlink.h
include/netlink/route/link.h
lib/nl.c
lib/route/link.c

index a13c48fc4aac10faf9830b40b7f793a711ed947a..07687083c09e988dc9cc7ebbcf1fc3c8d0c2377b 100644 (file)
@@ -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 *);
index b9951d6e5d345a4c80e7624a1a9cba4cc0aea330..3790c09574b6bb6584128f8bebfa6b87c349ecdb 100644 (file)
@@ -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);
index b70242ceca91ceae78da43b417867b1121d44ec3..f5f94e30e5e5a9dcee5d3049a3e032d345f96d7a 100644 (file)
--- 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;
+}
+
 /** @} */
 
 /** @} */
index 6ecde1d551a478ecacd776e0c05c6b5bb16953cf..38b9d82f53c636d0cce03208a364fc243ae410f2 100644 (file)
@@ -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;
+}
+
 /** @} */
 
 /**