diff options
author | Arend van Spriel <arend@broadcom.com> | 2013-07-15 10:09:11 (GMT) |
---|---|---|
committer | Thomas Graf <tgraf@suug.ch> | 2013-07-18 21:22:18 (GMT) |
commit | e77ea939c44b9d7241d00f8324f63294cc0279c0 (patch) | |
tree | 732ae216ba7880806939ecc4a024139cb7d76d3f /python | |
parent | c08aacc2e8b79d6eb644ae59bb4dc3c6287b8a6b (diff) | |
download | libnl-e77ea939c44b9d7241d00f8324f63294cc0279c0.zip libnl-e77ea939c44b9d7241d00f8324f63294cc0279c0.tar.gz libnl-e77ea939c44b9d7241d00f8324f63294cc0279c0.tar.bz2 |
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>
Diffstat (limited to 'python')
-rw-r--r-- | python/netlink/capi.i | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/python/netlink/capi.i b/python/netlink/capi.i index 73c4bf3..2d2cf0a 100644 --- a/python/netlink/capi.i +++ b/python/netlink/capi.i @@ -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; +} +%} |