add support functions for attributes and callback handlers

added support functions to access the netlink attributes and use
custom callback handlers. Most is wrapped as is, but there are
a couple of special cases handled.

1) void *nla_data(struct nlattr *);
The return value is changed to a Python byte array so it includes
the lenght of the data stream.

2) int nla_parse_nested(...);
This returns a tuple (err, dict). 'err' is the error code and 'dict'
is a dictionary with attribute identifier as key and value represents
a struct nlattr object.

3) macro nla_for_each_nested()
Provide nla_get_nested() which returns a Python list of struct nlattr
objects that is iterable.

4) allocate struct nla_policy array
Provide nla_policy_array() function that allocates consecutive space
in memory for struct nla_policy array entries. Each entry is put in
a Python list so the entry fields can be modified in Python. This
array object can be passed to the nla_parse_nested() function.

Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Thomas Graf <tgraf@suug.ch>
This commit is contained in:
Arend van Spriel 2013-07-15 12:09:11 +02:00 committed by Thomas Graf
parent c08aacc2e8
commit e77ea939c4

View file

@ -6,10 +6,13 @@
#include <netlink/msg.h>
#include <netlink/object.h>
#include <netlink/cache.h>
#include <netlink/attr.h>
#include <net/if.h>
%}
%include <stdint.i>
%include <cstring.i>
%include <cpointer.i>
%inline %{
struct nl_dump_params *alloc_dump_params(void)
@ -113,6 +116,9 @@ struct nl_dump_params
unsigned int dp_line;
};
/* <net/if.h> */
extern unsigned int if_nametoindex(const char *ifname);
/* <netlink/errno.h> */
extern const char *nl_geterror(int);
@ -175,6 +181,10 @@ extern uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk);
extern void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups);
extern int nl_socket_set_buffer_size(struct nl_sock *, int, int);
extern void nl_socket_set_cb(struct nl_sock *, struct nl_cb *);
extern int nl_send_auto_complete(struct nl_sock *, struct nl_msg *);
extern int nl_recvmsgs(struct nl_sock *, struct nl_cb *);
/* <netlink/msg.h> */
extern int nlmsg_size(int);
@ -452,3 +462,366 @@ extern int nl_str2af(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_addr2str(struct nl_addr *, char *buf, size_t len);
/* Message Handlers <netlink/handlers.h> */
/**
* Callback actions
* @ingroup cb
*/
enum nl_cb_action {
/** Proceed with wathever would come next */
NL_OK,
/** Skip this message */
NL_SKIP,
/** Stop parsing altogether and discard remaining messages */
NL_STOP,
};
/**
* Callback kinds
* @ingroup cb
*/
enum nl_cb_kind {
/** Default handlers (quiet) */
NL_CB_DEFAULT,
/** Verbose default handlers (error messages printed) */
NL_CB_VERBOSE,
/** Debug handlers for debugging */
NL_CB_DEBUG,
/** Customized handler specified by the user */
NL_CB_CUSTOM,
__NL_CB_KIND_MAX,
};
#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1)
/**
* Callback types
* @ingroup cb
*/
enum nl_cb_type {
/** Message is valid */
NL_CB_VALID,
/** Last message in a series of multi part messages received */
NL_CB_FINISH,
/** Report received that data was lost */
NL_CB_OVERRUN,
/** Message wants to be skipped */
NL_CB_SKIPPED,
/** Message is an acknowledge */
NL_CB_ACK,
/** Called for every message received */
NL_CB_MSG_IN,
/** Called for every message sent out except for nl_sendto() */
NL_CB_MSG_OUT,
/** Message is malformed and invalid */
NL_CB_INVALID,
/** Called instead of internal sequence number checking */
NL_CB_SEQ_CHECK,
/** Sending of an acknowledge message has been requested */
NL_CB_SEND_ACK,
/** Flag NLM_F_DUMP_INTR is set in message */
NL_CB_DUMP_INTR,
__NL_CB_TYPE_MAX,
};
#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1)
extern struct nl_cb *nl_cb_alloc(enum nl_cb_kind);
extern struct nl_cb *nl_cb_clone(struct nl_cb *);
extern struct nl_cb *nl_cb_get(struct nl_cb *);
extern void nl_cb_put(struct nl_cb *);
struct nlmsgerr {
int error;
};
%{
/**
* nl_recvmsgs() callback for message processing customization
* @ingroup cb
* @arg msg netlink message being processed
* @arg arg argument passwd on through caller
*/
typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
/**
* nl_recvmsgs() callback for error message processing customization
* @ingroup cb
* @arg nla netlink address of the peer
* @arg nlerr netlink error message being processed
* @arg arg argument passed on through caller
*/
typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla,
struct nlmsgerr *nlerr, void *arg);
struct pynl_callback {
PyObject *cbf;
PyObject *cba;
};
static int nl_recv_msg_handler(struct nl_msg *msg, void *arg)
{
struct pynl_callback *cbd = arg;
PyObject *msgobj;
PyObject *cbparobj;
PyObject *resobj;
int result;
if (!cbd)
return NL_STOP;
msgobj = SWIG_NewPointerObj(SWIG_as_voidptr(msg),
SWIGTYPE_p_nl_msg, 0 | 0 );
cbparobj = Py_BuildValue("(OO)", msgobj, cbd->cba);
resobj = PyObject_CallObject(cbd->cbf, cbparobj);
Py_DECREF(cbparobj);
if (resobj == NULL)
return NL_STOP;
if (!PyArg_ParseTuple(resobj, "i:nl_recv_msg_handler", &result))
result = NL_STOP;
Py_DECREF(resobj);
return result;
}
static int nl_recv_err_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
void *arg)
{
struct pynl_callback *cbd = arg;
PyObject *errobj;
PyObject *cbparobj;
PyObject *resobj;
int result;
if (!cbd)
return NL_STOP;
errobj = SWIG_NewPointerObj(SWIG_as_voidptr(err),
SWIGTYPE_p_nlmsgerr, 0 | 0 );
cbparobj = Py_BuildValue("(OO)", errobj, cbd->cba);
resobj = PyObject_CallObject(cbd->cbf, cbparobj);
Py_DECREF(cbparobj);
if (resobj == NULL)
return NL_STOP;
result = (int)PyInt_AsLong(resobj);
Py_DECREF(resobj);
printf("error: err=%d ret=%d\n", err->error, result);
return result;
}
%}
%inline %{
int py_nl_cb_set(struct nl_cb *cb, enum nl_cb_type t, enum nl_cb_kind k,
PyObject *func, PyObject *a)
{
struct pynl_callback *cbd;
if (k == NL_CB_CUSTOM) {
cbd = calloc(1, sizeof(*cbd));
Py_XINCREF(func);
Py_XINCREF(a);
cbd->cbf = func;
cbd->cba = a;
return nl_cb_set(cb, t, k, nl_recv_msg_handler, cbd);
}
return nl_cb_set(cb, t, k, NULL, NULL);
}
int py_nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind k,
PyObject *func , PyObject *a)
{
struct pynl_callback *cbd;
if (k == NL_CB_CUSTOM) {
cbd = calloc(1, sizeof(*cbd));
Py_XINCREF(func);
Py_XINCREF(a);
cbd->cbf = func;
cbd->cba = a;
return nl_cb_set_all(cb, k, nl_recv_msg_handler, cbd);
}
return nl_cb_set_all(cb, k, NULL, NULL);
}
int py_nl_cb_err(struct nl_cb *cb, enum nl_cb_kind k,
PyObject *func, PyObject *a)
{
struct pynl_callback *cbd;
if (k == NL_CB_CUSTOM) {
cbd = calloc(1, sizeof(*cbd));
Py_XINCREF(func);
Py_XINCREF(a);
cbd->cbf = func;
cbd->cba = a;
return nl_cb_err(cb, k, nl_recv_err_handler, cbd);
}
return nl_cb_err(cb, k, NULL, NULL);
}
%}
/* Attributes <netlink/attr.h> */
/*
* This typemap is a bit tricky as it uses arg1, which is knowledge about
* the SWIGged wrapper output.
*/
%typemap(out) void * {
$result = PyByteArray_FromStringAndSize($1, nla_len(arg1));
}
extern void *nla_data(struct nlattr *);
%typemap(out) void *;
extern int nla_type(const struct nlattr *);
/* Integer attribute */
extern uint8_t nla_get_u8(struct nlattr *);
extern int nla_put_u8(struct nl_msg *, int, uint8_t);
extern uint16_t nla_get_u16(struct nlattr *);
extern int nla_put_u16(struct nl_msg *, int, uint16_t);
extern uint32_t nla_get_u32(struct nlattr *);
extern int nla_put_u32(struct nl_msg *, int, uint32_t);
extern uint64_t nla_get_u64(struct nlattr *);
extern int nla_put_u64(struct nl_msg *, int, uint64_t);
/* String attribute */
extern char * nla_get_string(struct nlattr *);
extern char * nla_strdup(struct nlattr *);
extern int nla_put_string(struct nl_msg *, int, const char *);
/* Flag attribute */
extern int nla_get_flag(struct nlattr *);
extern int nla_put_flag(struct nl_msg *, int);
/* Msec attribute */
extern unsigned long nla_get_msecs(struct nlattr *);
extern int nla_put_msecs(struct nl_msg *, int, unsigned long);
/* Attribute nesting */
extern int nla_put_nested(struct nl_msg *, int, struct nl_msg *);
extern struct nlattr * nla_nest_start(struct nl_msg *, int);
extern int nla_nest_end(struct nl_msg *, struct nlattr *);
%inline %{
PyObject *py_nla_parse_nested(int max, struct nlattr *nest_attr, PyObject *p)
{
struct nlattr *tb_msg[max + 1];
struct nla_policy *policy = NULL;
void *pol;
PyObject *attrs = Py_None;
PyObject *k;
PyObject *v;
PyObject *resobj;
int err;
int i;
if (p != Py_None) {
PyObject *pobj;
if (!PyList_Check(p)) {
fprintf(stderr, "expected list object\n");
err = -1;
goto fail;
}
pobj = PyList_GetItem(p, 0);
err = SWIG_ConvertPtr(pobj, &pol, SWIGTYPE_p_nla_policy, 0 | 0 );
if (!SWIG_IsOK(err))
goto fail;
policy = pol;
}
err = nla_parse_nested(tb_msg, max, nest_attr, policy);
if (err < 0) {
fprintf(stderr, "Failed to parse response message\n");
} else {
attrs = PyDict_New();
for (i = 0; i <= max; i++)
if (tb_msg[i]) {
k = PyInt_FromLong((long)i);
v = SWIG_NewPointerObj(SWIG_as_voidptr(tb_msg[i]), SWIGTYPE_p_nlattr, 0 | 0 );
PyDict_SetItem(attrs, k, v);
}
}
fail:
if (attrs == Py_None)
Py_INCREF(attrs);
resobj = Py_BuildValue("(iO)", err, attrs);
return resobj;
}
/*
* nla_get_nested() - get list of nested attributes.
*
* nla_for_each_<nested|attr>() is a macro construct that needs another approach
* for Python. Create and return list of nested attributes.
*/
PyObject *nla_get_nested(struct nlattr *nest_attr)
{
PyObject *listobj;
PyObject *nestattrobj;
struct nlattr *pos;
int rem;
listobj = PyList_New(0);
nla_for_each_nested(pos, nest_attr, rem) {
nestattrobj = SWIG_NewPointerObj(SWIG_as_voidptr(pos),
SWIGTYPE_p_nlattr, 0 | 0 );
PyList_Append(listobj, nestattrobj);
}
return listobj;
}
%}
/**
* @ingroup attr
* Basic attribute data types
*
* See \ref attr_datatypes for more details.
*/
enum {
NLA_UNSPEC, /**< Unspecified type, binary data chunk */
NLA_U8, /**< 8 bit integer */
NLA_U16, /**< 16 bit integer */
NLA_U32, /**< 32 bit integer */
NLA_U64, /**< 64 bit integer */
NLA_STRING, /**< NUL terminated character string */
NLA_FLAG, /**< Flag */
NLA_MSECS, /**< Micro seconds (64bit) */
NLA_NESTED, /**< Nested attributes */
__NLA_TYPE_MAX,
};
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
/** @} */
/**
* @ingroup attr
* Attribute validation policy.
*
* See \ref attr_datatypes for more details.
*/
struct nla_policy {
/** Type of attribute or NLA_UNSPEC */
uint16_t type;
/** Minimal length of payload required */
uint16_t minlen;
/** Maximal length of payload allowed */
uint16_t maxlen;
};
%inline %{
PyObject *nla_policy_array(int n_items)
{
struct nla_policy *policies;
PyObject *listobj;
PyObject *polobj;
int i;
policies = calloc(n_items, sizeof(*policies));
listobj = PyList_New(n_items);
for (i = 0; i < n_items; i++) {
polobj = SWIG_NewPointerObj(SWIG_as_voidptr(&policies[i]),
SWIGTYPE_p_nla_policy, 0 | 0 );
PyList_SetItem(listobj, i, polobj);
}
return listobj;
}
%}