Signed-off-by: Vitezslav Samel <vitezslav(a)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