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@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;