diff --git a/src/decode.h b/src/decode.h index a0127f5f3e..4814afc586 100644 --- a/src/decode.h +++ b/src/decode.h @@ -42,6 +42,7 @@ typedef enum { #include "source-nfq.h" #include "source-ipfw.h" #include "source-pcap.h" +#include "source-af-packet.h" #include "action-globals.h" @@ -370,6 +371,9 @@ typedef struct Packet_ #ifdef IPFW IPFWPacketVars ipfw_v; #endif /* IPFW */ +#ifdef AF_PACKET + AFPPacketVars afp_v; +#endif /** libpcap vars: shared by Pcap Live mode and Pcap File mode */ PcapPacketVars pcap_v; @@ -385,6 +389,9 @@ typedef struct Packet_ int debuglog_flowbits_names_len; const char **debuglog_flowbits_names; + /** The release function for packet data */ + TmEcode (*ReleaseData)(ThreadVars *, struct Packet_ *); + /* pkt vars */ PktVar *pktvar; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 82e5c345ee..6fa02c5983 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -368,6 +368,17 @@ int AFPRead(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } +TmEcode AFPReleaseDataFromRing(ThreadVars *t, Packet *p) +{ + if (p->afp_v.relptr) { + union thdr h; + h.raw = p->afp_v.relptr; + h.h2->tp_status = TP_STATUS_KERNEL; + return TM_ECODE_OK; + } + return TM_ECODE_FAILED; +} + /** * \brief AF packet read function for ring * @@ -388,6 +399,11 @@ int AFPReadFromRing(AFPThreadVars *ptv) h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); if (h.raw == NULL) { SCReturnInt(AFP_FAILURE); + } else { + if (ptv->flags & AFP_RING_MODE) { + p->afp_v.relptr = h.raw; + p->ReleaseData = AFPReleaseDataFromRing; + } } if (h.h2->tp_status == TP_STATUS_KERNEL) { SCReturnInt(AFP_READ_OK); @@ -1013,6 +1029,13 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { SCLogInfo("Enabling zero copy mode"); } + /* If we are in RING mode, then we can use ZERO copy + * by using the data release mechanism */ + if (ptv->flags & AFP_RING_MODE) { + ptv->flags |= AFP_ZERO_COPY; + SCLogInfo("Enabling zero copy mode by using data release call"); + } + r = AFPCreateSocket(ptv, ptv->iface, 1); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket"); diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 02b1d63a2f..97dc2c29c7 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -67,6 +67,13 @@ typedef struct AFPIfaceConfig_ void (*DerefFunc)(void *); } AFPIfaceConfig; +/* per packet AF_PACKET vars */ +typedef struct AFPPacketVars_ +{ + void *relptr; +} AFPPacketVars; + + void TmModuleReceiveAFPRegister (void); void TmModuleDecodeAFPRegister (void); diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 1e5a5cd136..1844f7cc12 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -250,8 +250,16 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) FlowDecrUsecnt(p->root->flow); /* if p->root uses extended data, free them */ + if (p->root->ReleaseData) { + if (p->root->ReleaseData(t, p->root) == TM_ECODE_FAILED) { + SCLogWarning(SC_ERR_INVALID_ACTION, + "Unable to release packet data"); + } + } if (p->root->ext_pkt) { - SCFree(p->root->ext_pkt); + if (!(p->root->flags & PKT_ZERO_COPY)) { + SCFree(p->root->ext_pkt); + } p->root->ext_pkt = NULL; } if (p->root->flags & PKT_ALLOC) { @@ -262,6 +270,13 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) PACKET_RECYCLE(p->root); RingBufferMrMwPut(ringbuffer, (void *)p->root); } + + } + + if (p->ReleaseData) { + if (p->ReleaseData(t, p) == TM_ECODE_FAILED) { + SCLogWarning(SC_ERR_INVALID_ACTION, "Unable to release packet data"); + } } /* if p uses extended data, free them */