From: Ken-ichirou MATSUZAWA <chamaken@gmail.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>, netfilter-devel@vger.kernel.org
Subject: libmnl nl-mmap patch review request
Date: Wed, 01 Jan 2014 19:07:52 +0900 [thread overview]
Message-ID: <87zjngow07.wl%chamaken@gmail.com> (raw)
In-Reply-To: 87txek8ztc.wl%chamaken@gmail.com
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;
}
prev parent reply other threads:[~2014-01-01 10:08 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-07 15:07 [libmnl PATCH 0/9] mmaped netlink Ken-ichirou MATSUZAWA
2014-01-01 10:07 ` Ken-ichirou MATSUZAWA [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87zjngow07.wl%chamaken@gmail.com \
--to=chamaken@gmail.com \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.