* [libmnl PATCH 0/9] mmaped netlink
@ 2013-12-07 15:07 Ken-ichirou MATSUZAWA
2014-01-01 10:07 ` libmnl nl-mmap patch review request Ken-ichirou MATSUZAWA
0 siblings, 1 reply; 2+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2013-12-07 15:07 UTC (permalink / raw)
To: Pablo Neira Ayuso, netfilter-devel
Hello Pablo, list
# First of all, you will have to excuse my poor English, sorry
I started implementing mmaped netlink socket in libmnl. Would you review the
code? differ from original/nl-mmap, I added new struct mnl_ring_socket wrapping
mnl_socket and new file mmap.c. Patches are divided into 4 parts.
part1: [2, 3] resemble to original/nl-mmap
part2: [4, 5] add helper
part3: [6, 7] add more helper
part4: [8, 9] add new batch function for mmap
Theses can be seen at https://github.com/chamaken/libmnl/tree/mmap-sbs too.
I have no experience using libmnl, netlink then do not know what is suitable for
minimalistic. And I doubt part2 - 4 is suitable only for examples. Any advice is
welcome.
thanks,
^ permalink raw reply [flat|nested] 2+ messages in thread
* libmnl nl-mmap patch review request
2013-12-07 15:07 [libmnl PATCH 0/9] mmaped netlink Ken-ichirou MATSUZAWA
@ 2014-01-01 10:07 ` Ken-ichirou MATSUZAWA
0 siblings, 0 replies; 2+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2014-01-01 10:07 UTC (permalink / raw)
To: Pablo Neira Ayuso, netfilter-devel
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;
}
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2014-01-01 10:08 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-07 15:07 [libmnl PATCH 0/9] mmaped netlink Ken-ichirou MATSUZAWA
2014-01-01 10:07 ` libmnl nl-mmap patch review request 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).