-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
*/
Packet *PacketGetFromQueueOrAlloc(void)
{
- Packet *p = NULL;
-
/* try the pool first */
- if (PacketPoolSize() > 0) {
- p = PacketPoolGetPacket();
- }
+ Packet *p = PacketPoolGetPacket();
if (p == NULL) {
/* non fatal, we're just not processing a packet then */
struct DetectionEngineThreadCtx_;
typedef struct AppLayerThreadCtx_ AppLayerThreadCtx;
+struct PktPool_;
+
/* declare these here as they are called from the
* PACKET_RECYCLE and PACKET_CLEANUP macro's. */
typedef struct AppLayerDecoderEvents_ AppLayerDecoderEvents;
/* tunnel packet ref count */
uint16_t tunnel_tpr_cnt;
+ /* The Packet pool from which this packet was allocated. Used when returning
+ * the packet to its owner's stack. If NULL, then allocated with malloc.
+ */
+ struct PktPool_ *pool;
#ifdef PROFILING
PktProfiling *profile;
-/* Copyright (C) 2011-2013 Open Information Security Foundation
+/* Copyright (C) 2011-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
{
SCEnter();
- uint16_t packet_q_len = 0;
AFPThreadVars *ptv = (AFPThreadVars *)data;
struct pollfd fds;
int r;
/* make sure we have at least one packet in the packet pool, to prevent
* us from alloc'ing packets at line rate */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
r = poll(&fds, 1, POLL_TIMEOUT);
ptv->vlan_disabled = 1;
}
+ PacketPoolInit();
+
SCReturnInt(TM_ECODE_OK);
}
-/* Copyright (C) 2010 Open Information Security Foundation
+/* Copyright (C) 2010-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
SCLogInfo("Starting processing packets from stream: %d on DAG: %s",
ewtn->dagstream, ewtn->dagname);
+ PacketPoolInit();
+
SCReturnInt(TM_ECODE_OK);
}
/* Make sure we have at least one packet in the packet pool,
* to prevent us from alloc'ing packets at line rate. */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
prec = (char *)ewtn->btm;
dr = (dag_record_t*)prec;
-/* Copyright (C) 2010 Open Information Security Foundation
+/* Copyright (C) 2010-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
/* Make sure we have at least one packet in the packet pool,
* to prevent us from alloc'ing packets at line rate. */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
p = PacketGetFromQueueOrAlloc();
if (unlikely(p == NULL)) {
etv->tv = tv;
*data = (void *)etv;
+ PacketPoolInit();
+
SCLogInfo("Processing ERF file %s", (char *)initdata);
SCReturnInt(TM_ECODE_OK);
-/* Copyright (C) 2007-2011 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
/* make sure we have at least one packet in the packet pool, to prevent
* us from alloc'ing packets at line rate */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
*data = (void *)ntv;
+ PacketPoolInit();
+
SCReturnInt(TM_ECODE_OK);
}
*data = (void *)ptv;
+ PacketPoolInit();
+
+ /* Only rank 0 does initialization of mpipe */
if (rank != 0)
SCReturnInt(TM_ECODE_OK);
-/* Copyright (C) 2012 Open Information Security Foundation
+/* Copyright (C) 2012-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
*data = (void *)ntv;
+ PacketPoolInit();
+
SCReturnInt(TM_ECODE_OK);
}
while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) {
/* make sure we have at least one packet in the packet pool, to prevent
* us from alloc'ing packets at line rate */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
/*
* Napatech returns packets 1 at a time
-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#undef T_DATA_SIZE
*data = (void *)ntv;
+
+ PacketPoolInit();
+
SCMutexUnlock(&nfq_init_lock);
return TM_ECODE_OK;
}
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
/* make sure we have at least one packet in the packet pool, to prevent
* us from alloc'ing packets at line rate */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
/* Right now we just support reading packets one at a time. */
r = pcap_dispatch(pcap_g.pcap_handle, (int)packet_q_len,
ptv->tv = tv;
*data = (void *)ptv;
+
+ PacketPoolInit();
+
SCReturnInt(TM_ECODE_OK);
}
-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
/* make sure we have at least one packet in the packet pool, to prevent
* us from alloc'ing packets at line rate */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
/* Right now we just support reading packets one at a time. */
r = pcap_dispatch(ptv->pcap_handle, (int)packet_q_len,
*data = (void *)ptv;
+ PacketPoolInit();
+
/* Dereference config */
pcapconfig->DerefFunc(pcapconfig);
SCReturnInt(TM_ECODE_OK);
/* make sure we have at least one packet in the packet pool, to prevent
* us from alloc'ing packets at line rate */
- do {
- packet_q_len = PacketPoolSize();
- if (unlikely(packet_q_len == 0)) {
- PacketPoolWait();
- }
- } while (packet_q_len == 0);
+ PacketPoolWait();
p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
*data = (void *)ptv;
pfconf->DerefFunc(pfconf);
+
+ PacketPoolInit();
+
return TM_ECODE_OK;
}
NSS_NoDB_Init(NULL);
#endif
- PacketPoolInit(max_pending_packets);
HostInitConfig(HOST_VERBOSE);
if (suri.run_mode != RUNMODE_UNIX_SOCKET) {
FlowInitConfig(FLOW_VERBOSE);
-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
*
* \author Victor Julien <victor@inliniac.net>
*
- * Packetpool queue handlers. Packet pool is implemented as a ringbuffer.
- * We're using a multi reader / multi writer version of the ringbuffer,
- * that is relatively expensive due to the CAS function. But it is necessary
- * because every thread can return packets to the pool and multiple parts
- * of the code retrieve packets (Decode, Defrag) and these can run in their
- * own threads as well.
+ * Packetpool queue handlers. Packet pool is implemented as a stack.
*/
#include "suricata.h"
#include "tmqh-packetpool.h"
-#include "util-ringbuffer.h"
#include "util-debug.h"
#include "util-error.h"
#include "util-profiling.h"
#include "util-device.h"
-static RingBuffer16 *ringbuffer = NULL;
+/* TODO: Handle case without __thread */
+__thread PktPool thread_pkt_pool;
+
/**
* \brief TmqhPacketpoolRegister
* \initonly
tmqh_table[TMQH_PACKETPOOL].name = "packetpool";
tmqh_table[TMQH_PACKETPOOL].InHandler = TmqhInputPacketpool;
tmqh_table[TMQH_PACKETPOOL].OutHandler = TmqhOutputPacketpool;
-
- ringbuffer = RingBufferInit();
- if (ringbuffer == NULL) {
- SCLogError(SC_ERR_FATAL, "Error registering Packet pool handler (at ring buffer init)");
- exit(EXIT_FAILURE);
- }
-}
-
-void TmqhPacketpoolDestroy (void) {
- /* doing this clean up PacketPoolDestroy now,
- * where we also clean the packets */
}
-int PacketPoolIsEmpty(void) {
- return RingBufferIsEmpty(ringbuffer);
-}
+static int PacketPoolIsEmpty(void)
+{
+ /* Check local stack first. */
+ if (thread_pkt_pool.head || thread_pkt_pool.return_head)
+ return 0;
-uint16_t PacketPoolSize(void) {
- return RingBufferSize(ringbuffer);
+ return 1;
}
-void PacketPoolWait(void) {
- RingBufferWait(ringbuffer);
+void PacketPoolWait(void)
+{
+ while(PacketPoolIsEmpty())
+ ;
}
/** \brief a initialized packet
*
* \warning Use *only* at init, not at packet runtime
*/
-void PacketPoolStorePacket(Packet *p) {
- if (RingBufferIsFull(ringbuffer)) {
- exit(1);
- }
-
+static void PacketPoolStorePacket(Packet *p)
+{
/* Clear the PKT_ALLOC flag, since that indicates to push back
* onto the ring buffer. */
p->flags &= ~PKT_ALLOC;
+ p->pool = &thread_pkt_pool;;
p->ReleasePacket = PacketPoolReturnPacket;
PacketPoolReturnPacket(p);
-
- SCLogDebug("buffersize %u", RingBufferSize(ringbuffer));
}
-/** \brief get a packet from the packet pool, but if the
- * pool is empty, don't wait, just return NULL
+/** \brief Get a new packet from the packet pool
+ *
+ * Only allocates from the thread's local stack, or mallocs new packets.
+ * If the local stack is empty, first move all the return stack packets to
+ * the local stack.
+ * \retval Packet pointer, or NULL on failure.
*/
-Packet *PacketPoolGetPacket(void) {
- if (RingBufferIsEmpty(ringbuffer))
- return NULL;
+Packet *PacketPoolGetPacket(void)
+{
+ PktPool *pool = &thread_pkt_pool;
+
+ if (pool->head) {
+ /* Stack is not empty. */
+ Packet *p = pool->head;
+ pool->head = p->next;
+ p->pool = pool;
+ return p;
+ }
+
+ /* Local Stack is empty, so check the return stack, which requires
+ * locking. */
+ SCMutexLock(&pool->return_mutex);
+ /* Move all the packets from the locked return stack to the local stack. */
+ pool->head = pool->return_head;
+ pool->return_head = NULL;
+ SCMutexUnlock(&pool->return_mutex);
+
+ /* Try to allocate again. Need to check for not empty again, since the
+ * return stack might have been empty too.
+ */
+ if (pool->head) {
+ /* Stack is not empty. */
+ Packet *p = pool->head;
+ pool->head = p->next;
+ p->pool = pool;
+ return p;
+ }
- Packet *p = RingBufferMrMwGetNoWait(ringbuffer);
- return p;
+ /* Failed to allocate a packet, so return NULL. */
+ /* Optionally, could allocate a new packet here. */
+ return NULL;
}
/** \brief Return packet to Packet pool
*/
void PacketPoolReturnPacket(Packet *p)
{
+ PktPool *pool = p->pool;
+ if (pool == NULL) {
+ free(p);
+ return;
+ }
+
PACKET_RECYCLE(p);
- RingBufferMrMwPut(ringbuffer, (void *)p);
+
+ if (pool == &thread_pkt_pool) {
+ /* Push back onto this thread's own stack, so no locking. */
+ p->next = thread_pkt_pool.head;
+ thread_pkt_pool.head = p;
+ } else {
+ /* Push onto return stack for this pool */
+ SCMutexLock(&pool->return_mutex);
+ p->next = pool->return_head;
+ pool->return_head = p;
+ SCMutexUnlock(&pool->return_mutex);
+ }
}
-void PacketPoolInit(intmax_t max_pending_packets) {
+void PacketPoolInit(void)
+{
+ extern intmax_t max_pending_packets;
+
+ SCMutexInit(&thread_pkt_pool.return_mutex, NULL);
+
/* pre allocate packets */
SCLogDebug("preallocating packets... packet size %" PRIuMAX "", (uintmax_t)SIZE_OF_PACKET);
int i = 0;
}
void PacketPoolDestroy(void) {
- if (ringbuffer == NULL) {
- return;
- }
-
+#if 0
Packet *p = NULL;
while ((p = PacketPoolGetPacket()) != NULL) {
PACKET_CLEANUP(p);
SCFree(p);
}
-
- RingBufferDestroy(ringbuffer);
- ringbuffer = NULL;
+#endif
}
-Packet *TmqhInputPacketpool(ThreadVars *t)
+Packet *TmqhInputPacketpool(ThreadVars *tv)
{
- Packet *p = NULL;
-
- while (p == NULL && ringbuffer->shutdown == FALSE) {
- p = RingBufferMrMwGet(ringbuffer);
- }
-
- /* packet is clean */
-
- return p;
+ return PacketPoolGetPacket();
}
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#ifndef __TMQH_PACKETPOOL_H__
#define __TMQH_PACKETPOOL_H__
+#include "decode.h"
+
+typedef struct PktPool_ {
+ /* link listed of free packets local to this thread. */
+ Packet *head;
+
+ /* Return stack, onto which other threads free packets. */
+ struct {
+ /* linked list of free packets. */
+ Packet *return_head;
+ SCMutex return_mutex;
+ } __attribute__((aligned(CLS)));
+} PktPool;
+
Packet *TmqhInputPacketpool(ThreadVars *);
void TmqhOutputPacketpool(ThreadVars *, Packet *);
void TmqhReleasePacketsToPacketPool(PacketQueue *);
-void TmqhPacketpoolRegister (void);
-void TmqhPacketpoolDestroy (void);
+void TmqhPacketpoolRegister(void);
Packet *PacketPoolGetPacket(void);
-uint16_t PacketPoolSize(void);
-void PacketPoolStorePacket(Packet *);
void PacketPoolWait(void);
void PacketPoolReturnPacket(Packet *p);
-void PacketPoolInit(intmax_t max_pending_packets);
+void PacketPoolInit(void);
void PacketPoolDestroy(void);
#endif /* __TMQH_PACKETPOOL_H__ */