af-packet: improve error handling

Stress condition in Suricata could lead to interface to disconnect
when it is not necessary. This patch updates the error handling
code to try to continue reading when such a case occurs.
pull/3539/head
Eric Leblond 6 years ago
parent 3fdc6183b0
commit b5f5ef7eba

@ -172,7 +172,8 @@ static SCMutex afpacket_bpf_set_filter_lock = SCMUTEX_INITIALIZER;
enum {
AFP_READ_OK,
AFP_READ_FAILURE,
AFP_FAILURE,
/** Error during treatment by other functions of Suricata */
AFP_SURI_FAILURE,
AFP_KERNEL_DROP,
};
@ -215,6 +216,7 @@ typedef struct AFPThreadVars_
/* references to packet and drop counters */
uint16_t capture_kernel_packets;
uint16_t capture_kernel_drops;
uint16_t capture_errors;
/* handle state */
uint8_t afp_state;
@ -594,7 +596,7 @@ static int AFPRead(AFPThreadVars *ptv)
p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
PKT_SET_SRC(p, PKT_SRC_WIRE);
@ -620,7 +622,7 @@ static int AFPRead(AFPThreadVars *ptv)
SET_PKT_LEN(p, caplen + offset);
if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) {
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)",
GET_PKT_LEN(p), p, GET_PKT_DATA(p));
@ -660,7 +662,7 @@ static int AFPRead(AFPThreadVars *ptv)
if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
SCReturnInt(AFP_READ_OK);
}
@ -824,8 +826,10 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
/* Read packet from ring */
h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]);
if (h.raw == NULL) {
SCReturnInt(AFP_FAILURE);
if (unlikely(h.raw == NULL)) {
/* Impossible we reach this point in normal condition, so trigger
* a failure in reading */
SCReturnInt(AFP_READ_FAILURE);
}
if ((! h.h2->tp_status) || (h.h2->tp_status & TP_STATUS_USER_BUSY)) {
@ -863,7 +867,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
PKT_SET_SRC(p, PKT_SRC_WIRE);
@ -892,7 +896,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
if (ptv->flags & AFP_ZERO_COPY) {
if (PacketSetData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) {
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
} else {
p->afp_v.relptr = h.raw;
p->ReleasePacket = AFPReleasePacket;
@ -908,8 +912,15 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
}
} else {
if (PacketCopyData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) {
/* As we can possibly fail to copy the data due to invalid data, let's
* skip this packet and switch to the next one.
*/
h.h2->tp_status = TP_STATUS_KERNEL;
if (++ptv->frame_offset >= ptv->req.tp_frame_nr) {
ptv->frame_offset = 0;
}
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
}
/* Timestamp */
@ -951,7 +962,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
ptv->frame_offset = 0;
}
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
next_frame:
@ -975,7 +986,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
{
Packet *p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
PKT_SET_SRC(p, PKT_SRC_WIRE);
@ -993,7 +1004,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
if (ptv->flags & AFP_ZERO_COPY) {
if (PacketSetData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) {
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
p->afp_v.relptr = ppd;
p->ReleasePacket = AFPReleasePacketV3;
@ -1009,7 +1020,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
} else {
if (PacketCopyData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) {
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
}
/* Timestamp */
@ -1038,7 +1049,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
TmqhOutputPacketpool(ptv->tv, p);
SCReturnInt(AFP_FAILURE);
SCReturnInt(AFP_SURI_FAILURE);
}
SCReturnInt(AFP_READ_OK);
@ -1048,12 +1059,23 @@ static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pb
{
int num_pkts = pbd->hdr.bh1.num_pkts, i;
uint8_t *ppd;
int ret = 0;
ppd = (uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt;
for (i = 0; i < num_pkts; ++i) {
if (unlikely(AFPParsePacketV3(ptv, pbd,
(struct tpacket3_hdr *)ppd) == AFP_FAILURE)) {
SCReturnInt(AFP_READ_FAILURE);
ret = AFPParsePacketV3(ptv, pbd,
(struct tpacket3_hdr *)ppd);
switch (ret) {
case AFP_READ_OK:
break;
case AFP_SURI_FAILURE:
/* Internal error but let's just continue and
* treat thenext packet */
break;
case AFP_READ_FAILURE:
SCReturnInt(AFP_READ_FAILURE);
default:
SCReturnInt(ret);
}
ppd = ppd + ((struct tpacket3_hdr *)ppd)->tp_next_offset;
}
@ -1075,6 +1097,7 @@ static int AFPReadFromRingV3(AFPThreadVars *ptv)
{
#ifdef HAVE_TPACKET_V3
struct tpacket_block_desc *pbd;
int ret = 0;
/* Loop till we have packets available */
while (1) {
@ -1090,9 +1113,10 @@ static int AFPReadFromRingV3(AFPThreadVars *ptv)
SCReturnInt(AFP_READ_OK);
}
if (unlikely(AFPWalkBlock(ptv, pbd) != AFP_READ_OK)) {
ret = AFPWalkBlock(ptv, pbd);
if (unlikely(ret != AFP_READ_OK)) {
AFPFlushBlock(pbd);
SCReturnInt(AFP_READ_FAILURE);
SCReturnInt(ret);
}
AFPFlushBlock(pbd);
@ -1496,9 +1520,8 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot)
ptv->iface, errno, strerror(errno));
AFPSwitchState(ptv, AFP_STATE_DOWN);
continue;
case AFP_FAILURE:
AFPSwitchState(ptv, AFP_STATE_DOWN);
SCReturnInt(TM_ECODE_FAILED);
case AFP_SURI_FAILURE:
StatsIncr(ptv->tv, ptv->capture_errors);
break;
case AFP_KERNEL_DROP:
AFPDumpCounters(ptv);
@ -2199,6 +2222,8 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data)
ptv->tv);
ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops",
ptv->tv);
ptv->capture_errors = StatsRegisterCounter("capture.errors",
ptv->tv);
#endif
ptv->copy_mode = afpconfig->copy_mode;

Loading…
Cancel
Save