* [libmnl PATCH 2/9] mmap: initial
@ 2013-12-07 15:09 Ken-ichirou MATSUZAWA
0 siblings, 0 replies; only message in thread
From: Ken-ichirou MATSUZAWA @ 2013-12-07 15:09 UTC (permalink / raw)
To: Pablo Neira Ayuso, netfilter-devel
Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
include/libmnl/libmnl.h | 44 ++++++++++
src/Makefile.am | 2 +-
src/libmnl.map | 7 ++
src/mmap.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 279 insertions(+), 1 deletion(-)
create mode 100644 src/mmap.c
diff --git a/include/libmnl/libmnl.h b/include/libmnl/libmnl.h
index 223709c..11abb04 100644
--- a/include/libmnl/libmnl.h
+++ b/include/libmnl/libmnl.h
@@ -180,6 +180,50 @@ extern int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len);
/*
+ * mmapped API
+ */
+
+/*
+ * ring contains #nr blocks, block contains #nr frames
+ * ring size == nm_block_size * nm_block_nr
+ * == nm_frame_size * nm_frame_nr
+ *
+ * frames per block: nm_block_size / nm_frame_size
+ * nm_frame_nr : frames per block * nm_block_nr
+ * nm_block_size : n * getpagesize()
+ * nm_frame_size : >= NL_MMAP_HDRLEN to hold at least the frame header
+ * nm_frame_size : <= nm_block_size
+ */
+#define MNL_MMAP_DEFAULT_REQ { \
+ .nm_block_size = MNL_SOCKET_BUFFER_SIZE * 16, \
+ .nm_block_nr = 64, \
+ .nm_frame_size = 16384, \
+ .nm_frame_nr = 64 * MNL_SOCKET_BUFFER_SIZE * 16 / 16384, \
+}
+
+#define MNL_MMAP_SMALL_REQ { \
+ .nm_block_size = getpagesize(), \
+ .nm_block_nr = 4, \
+ .nm_frame_size = getpagesize() / 2, \
+ .nm_frame_nr = (4 * getpagesize()) / (getpagesize() / 2), \
+}
+
+#define MNL_MMAP_MSGHDR(nlmhdr) ((void *)(nlmhdr) + NL_MMAP_HDRLEN)
+
+enum mnl_ring_types {
+ MNL_RING_RX,
+ MNL_RING_TX,
+};
+
+struct mnl_ring_socket;
+
+extern struct mnl_ring_socket *
+mnl_ring_map(const struct mnl_socket *nl, struct nl_mmap_req *tx_req, struct nl_mmap_req *rx_req);
+extern int mnl_ring_unmap(struct mnl_ring_socket *nlm);
+extern struct nl_mmap_hdr *mnl_ring_get_frame(struct mnl_ring_socket *nlm, enum mnl_ring_types type);
+extern int mnl_ring_advance(struct mnl_ring_socket *nlm, enum mnl_ring_types type);
+
+/*
* other declarations
*/
diff --git a/src/Makefile.am b/src/Makefile.am
index 9aab516..f97958c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,4 +2,4 @@ include $(top_srcdir)/Make_global.am
lib_LTLIBRARIES = libmnl.la
libmnl_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmnl.map -version-info $(LIBVERSION)
-libmnl_la_SOURCES = socket.c callback.c nlmsg.c attr.c internal.h libmnl.map
+libmnl_la_SOURCES = socket.c callback.c nlmsg.c attr.c mmap.c internal.h libmnl.map
diff --git a/src/libmnl.map b/src/libmnl.map
index dbc332e..73de08f 100644
--- a/src/libmnl.map
+++ b/src/libmnl.map
@@ -72,3 +72,10 @@ local: *;
LIBMNL_1.1 {
mnl_attr_parse_payload;
} LIBMNL_1.0;
+
+LIBMNL_1.2 {
+ mnl_ring_map;
+ mnl_ring_unmap;
+ mnl_ring_get_frame;
+ mnl_ring_advance;
+} LIBMNL_1.1;
diff --git a/src/mmap.c b/src/mmap.c
new file mode 100644
index 0000000..348fa89
--- /dev/null
+++ b/src/mmap.c
@@ -0,0 +1,227 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <libmnl/libmnl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include "internal.h"
+
+
+struct mnl_ring {
+ void *ring;
+ unsigned int frame_size;
+ unsigned int frame_max;
+ unsigned int block_size;
+ unsigned int head;
+};
+
+/*
+ * ring descriptor
+ */
+struct mnl_ring_socket {
+ const struct mnl_socket *sock;
+
+ struct mnl_ring *tx_ring;
+ struct mnl_ring *rx_ring;
+};
+
+
+static inline struct mnl_ring *get_mnl_ring(struct mnl_ring_socket *nlm, enum mnl_ring_types type)
+{
+ return type == MNL_RING_TX ? nlm->tx_ring : nlm->rx_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;
+}
+
+/**
+ * \defgroup socket Netlink mmapped socket helpers
+ * @{
+ */
+
+/**
+ * mnl_ring_map - setup a ring descriptor
+ * \param nl opend mnl_socket
+ * \param tx_req setsockopt param for tx ring
+ * \param rx_req setsockopt param for rx ring
+ *
+ * return NULL if fail
+ */
+struct mnl_ring_socket *
+mnl_ring_map(const struct mnl_socket *nl, struct nl_mmap_req *tx_req, struct nl_mmap_req *rx_req)
+{
+ void *ring;
+ struct mnl_ring_socket *nlm;
+ size_t tx_size = 0, rx_size = 0;
+
+ nlm = calloc(sizeof(struct mnl_ring_socket), 1);
+ if (nlm == NULL)
+ return NULL;
+ nlm->sock = nl;
+
+ if (tx_req != NULL) {
+ nlm->tx_ring = alloc_ring(tx_req);
+ if (nlm->tx_ring == NULL)
+ goto error;
+ if (mnl_socket_setsockopt(nl, NETLINK_TX_RING, tx_req, sizeof(*tx_req)) < 0)
+ goto error;
+ tx_size = tx_req->nm_block_nr * tx_req->nm_block_size;
+ }
+
+ if (rx_req != NULL) {
+ nlm->rx_ring = alloc_ring(rx_req);
+ if (nlm->rx_ring == NULL)
+ goto error;
+ if (mnl_socket_setsockopt(nl, NETLINK_RX_RING, rx_req, sizeof(*rx_req)) < 0)
+ goto error;
+ rx_size += rx_req->nm_block_nr * rx_req->nm_block_size;
+ }
+
+ ring = mmap(NULL, tx_size + rx_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ mnl_socket_get_fd(nlm->sock), 0);
+ if (ring == MAP_FAILED)
+ goto error;
+
+ if (rx_req != NULL && tx_req != NULL) {
+ nlm->rx_ring->ring = ring;
+ nlm->tx_ring->ring = ring + rx_size;
+ } else if (rx_req != NULL) {
+ nlm->rx_ring->ring = ring;
+ } else {
+ nlm->tx_ring->ring = ring;
+ }
+
+ return nlm;
+
+error:
+ if (nlm->tx_ring != NULL)
+ free(nlm->tx_ring);
+ if (nlm->rx_ring != NULL)
+ free(nlm->rx_ring);
+ free(nlm);
+ return NULL;
+}
+EXPORT_SYMBOL(mnl_ring_map);
+
+
+static int unmap_ring(struct mnl_ring *ring)
+{
+ size_t ring_size;
+ unsigned int frames_per_block;
+ int ret;
+
+ frames_per_block = ring->block_size / ring->frame_size;
+ ring_size = (ring->frame_max + 1 + frames_per_block - 1) / frames_per_block * ring->block_size;
+
+ ret = munmap(ring->ring, ring_size);
+ if (ret < 0)
+ return ret;
+
+ ring->ring = NULL;
+ ring->frame_size = 0;
+ ring->frame_max = 0;
+ ring->block_size = 0;
+ ring->head = 0;
+
+ return ret;
+}
+
+/**
+ * mnl_ring_unmap - free a given ring descriptor
+ * \param nlm ring descriptor obtained via mnl_ring_map()
+ */
+int mnl_ring_unmap(struct mnl_ring_socket *nlm)
+{
+ int ret;
+
+ /* XXX: how's sockopt going? */
+ if (nlm->tx_ring != NULL) {
+ ret = unmap_ring(nlm->tx_ring);
+ if (ret < 0)
+ return ret;
+ free(nlm->tx_ring);
+ nlm->tx_ring = NULL;
+ }
+ if (nlm->rx_ring != NULL) {
+ ret = unmap_ring(nlm->rx_ring);
+ if (ret < 0)
+ return ret;
+ free(nlm->rx_ring);
+ nlm->rx_ring = NULL;
+ }
+
+ free(nlm);
+ return 1;
+}
+EXPORT_SYMBOL(mnl_ring_unmap);
+
+/**
+ * mnl_ring_get_frame - get current frame
+ * \param nlm ring descriptor
+ * \param type ring type either MNL_RING_RX or MNL_RING_TX
+ */
+struct nl_mmap_hdr *mnl_ring_get_frame(struct mnl_ring_socket *nlm, enum mnl_ring_types type)
+{
+ unsigned int frames_per_block, block_pos, frame_off;
+ struct mnl_ring *ring;
+
+ ring = get_mnl_ring(nlm, type);
+ if (ring == NULL) {
+ errno = EBADR;
+ 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_ring_get_frame);
+
+/**
+ * mnl_ring_advance - set forward frame pointer
+ * \param nlm ring descriptor
+ * \param type ring type either MNL_RING_RX or MNL_RING_TX
+ */
+int mnl_ring_advance(struct mnl_ring_socket *nlm, enum mnl_ring_types type)
+{
+ struct mnl_ring *ring;
+
+ ring = get_mnl_ring(nlm, type);
+ if (ring == NULL) {
+ errno = EBADR;
+ return -1;
+ }
+ ring->head = ring->head != ring->frame_max ? ring->head + 1 : 0;
+
+ return 1; /* ring->head; */
+}
+EXPORT_SYMBOL(mnl_ring_advance);
+
+/**
+ * @}
+ */
--
1.8.4.rc3
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2013-12-07 15:10 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-07 15:09 [libmnl PATCH 2/9] mmap: initial Ken-ichirou MATSUZAWA
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).