[prev in list] [next in list] [prev in thread] [next in thread] 

List:       iptraf-ng
Subject:    [PATCH 3/3] capt.c: add capturing using mmap()ed PACKET_RX_RING memory
From:       Vitezslav Samel <vitezslav () samel ! cz>
Date:       2014-06-20 13:36:36
Message-ID: 1403271396-1776-4-git-send-email-vitezslav () samel ! cz
[Download RAW message or body]

Signed-off-by: Vitezslav Samel <vitezslav@samel.cz>
---
 Makefile               |   2 +
 src/capt-mmap-v2.c     | 147 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/capt-mmap-v2.h     |   6 ++
 src/capt.c             |   5 ++
 src/iptraf-ng-compat.h |   1 +
 5 files changed, 161 insertions(+)
 create mode 100644 src/capt-mmap-v2.c
 create mode 100644 src/capt-mmap-v2.h

diff --git a/Makefile b/Makefile
index 71439a7..7326c3b 100644
--- a/Makefile
+++ b/Makefile
@@ -120,6 +120,7 @@ iptraf-h += src/built-in.h
 iptraf-h += src/sockaddr.h
 iptraf-h += src/capt.h
 iptraf-h += src/capt-recvmsg.h
+iptraf-h += src/capt-mmap-v2.h
 
 iptraf-o += src/tui/input.o
 iptraf-o += src/tui/labels.o
@@ -164,6 +165,7 @@ iptraf-o += src/capture-pkt.o
 iptraf-o += src/sockaddr.o
 iptraf-o += src/capt.o
 iptraf-o += src/capt-recvmsg.o
+iptraf-o += src/capt-mmap-v2.o
 
 rvnamed-o += src/rvnamed.o
 rvnamed-o += src/getpath.o
diff --git a/src/capt-mmap-v2.c b/src/capt-mmap-v2.c
new file mode 100644
index 0000000..ebbc125
--- /dev/null
+++ b/src/capt-mmap-v2.c
@@ -0,0 +1,147 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "packet.h"
+#include "capt.h"
+
+struct capt_data_mmap_v2 {
+	void			*mmap;
+	size_t			mmap_size;
+	struct tpacket2_hdr	**hdr;
+	struct sockaddr_ll	**sll;
+	unsigned int		lastslot;
+	unsigned int		slot;
+};
+
+#define FRAMES 512
+
+static unsigned int capt_mmap_find_filled_slot(struct capt_data_mmap_v2 *data)
+{
+	for (unsigned int i = data->lastslot; i < data->lastslot + FRAMES; i++) {
+		unsigned int slot = i >= FRAMES ? i - FRAMES : i;
+
+		if (data->hdr[slot]->tp_status & TP_STATUS_USER)
+			return slot;
+	}
+	return FRAMES;
+}
+
+static unsigned int capt_have_packet_mmap_v2(struct capt *capt)
+{
+	struct capt_data_mmap_v2 *data = capt->priv;
+
+	return capt_mmap_find_filled_slot(data) != FRAMES;
+}
+
+static int capt_get_packet_mmap_v2(struct capt *capt, struct pkt_hdr *pkt)
+{
+	struct capt_data_mmap_v2 *data = capt->priv;
+	int ss = 0;
+
+	unsigned int slot = capt_mmap_find_filled_slot(data);
+	if (slot < FRAMES) {
+		struct tpacket2_hdr *hdr = data->hdr[slot];
+		struct sockaddr_ll *sll = data->sll[slot];
+
+		pkt->pkt_buf = (char *)hdr + hdr->tp_mac;
+		pkt->pkt_payload = NULL;
+		pkt->pkt_caplen = hdr->tp_snaplen;
+		pkt->pkt_len = hdr->tp_len;
+		pkt->from = sll;
+		pkt->pkt_protocol = ntohs(sll->sll_protocol);
+
+		data->slot = slot;
+		ss = hdr->tp_len;
+	}
+	return ss;
+}
+
+static int capt_put_packet_mmap_v2(struct capt *capt, struct pkt_hdr *pkt __unused)
+{
+	struct capt_data_mmap_v2 *data = capt->priv;
+
+	/* hand out processed slot to kernel */
+	if (data->slot < FRAMES) {
+		data->hdr[data->slot]->tp_status = TP_STATUS_KERNEL;
+		data->lastslot = data->slot;
+	} else
+		data->slot = FRAMES;
+
+	return 0;
+}
+
+static void capt_cleanup_mmap_v2(struct capt *capt)
+{
+	struct capt_data_mmap_v2 *data = capt->priv;
+
+	free(data->sll);
+	data->sll = NULL;
+
+	free(data->hdr);
+	data->hdr = NULL;
+
+	munmap(data->mmap, data->mmap_size);
+	data->mmap = NULL;
+	data->mmap_size = 0;
+
+	free(capt->priv);
+	capt->priv = NULL;
+}
+
+int capt_setup_mmap_v2(struct capt *capt)
+{
+	int version = TPACKET_V2;
+	if (setsockopt(capt->fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)) != 0)
+		return -1;
+
+	int hdrlen = version;
+	socklen_t socklen = sizeof(hdrlen);
+	if (getsockopt(capt->fd, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &socklen) != 0)
+		return -1;
+
+	/* computed not exactly, but almost there */
+	size_t frame_size = TPACKET_ALIGN(hdrlen) +
+			    TPACKET_ALIGN(sizeof(struct sockaddr_ll)) +
+			    TPACKET_ALIGN(MAX_PACKET_SIZE);
+
+	struct tpacket_req req;
+
+	req.tp_block_nr = 1;
+	req.tp_frame_nr = FRAMES;
+	/* frame_size must be a multiple of TPACKET_ALIGNMENT */
+	req.tp_frame_size = frame_size;
+	/* block_size must be a multiple of PAGE_SIZE */
+	/* TODO: check for this condition (incidently we are OK now) */
+	req.tp_block_size = req.tp_frame_nr * req.tp_frame_size;
+
+	if(setsockopt(capt->fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) != 0)
+		return -1;
+
+	size_t size = req.tp_block_size * req.tp_block_nr;
+	void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, capt->fd, 0);
+	if (map == MAP_FAILED)
+		return -1;
+
+	struct capt_data_mmap_v2 *data = xmallocz(sizeof(struct capt_data_mmap_v2));
+
+	data->mmap = map;
+	data->mmap_size = size;
+	data->hdr = xmallocz(FRAMES * sizeof(*data->hdr));
+	data->sll = xmallocz(FRAMES * sizeof(*data->sll));
+	for (int i = 0; i < FRAMES; i++) {
+		data->hdr[i] = (struct tpacket2_hdr *)((char *)map + i * frame_size);
+		data->sll[i] = (struct sockaddr_ll *)((char *)data->hdr[i] + TPACKET_ALIGN(hdrlen));
+	}
+	data->lastslot = 0;
+	data->slot = FRAMES;
+
+	capt->priv		= data;
+	capt->have_packet	= capt_have_packet_mmap_v2;
+	capt->get_packet	= capt_get_packet_mmap_v2;
+	capt->put_packet	= capt_put_packet_mmap_v2;
+	capt->cleanup		= capt_cleanup_mmap_v2;
+
+	return 0;	/* All O.K. */
+}
diff --git a/src/capt-mmap-v2.h b/src/capt-mmap-v2.h
new file mode 100644
index 0000000..daa92e7
--- /dev/null
+++ b/src/capt-mmap-v2.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_CAPT_MMAP_V2_H
+#define IPTRAF_NG_CAPT_MMAP_V2_H
+
+int capt_setup_mmap_v2(struct capt *capt);
+
+#endif	/* IPTRAF_NG_CAPT_MMAP_V2_H */
diff --git a/src/capt.c b/src/capt.c
index b7a75ec..f704e13 100644
--- a/src/capt.c
+++ b/src/capt.c
@@ -11,6 +11,7 @@
 #ifdef USE_RECVMMSG
 #include "capt-recvmmsg.h"
 #endif
+#include "capt-mmap-v2.h"
 
 static int capt_set_recv_timeout(int fd, unsigned int msec)
 {
@@ -48,6 +49,10 @@ int capt_init(struct capt *capt, char *ifname)
 	if (capt_set_recv_timeout(capt->fd, 250) == -1)
 		goto out;
 
+	/* try packet mmap() TPACKET_V2 */
+	if (capt_setup_mmap_v2(capt) == 0)
+		return 0;
+
 #ifdef USE_RECVMMSG
 	/* try packet recvmmsg() */
 	if (capt_setup_recvmmsg(capt) == 0)
diff --git a/src/iptraf-ng-compat.h b/src/iptraf-ng-compat.h
index aaa2807..8fe5154 100644
--- a/src/iptraf-ng-compat.h
+++ b/src/iptraf-ng-compat.h
@@ -26,6 +26,7 @@
 #include <sys/ioctl.h>
 #include <sys/wait.h>
 #include <sys/un.h>
+#include <sys/mman.h>
 
 #include <netinet/in.h>
 #include <netinet/udp.h>
-- 
1.9.1

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic