From 501be7dbf38031cf6b9d01212d9399325f314bd1 Mon Sep 17 00:00:00 2001
From: Eric Leblond <eric@regit.org>
Date: Fri, 15 Jun 2012 17:18:57 +0200
Subject: [PATCH] capture: add data release mechanism

This patch adds a data release mechanism. If the capture module
has a call to indicate that userland has finished with the data,
it is possible to use this system. The data will then be released
when the treatment of the packet is finished.

To do so the Packet structure has been modified:
+    TmEcode (*ReleaseData)(struct Packet_ *);
+    void *relptr;
If ReleaseData and relptr are not null, the function is called
when the treatment of the Packet is finished.
Thus it is sufficient for the capture module to code a function
wrapping the data release mechanism and to assign it to ReleaseData
field.
---
 src/decode.h           |    4 ++++
 src/source-af-packet.c |   23 +++++++++++++++++++++++
 src/tmqh-packetpool.c  |    6 ++++++
 3 files changed, 33 insertions(+)

diff --git a/src/decode.h b/src/decode.h
index 553a254..1a4f178 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -381,6 +381,10 @@ typedef struct Packet_
     /* IPS action to take */
     uint8_t action;
 
+    /** The release function for packet data */
+    TmEcode (*ReleaseData)(struct Packet_ *);
+    void *relptr;
+
     /* pkt vars */
     PktVar *pktvar;
 
diff --git a/src/source-af-packet.c b/src/source-af-packet.c
index 2c39bdc..03e0f3e 100644
--- a/src/source-af-packet.c
+++ b/src/source-af-packet.c
@@ -384,6 +384,17 @@ int AFPRead(AFPThreadVars *ptv)
     SCReturnInt(AFP_READ_OK);
 }
 
+TmEcode AFPReleaseDataFromRing(Packet *p)
+{
+    if (p->relptr) {
+        union thdr h;
+        h.raw = p->relptr;
+        h.h2->tp_status = TP_STATUS_KERNEL;
+        return TM_ECODE_OK;
+    }
+    return TM_ECODE_FAILED;
+}
+
 /**
  * \brief AF packet read function for ring
  *
@@ -434,6 +445,11 @@ int AFPReadFromRing(AFPThreadVars *ptv)
         if (PacketSetData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) {
             TmqhOutputPacketpool(ptv->tv, p);
             SCReturnInt(AFP_FAILURE);
+        } else {
+            if (ptv->flags & AFP_RING_MODE) {
+                p->relptr = h.raw;
+                p->ReleaseData = AFPReleaseDataFromRing;
+            }
         }
     } else {
         if (PacketCopyData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) {
@@ -1023,6 +1039,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/tmqh-packetpool.c b/src/tmqh-packetpool.c
index 01422d3..b0e5dd0 100644
--- a/src/tmqh-packetpool.c
+++ b/src/tmqh-packetpool.c
@@ -239,6 +239,12 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
         p->ext_pkt = NULL;
     }
 
+    if (p->relptr && p->ReleaseData) {
+        if (p->ReleaseData(p) == TM_ECODE_FAILED) {
+            SCLogWarning(SC_ERR_INVALID_ACTION, "Unable to release packet data");
+        }
+    }
+
     PACKET_PROFILING_END(p);
 
     SCLogDebug("getting rid of tunnel pkt... alloc'd %s (root %p)", p->flags & PKT_ALLOC ? "true" : "false", p->root);
-- 
1.7.10

