libmnl nl-mmap patch review request

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  Hello Pablo, all.
# May you all have a wonderful new year

I found original nl-mmap branch is probably enough and follow them. Would you
revew my patch? 

Two things I've changed to nl-mmap. One is holding frame params for each of TX
and RX ring. Another is adding two functions instead of mnl_socket_set_ring() - 
mnl_socket_set_ringopt() and mnl_socket_map_ring(). I think it's difficult to
notify what's wrong on error in one function.

Any advice is welcome, thanks.

---

 include/libmnl/libmnl.h |  13 ++++
 include/linux/netlink.h |  40 +++++++++-
 src/libmnl.map          |   6 +-
 src/nlmsg.c             |  29 ++++++++
 src/socket.c            | 193 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 276 insertions(+), 5 deletions(-)

diff --git a/include/libmnl/libmnl.h b/include/libmnl/libmnl.h
index 223709c..348cd3c 100644
--- a/include/libmnl/libmnl.h
+++ b/include/libmnl/libmnl.h
@@ -21,8 +21,20 @@ extern "C" {
 
 struct mnl_socket;
 
+enum mnl_ring_types {
+	MNL_RING_RX,
+	MNL_RING_TX,
+};
+
+#define MNL_RING_MSGHDR(hdr) ((void *)(hdr) + NL_MMAP_HDRLEN)
+
 extern struct mnl_socket *mnl_socket_open(int type);
 extern int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid);
+extern int mnl_socket_set_ringopt(struct mnl_socket *nl, struct nl_mmap_req *req,
+				  enum mnl_ring_types type);
+extern int mnl_socket_map_ring(struct mnl_socket *nl);
+extern struct nl_mmap_hdr *mnl_socket_get_frame(const struct mnl_socket *nl, enum mnl_ring_types type);
+extern int mnl_socket_advance_ring(const struct mnl_socket *nl, enum mnl_ring_types type);
 extern int mnl_socket_close(struct mnl_socket *nl);
 extern int mnl_socket_get_fd(const struct mnl_socket *nl);
 extern unsigned int mnl_socket_get_portid(const struct mnl_socket *nl);
@@ -74,6 +86,7 @@ extern void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b);
 extern void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b);
 extern void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b);
 extern bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b);
+extern void mnl_nlmsg_batch_reset_buffer(struct mnl_nlmsg_batch *b, void *buf, size_t limit);
 
 /*
  * Netlink attributes API
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index ced0e1a..1a85940 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -1,6 +1,7 @@
-#ifndef __LINUX_NETLINK_H
-#define __LINUX_NETLINK_H
+#ifndef _UAPI__LINUX_NETLINK_H
+#define _UAPI__LINUX_NETLINK_H
 
+#include <linux/kernel.h>
 #include <linux/socket.h> /* for __kernel_sa_family_t */
 #include <linux/types.h>
 
@@ -78,7 +79,7 @@ struct nlmsghdr {
 #define NLMSG_ALIGNTO	4U
 #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
 #define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
 #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
 #define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
 #define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
@@ -105,11 +106,42 @@ struct nlmsgerr {
 #define NETLINK_PKTINFO		3
 #define NETLINK_BROADCAST_ERROR	4
 #define NETLINK_NO_ENOBUFS	5
+#define NETLINK_RX_RING		6
+#define NETLINK_TX_RING		7
 
 struct nl_pktinfo {
 	__u32	group;
 };
 
+struct nl_mmap_req {
+	unsigned int	nm_block_size;
+	unsigned int	nm_block_nr;
+	unsigned int	nm_frame_size;
+	unsigned int	nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+	unsigned int	nm_status;
+	unsigned int	nm_len;
+	__u32		nm_group;
+	/* credentials */
+	__u32		nm_pid;
+	__u32		nm_uid;
+	__u32		nm_gid;
+};
+
+enum nl_mmap_status {
+	NL_MMAP_STATUS_UNUSED,
+	NL_MMAP_STATUS_RESERVED,
+	NL_MMAP_STATUS_VALID,
+	NL_MMAP_STATUS_COPY,
+	NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT		NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz)		__ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN			NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
 #define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
 
 enum {
@@ -150,4 +182,4 @@ struct nlattr {
 #define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
 
 
-#endif /* __LINUX_NETLINK_H */
+#endif /* _UAPI__LINUX_NETLINK_H */
diff --git a/src/libmnl.map b/src/libmnl.map
index dbc332e..26269c2 100644
--- a/src/libmnl.map
+++ b/src/libmnl.map
@@ -65,10 +65,14 @@ global:
   mnl_socket_recvfrom;
   mnl_socket_sendto;
   mnl_socket_setsockopt;
-
 local: *;
 };
 
 LIBMNL_1.1 {
   mnl_attr_parse_payload;
+  mnl_socket_set_ringopt;
+  mnl_socket_map_ring;
+  mnl_socket_get_frame;
+  mnl_socket_advance_ring;
+  mnl_nlmsg_batch_reset_buffer;
 } LIBMNL_1.0;
diff --git a/src/nlmsg.c b/src/nlmsg.c
index fdb7af8..5dbe1ba 100644
--- a/src/nlmsg.c
+++ b/src/nlmsg.c
@@ -569,5 +569,34 @@ bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
 EXPORT_SYMBOL(mnl_nlmsg_batch_is_empty);
 
 /**
+ * mnl_nlmsg_batch_reset_buffer - reset to the new buffer
+ * \param buf pointer to the new (mmaped tx frame) buffer that will store this
+ *        batch
+ * \param limit maximum size of the batch (should be half of
+ *        nl_mmap_req.frame_size)
+ *
+ * This function is for mmap tx frame, allows to set new buffer (frame) and
+ * reset a batch, so you can reuse it to create a new one. This function moves
+ * the last message which does not fit the batch to the head of the new buffer,
+ * if any.
+ */
+void mnl_nlmsg_batch_reset_buffer(struct mnl_nlmsg_batch *b, void *buf, size_t limit)
+{
+	if (b->overflow) {
+		struct nlmsghdr *nlh = b->cur;
+		memcpy(buf, b->cur, nlh->nlmsg_len);
+		b->buflen = nlh->nlmsg_len;
+		b->cur = buf + b->buflen;
+		b->overflow = false;
+	} else {
+		b->buflen = 0;
+		b->cur = buf;
+	}
+	b->buf = buf;
+	b->limit = limit;
+}
+EXPORT_SYMBOL(mnl_nlmsg_batch_reset_buffer);
+
+/**
  * @}
  */
diff --git a/src/socket.c b/src/socket.c
index 676a08a..f68047d 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -10,6 +10,7 @@
 #include <libmnl/libmnl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/mman.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <time.h>
@@ -66,9 +67,19 @@
  * code tree.
  */
 
+struct mnl_ring {
+	unsigned int		head;
+	void			*ring;
+	unsigned int		frame_size;
+	unsigned int		frame_max;
+	unsigned int		block_size;
+};
+
 struct mnl_socket {
 	int 			fd;
 	struct sockaddr_nl	addr;
+	struct mnl_ring		*rx_ring;
+	struct mnl_ring		*tx_ring;
 };
 
 /**
@@ -168,6 +179,184 @@ int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
 }
 EXPORT_SYMBOL(mnl_socket_bind);
 
+static inline struct mnl_ring *get_mnl_ring(const struct mnl_socket *nl, enum mnl_ring_types type)
+{
+	struct mnl_ring *ring;
+
+	switch (type) {
+	case MNL_RING_RX:
+		ring = nl->rx_ring;
+		break;
+	case MNL_RING_TX:
+		ring = nl->tx_ring;
+		break;
+	default:
+		errno = EINVAL;
+		return NULL;
+		break;
+	}
+	if (ring == NULL || ring->ring == NULL) {
+		errno = EBADR;
+		return NULL;
+	}
+	return ring;
+}
+
+static struct mnl_ring *alloc_ring(const struct nl_mmap_req *req)
+{
+	struct mnl_ring *ring;
+
+	ring = calloc(sizeof(struct mnl_ring), 1);
+	if (ring == NULL)
+		return NULL;
+
+	ring->frame_size	= req->nm_frame_size;
+	ring->frame_max		= req->nm_frame_nr - 1;
+	ring->block_size	= req->nm_block_size;
+
+	return ring;
+}
+
+/**
+ * mnl_socket_set_ringopt - set ring opt to prepare for mnl_socket_map_ring()
+ * \param nl netlink socket obtained via mnl_socket_open()
+ * \param req setsockopt param for ring
+ * \param type ring type either MNL_RING_RX or MNL_RING_TX
+ *
+ * On success, 0 is returned. On error, this function returns -1, errno is
+ * appropriately set.
+ */
+int mnl_socket_set_ringopt(struct mnl_socket *nl, struct nl_mmap_req *req,
+			   enum mnl_ring_types type)
+{
+	int optype, pre_errno, ret;
+	struct mnl_ring **ring;
+
+	switch (type) {
+	case MNL_RING_RX:
+		ring = &nl->rx_ring;
+		optype = NETLINK_RX_RING;
+		break;
+	case MNL_RING_TX:
+		ring = &nl->tx_ring;
+		optype = NETLINK_TX_RING;
+		break;
+	default:
+		errno = EINVAL;
+		return -1;
+		break;
+	}
+
+	if (*ring != NULL) {
+		errno = EALREADY;
+		return -1;
+	}
+	*ring = alloc_ring(req);
+	if (*ring == NULL)
+		return -1;
+
+	ret = mnl_socket_setsockopt(nl, optype, req, sizeof(*req));
+	if (ret == -1) {
+		pre_errno = errno;
+		free(*ring);
+		*ring = NULL;
+		errno = pre_errno;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(mnl_socket_set_ringopt);
+
+/**
+ * mnl_socket_map_ring - setup a ring for mnl_socket
+ * \param nl netlink socket obtained via mnl_socket_open()
+ *
+ * This function must be called after setting up by mnl_socket_set_ringopt().
+ * On success, 0 is returned. On error, this function returns -1, errno is
+ * appropriately set and req parameter
+ */
+int mnl_socket_map_ring(struct mnl_socket *nl)
+{
+	size_t rx_size = 0, tx_size = 0;
+	struct mnl_ring *rx_ring = nl->tx_ring, *tx_ring = nl->tx_ring;
+	void *ring;
+
+	if (rx_ring == NULL && tx_ring == NULL) {
+		errno = EBADR;
+		return -1;
+	}
+
+	if (rx_ring != NULL)
+		rx_size = ((rx_ring->frame_max + 1) * rx_ring->frame_size + rx_ring->block_size - 1)
+			& ~(rx_ring->block_size - 1);
+	if (tx_ring != NULL)
+		tx_size = ((tx_ring->frame_max + 1) * tx_ring->frame_size + tx_ring->block_size - 1)
+			& ~(tx_ring->block_size - 1);
+	ring = mmap(NULL, tx_size + rx_size, PROT_READ | PROT_WRITE, MAP_SHARED, nl->fd, 0);
+	if (ring == MAP_FAILED)
+		return -1;
+
+	if (rx_ring != NULL && tx_ring != NULL) {
+		nl->rx_ring->ring = ring;
+		nl->tx_ring->ring = ring + rx_size;
+	} else if (rx_ring != NULL) {
+		nl->rx_ring->ring = ring;
+	} else {
+		nl->tx_ring->ring = ring;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(mnl_socket_map_ring);
+
+/**
+ * mnl_socket_get_frame - get current frame
+ * \param nl netlink socket obtained via mnl_socket_open()
+ * \param type ring type either MNL_RING_RX or MNL_RING_TX
+ *
+ * On error, it returns NULL and errno is appropriately set. Otherwise, this
+ * function returns the current nl_mmap_hdr frame in the ring specified by type
+ * - MNL_RING_RX for receiving or MNL_RING_TX for sending.
+ */
+struct nl_mmap_hdr *mnl_socket_get_frame(const struct mnl_socket *nl,
+					 enum mnl_ring_types type)
+{
+	unsigned int frames_per_block, block_pos, frame_off;
+	struct mnl_ring *ring;
+
+	ring = get_mnl_ring(nl, type);
+	if (ring == NULL)
+		return NULL;
+
+	frames_per_block = ring->block_size / ring->frame_size;
+	block_pos = ring->head / frames_per_block;
+	frame_off = ring->head % frames_per_block;
+
+	return (struct nl_mmap_hdr *)(ring->ring + block_pos * ring->block_size + frame_off * ring->frame_size);
+}
+EXPORT_SYMBOL(mnl_socket_get_frame);
+
+/**
+ * mnl_socket_advance_ring - set forward frame pointer
+ * \param nl netlink socket obtained via mnl_socket_open()
+ * \param type ring type either MNL_RING_RX or MNL_RING_TX
+ *
+ * On error, this function returns -1 and errno is appropriately set. On
+ * success, 0 is returned.
+ */
+int mnl_socket_advance_ring(const struct mnl_socket *nl, enum mnl_ring_types type)
+{
+	struct mnl_ring *ring;
+
+	ring = get_mnl_ring(nl, type);
+	if (ring == NULL)
+		return -1;
+
+	ring->head = ring->head != ring->frame_max ? ring->head + 1 : 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(mnl_socket_advance_ring);
+
 /**
  * mnl_socket_sendto - send a netlink message of a certain size
  * \param nl netlink socket obtained via mnl_socket_open()
@@ -246,6 +435,10 @@ EXPORT_SYMBOL(mnl_socket_recvfrom);
 int mnl_socket_close(struct mnl_socket *nl)
 {
 	int ret = close(nl->fd);
+	if (nl->rx_ring)
+		free(nl->rx_ring);
+	if (nl->tx_ring)
+		free(nl->tx_ring);
 	free(nl);
 	return ret;
 }
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux