]> granicus.if.org Git - libnl/commitdiff
add support functions for attributes and callback handlers
authorArend van Spriel <arend@broadcom.com>
Mon, 15 Jul 2013 10:09:11 +0000 (12:09 +0200)
committerThomas Graf <tgraf@suug.ch>
Thu, 18 Jul 2013 21:22:18 +0000 (23:22 +0200)
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>
python/netlink/capi.i

index 73c4bf31f93e2879507f16583bc16285c4274870..2d2cf0a34acd1dfaf20662db9b2c3443acfc1523 100644 (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;
+}
+%}