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.
This commit is contained in:
parent
41fb241b7b
commit
48d543cfdf
4 changed files with 174 additions and 1 deletions
|
@ -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 *);
|
||||
|
|
|
@ -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);
|
||||
|
|
70
lib/nl.c
70
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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue