[PATCH 1/3] add support functions for attributes and callback handlers

Arend van Spriel arend at broadcom.com
Mon Jul 15 06:09:11 EDT 2013


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 at broadcom.com>
---
 python/netlink/capi.i |  373 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 373 insertions(+)

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;
+}
+%}
-- 
1.7.10.4





More information about the libnl mailing list