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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).