Fix NFQ receive/verdict race condition in cases where the packetpool is empty.

remotes/origin/master-1.0.x
Victor Julien 16 years ago
parent 647b1c0eba
commit bb685751d9

@ -46,16 +46,16 @@ void DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
} }
/** /**
* \brief Get a pseudo packet for tunnels and defrag reassembly. We try to * \brief Get a packet. We try to get a packet from the packet_q first, but
* get a packet from the packet_q first, but if that is empty we alloc * if that is empty we alloc a packet that is free'd again after
* a packet that is free'd again after processing. * processing.
* *
* \retval p packet, NULL on error * \retval p packet, NULL on error
*/ */
static Packet *PacketGetPseudoPkt (void) Packet *PacketGetFromQueueOrAlloc(void) {
{
Packet *p = NULL; Packet *p = NULL;
/* try the queue first */
SCMutexLock(&packet_q.mutex_q); SCMutexLock(&packet_q.mutex_q);
p = PacketDequeue(&packet_q); p = PacketDequeue(&packet_q);
SCMutexUnlock(&packet_q.mutex_q); SCMutexUnlock(&packet_q.mutex_q);
@ -90,7 +90,7 @@ static Packet *PacketGetPseudoPkt (void)
Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto) Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto)
{ {
/* get us a packet */ /* get us a packet */
Packet *p = PacketGetPseudoPkt(); Packet *p = PacketGetFromQueueOrAlloc();
if (p == NULL) { if (p == NULL) {
return NULL; return NULL;
} }

@ -488,6 +488,7 @@ typedef struct DecodeThreadVars_
void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *);
Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto); Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto);
Packet *PacketGetFromQueueOrAlloc(void);
/* decoder functions */ /* decoder functions */
void DecodeEthernet(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeEthernet(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *);

@ -204,7 +204,11 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
ThreadVars *tv = ntv->tv; ThreadVars *tv = ntv->tv;
/* grab a packet */ /* grab a packet */
Packet *p = tv->tmqh_in(tv); Packet *p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
return -1;
}
NFQSetupPkt(p, (void *)nfa); NFQSetupPkt(p, (void *)nfa);
#ifdef COUNTERS #ifdef COUNTERS
@ -399,8 +403,7 @@ void NFQRecvPkt(NFQThreadVars *t) {
rv = recv(t->fd, buf, sizeof(buf), 0); rv = recv(t->fd, buf, sizeof(buf), 0);
if (rv < 0) { if (rv < 0) {
if (errno == EINTR || errno == EWOULDBLOCK if (errno == EINTR || errno == EWOULDBLOCK) {
) {
/* no error on timeout */ /* no error on timeout */
} else { } else {
#ifdef COUNTERS #ifdef COUNTERS
@ -497,6 +500,15 @@ process_rv:
TmEcode ReceiveNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { TmEcode ReceiveNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) {
NFQThreadVars *ntv = (NFQThreadVars *)data; NFQThreadVars *ntv = (NFQThreadVars *)data;
/* make sure we have at least one packet in the packet pool, to prevent
* us from 1) alloc'ing packets at line rate, 2) have a race condition
* for the nfq mutex lock with the verdict thread. */
SCMutexLock(&packet_q.mutex_q);
if (packet_q.len == 0) {
SCondWait(&packet_q.cond_q, &packet_q.mutex_q);
}
SCMutexUnlock(&packet_q.mutex_q);
/* do our nfq magic */ /* do our nfq magic */
NFQRecvPkt(ntv); NFQRecvPkt(ntv);

Loading…
Cancel
Save