Since recvmmsg() was introduced in linux-2.6.34 and glibc-2.12,
you need to explicitly turn it on in Makefile.
Signed-off-by: Vitezslav Samel <vitezslav(a)samel.cz>
---
Makefile | 9 ++++
src/capt-recvmmsg.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/capt-recvmmsg.h | 6 +++
src/capt.c | 9 ++++
4 files changed, 162 insertions(+)
create mode 100644 src/capt-recvmmsg.c
create mode 100644 src/capt-recvmmsg.h
diff --git a/Makefile b/Makefile
index 64ca213..71439a7 100644
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,9 @@ all::
# Define NEEDS_NCURSES6 if you need linking with ncurses6.
#
# Define NEEDS_NCURSESW6 if you need linking with ncursesw6.
+#
+# Define USE_RECVMMSG if you want to use recvmmsg() packet capturing interface.
+#USE_RECVMMSG := 1
VERSION-FILE: FORCE
@@ -276,6 +279,12 @@ ifndef NCURSES_LDFLAGS
endif
endif
+ifdef USE_RECVMMSG
+ CFLAGS += -D_USE_GNU -DUSE_RECVMMSG
+ iptraf-h += src/capt-recvmmsg.h
+ iptraf-o += src/capt-recvmmsg.o
+endif
+
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
diff --git a/src/capt-recvmmsg.c b/src/capt-recvmmsg.c
new file mode 100644
index 0000000..8bcf1a8
--- /dev/null
+++ b/src/capt-recvmmsg.c
@@ -0,0 +1,138 @@
+/* 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"
+
+#define FRAMES 128
+
+struct capt_data_recvmmsg {
+ char *buf;
+
+ struct mmsghdr *msgvec;
+ struct iovec *iov;
+ struct sockaddr_ll *from;
+
+ unsigned int lastslot;
+ unsigned int slot;
+};
+
+static unsigned int capt_recvmmsg_find_filled_slot(struct capt_data_recvmmsg *data)
+{
+ for (unsigned int slot = data->lastslot; slot < FRAMES; slot++)
+ if (data->msgvec[slot].msg_len != 0)
+ return slot;
+
+ return FRAMES;
+}
+
+static unsigned int capt_have_packet_recvmmsg(struct capt *capt)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+
+ return capt_recvmmsg_find_filled_slot(data) != FRAMES;
+}
+
+static int capt_get_packet_recvmmsg(struct capt *capt, struct pkt_hdr *pkt)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+ int ret = 0;
+
+ unsigned int slot = capt_recvmmsg_find_filled_slot(data);
+ if (slot == FRAMES) {
+ /* these are set upon return from recvmsg() so clean */
+ /* them beforehand */
+ for (unsigned int i = 0; i < FRAMES; i++) {
+ data->msgvec[i].msg_hdr.msg_controllen = 0;
+ data->msgvec[i].msg_hdr.msg_flags = 0;
+ data->msgvec[i].msg_len = 0;
+ }
+
+ int received = recvmmsg(capt->fd, data->msgvec, FRAMES, MSG_TRUNC | MSG_DONTWAIT,
NULL);
+ if (received <= 0)
+ return received;
+ slot = 0;
+ }
+ pkt->pkt_len = data->msgvec[slot].msg_len;
+ pkt->pkt_caplen = data->msgvec[slot].msg_len;
+ if (pkt->pkt_caplen > MAX_PACKET_SIZE)
+ pkt->pkt_caplen = MAX_PACKET_SIZE;
+ pkt->pkt_buf = data->buf + slot * MAX_PACKET_SIZE;
+ pkt->from = &data->from[slot];
+ pkt->pkt_payload = NULL;
+ pkt->pkt_protocol = ntohs(pkt->from->sll_protocol);
+
+ data->slot = slot;
+
+ return ret;
+}
+
+static int capt_put_packet_recvmmsg(struct capt *capt, struct pkt_hdr *pkt __unused)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+
+ /* hand out processed slot to kernel */
+ if (data->slot < FRAMES) {
+ data->msgvec[data->slot].msg_len = 0;
+ data->lastslot = data->slot;
+ } else
+ data->slot = FRAMES;
+
+ return 0;
+}
+
+static void capt_cleanup_recvmmsg(struct capt *capt)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+
+ capt->cleanup = NULL;
+ capt->put_packet = NULL;
+ capt->get_packet = NULL;
+ capt->have_packet = NULL;
+
+ free(data->from);
+ data->from = NULL;
+ free(data->iov);
+ data->iov = NULL;
+ free(data->msgvec);
+ data->msgvec = NULL;
+ free(data->buf);
+ data->buf = NULL;
+
+ free(capt->priv);
+ capt->priv = NULL;
+}
+
+int capt_setup_recvmmsg(struct capt *capt)
+{
+ struct capt_data_recvmmsg *data;
+
+ data = xmallocz(sizeof(struct capt_data_recvmmsg));
+ data->buf = xmallocz(FRAMES * MAX_PACKET_SIZE);
+ data->msgvec = xmallocz(FRAMES * sizeof(*data->msgvec));
+ data->iov = xmallocz(FRAMES * sizeof(*data->iov));
+ data->from = xmallocz(FRAMES * sizeof(*data->from));
+
+ for (unsigned int i = 0; i < FRAMES; i++) {
+ data->iov[i].iov_len = MAX_PACKET_SIZE;
+ data->iov[i].iov_base = data->buf + i * MAX_PACKET_SIZE;
+
+ data->msgvec[i].msg_hdr.msg_name = &data->from[i];
+ data->msgvec[i].msg_hdr.msg_namelen = sizeof(data->from[i]);
+ data->msgvec[i].msg_hdr.msg_iov = &data->iov[i];
+ data->msgvec[i].msg_hdr.msg_iovlen = 1;
+ data->msgvec[i].msg_hdr.msg_control = NULL;
+ }
+ data->slot = FRAMES;
+ data->lastslot = 0;
+
+ capt->priv = data;
+ capt->have_packet = capt_have_packet_recvmmsg;
+ capt->get_packet = capt_get_packet_recvmmsg;
+ capt->put_packet = capt_put_packet_recvmmsg;
+ capt->cleanup = capt_cleanup_recvmmsg;
+
+ return 0;
+}
diff --git a/src/capt-recvmmsg.h b/src/capt-recvmmsg.h
new file mode 100644
index 0000000..8461eed
--- /dev/null
+++ b/src/capt-recvmmsg.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_CAPT_RECVMMSG_H
+#define IPTRAF_NG_CAPT_RECVMMSG_H
+
+int capt_setup_recvmmsg(struct capt *capt);
+
+#endif /* IPTRAF_NG_CAPT_RECVMMSG_H */
diff --git a/src/capt.c b/src/capt.c
index 9c0d6d4..b7a75ec 100644
--- a/src/capt.c
+++ b/src/capt.c
@@ -8,6 +8,9 @@
#include "packet.h"
#include "capt.h"
#include "capt-recvmsg.h"
+#ifdef USE_RECVMMSG
+#include "capt-recvmmsg.h"
+#endif
static int capt_set_recv_timeout(int fd, unsigned int msec)
{
@@ -45,6 +48,12 @@ int capt_init(struct capt *capt, char *ifname)
if (capt_set_recv_timeout(capt->fd, 250) == -1)
goto out;
+#ifdef USE_RECVMMSG
+ /* try packet recvmmsg() */
+ if (capt_setup_recvmmsg(capt) == 0)
+ return 0;
+#endif
+
/* try packet recvmsg() */
if (capt_setup_recvmsg(capt) == 0)
return 0;
--
1.9.1