From 54eade75b718f73244ba1ee88a82f296fa7afcf3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 24 Jul 2023 20:33:35 +0200 Subject: [PATCH 1/5] stats: simplify ips capture stats logic Since many implementations use the ReleasePacket callback to issue their verdict, no thread ctx is available. To work around this just register the stats in a `thread_local` variable instead. --- src/decode.c | 15 +++++++++++++-- src/decode.h | 13 ++----------- src/source-nfq.c | 7 ++----- src/source-windivert.c | 5 ++--- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/decode.c b/src/decode.c index a91ea2606694..43220543bf1e 100644 --- a/src/decode.c +++ b/src/decode.c @@ -822,9 +822,19 @@ const char *PacketDropReasonToString(enum PacketDropReason r) return NULL; } +typedef struct CaptureStats_ { + uint16_t counter_ips_accepted; + uint16_t counter_ips_blocked; + uint16_t counter_ips_rejected; + uint16_t counter_ips_replaced; +} CaptureStats; + +thread_local CaptureStats t_capture_stats; + /* TODO drop reason stats! */ -void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p) +void CaptureStatsUpdate(ThreadVars *tv, const Packet *p) { + CaptureStats *s = &t_capture_stats; if (unlikely(PacketCheckAction(p, ACTION_REJECT_ANY))) { StatsIncr(tv, s->counter_ips_rejected); } else if (unlikely(PacketCheckAction(p, ACTION_DROP))) { @@ -836,8 +846,9 @@ void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p) } } -void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s) +void CaptureStatsSetup(ThreadVars *tv) { + CaptureStats *s = &t_capture_stats; s->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); diff --git a/src/decode.h b/src/decode.h index 0627bea7f216..b50324c98d1b 100644 --- a/src/decode.h +++ b/src/decode.h @@ -749,17 +749,8 @@ typedef struct DecodeThreadVars_ } DecodeThreadVars; -typedef struct CaptureStats_ { - - uint16_t counter_ips_accepted; - uint16_t counter_ips_blocked; - uint16_t counter_ips_rejected; - uint16_t counter_ips_replaced; - -} CaptureStats; - -void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p); -void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s); +void CaptureStatsUpdate(ThreadVars *tv, const Packet *p); +void CaptureStatsSetup(ThreadVars *tv); #define PACKET_CLEAR_L4VARS(p) do { \ memset(&(p)->l4vars, 0x00, sizeof((p)->l4vars)); \ diff --git a/src/source-nfq.c b/src/source-nfq.c index 2262f10730f9..5c3d7a39f83e 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -120,8 +120,6 @@ typedef struct NFQThreadVars_ char *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ - - CaptureStats stats; } NFQThreadVars; /* shared vars for all for nfq queues and threads */ static NFQGlobalVars nfq_g; @@ -779,7 +777,7 @@ TmEcode VerdictNFQThreadInit(ThreadVars *tv, const void *initdata, void **data) { NFQThreadVars *ntv = (NFQThreadVars *) initdata; - CaptureStatsSetup(tv, &ntv->stats); + CaptureStatsSetup(tv); *data = (void *)ntv; return TM_ECODE_OK; @@ -1191,9 +1189,8 @@ TmEcode NFQSetVerdict(Packet *p) */ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data) { - NFQThreadVars *ntv = (NFQThreadVars *)data; /* update counters */ - CaptureStatsUpdate(tv, &ntv->stats, p); + CaptureStatsUpdate(tv, p); /* if this is a tunnel packet we check if we are ready to verdict * already. */ diff --git a/src/source-windivert.c b/src/source-windivert.c index f0d956973de5..89bf8009eaae 100644 --- a/src/source-windivert.c +++ b/src/source-windivert.c @@ -95,7 +95,6 @@ typedef struct WinDivertThreadVars_ { WinDivertHandle filter_handle; int thread_num; - CaptureStats stats; int64_t qpc_start_time; int64_t qpc_start_count; int64_t qpc_freq_usec; @@ -750,7 +749,7 @@ static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p) WinDivertThreadVars *wd_tv = WinDivertGetThread(p->windivert_v.thread_num); /* update counters */ - CaptureStatsUpdate(tv, &wd_tv->stats, p); + CaptureStatsUpdate(tv, p); #ifdef COUNTERS WinDivertQueueVars *wd_qv = WinDivertGetQueue(wd_tv->thread_num); @@ -823,7 +822,7 @@ TmEcode VerdictWinDivertThreadInit(ThreadVars *tv, const void *initdata, WinDivertThreadVars *wd_tv = (WinDivertThreadVars *)initdata; - CaptureStatsSetup(tv, &wd_tv->stats); + CaptureStatsSetup(tv); *data = wd_tv; From 100b0a8b6280528e8dae98b79dffb2c810dcdef8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 24 Jul 2023 21:08:00 +0200 Subject: [PATCH 2/5] eve/schema: add ips capture stats --- etc/schema.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/etc/schema.json b/etc/schema.json index f1936fb195be..b5238373493b 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -4013,6 +4013,24 @@ }, "additionalProperties": false }, + "ips": { + "type": "object", + "properties": { + "accepted": { + "type": "integer" + }, + "blocked": { + "type": "integer" + }, + "rejected": { + "type": "integer" + }, + "replaced": { + "type": "integer" + } + }, + "additionalProperties": false + }, "decoder": { "type": "object", "properties": { From 485eca5673c70cfd61d609eaa2a9877aab4ab518 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 24 Jul 2023 21:09:10 +0200 Subject: [PATCH 3/5] stats: register ips capture stats for each packet thread ReleasePacket based verdicts can happen in several threads, depending on the runmode details. Only register and update if in IPS mode. --- src/decode.c | 15 ++++++++++----- src/source-nfq.c | 5 +---- src/source-windivert.c | 3 --- src/tm-threads.c | 3 ++- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/decode.c b/src/decode.c index 43220543bf1e..90d755ba78c5 100644 --- a/src/decode.c +++ b/src/decode.c @@ -834,6 +834,9 @@ thread_local CaptureStats t_capture_stats; /* TODO drop reason stats! */ void CaptureStatsUpdate(ThreadVars *tv, const Packet *p) { + if (!EngineModeIsIPS() || PKT_IS_PSEUDOPKT(p)) + return; + CaptureStats *s = &t_capture_stats; if (unlikely(PacketCheckAction(p, ACTION_REJECT_ANY))) { StatsIncr(tv, s->counter_ips_rejected); @@ -848,11 +851,13 @@ void CaptureStatsUpdate(ThreadVars *tv, const Packet *p) void CaptureStatsSetup(ThreadVars *tv) { - CaptureStats *s = &t_capture_stats; - s->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); - s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); - s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); - s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); + if (EngineModeIsIPS()) { + CaptureStats *s = &t_capture_stats; + s->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); + s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); + s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); + s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); + } } void DecodeGlobalConfig(void) diff --git a/src/source-nfq.c b/src/source-nfq.c index 5c3d7a39f83e..cad4e2c7d7db 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -775,10 +775,7 @@ TmEcode ReceiveNFQThreadDeinit(ThreadVars *t, void *data) TmEcode VerdictNFQThreadInit(ThreadVars *tv, const void *initdata, void **data) { - NFQThreadVars *ntv = (NFQThreadVars *) initdata; - - CaptureStatsSetup(tv); - + NFQThreadVars *ntv = (NFQThreadVars *)initdata; *data = (void *)ntv; return TM_ECODE_OK; } diff --git a/src/source-windivert.c b/src/source-windivert.c index 89bf8009eaae..6a3d36601517 100644 --- a/src/source-windivert.c +++ b/src/source-windivert.c @@ -821,9 +821,6 @@ TmEcode VerdictWinDivertThreadInit(ThreadVars *tv, const void *initdata, SCEnter(); WinDivertThreadVars *wd_tv = (WinDivertThreadVars *)initdata; - - CaptureStatsSetup(tv); - *data = wd_tv; SCReturnInt(TM_ECODE_OK); diff --git a/src/tm-threads.c b/src/tm-threads.c index 361bad6df0b6..7bc1172a42d6 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -242,7 +242,7 @@ static void *TmThreadsSlotPktAcqLoop(void *td) /* Drop the capabilities for this thread */ SCDropCaps(tv); - + CaptureStatsSetup(tv); PacketPoolInit(); /* check if we are setup properly */ @@ -372,6 +372,7 @@ static void *TmThreadsSlotVar(void *td) char run = 1; TmEcode r = TM_ECODE_OK; + CaptureStatsSetup(tv); PacketPoolInit();//Empty(); SCSetThreadName(tv->name); From ad0bdb8d62a45eb015511f26a506d1be048ef476 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 24 Jul 2023 22:13:52 +0200 Subject: [PATCH 4/5] stats: update ips capture counters centrally This adds support to all capture methods for these counters. Ticket: #4756. --- src/source-nfq.c | 3 --- src/source-windivert.c | 3 --- src/tmqh-packetpool.c | 4 ++++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index cad4e2c7d7db..5293f2529a4c 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1186,9 +1186,6 @@ TmEcode NFQSetVerdict(Packet *p) */ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data) { - /* update counters */ - CaptureStatsUpdate(tv, p); - /* if this is a tunnel packet we check if we are ready to verdict * already. */ if (IS_TUNNEL_PKT(p)) { diff --git a/src/source-windivert.c b/src/source-windivert.c index 6a3d36601517..5625b7f0f56f 100644 --- a/src/source-windivert.c +++ b/src/source-windivert.c @@ -748,9 +748,6 @@ static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p) SCEnter(); WinDivertThreadVars *wd_tv = WinDivertGetThread(p->windivert_v.thread_num); - /* update counters */ - CaptureStatsUpdate(tv, p); - #ifdef COUNTERS WinDivertQueueVars *wd_qv = WinDivertGetQueue(wd_tv->thread_num); #endif /* COUNTERS */ diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 5d77e416243d..350fcd752f47 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -429,6 +429,9 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) SCSpinUnlock(lock); SCLogDebug("tunnel stuff done, move on (proot %d)", proot); + + } else { + CaptureStatsUpdate(t, p); } SCLogDebug("[packet %p][%s] %s", p, @@ -440,6 +443,7 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) if (proot == true) { SCLogDebug("getting rid of root pkt... alloc'd %s", BOOL2STR(p->root->pool == NULL)); + CaptureStatsUpdate(t, p->root); PacketReleaseRefs(p->root); p->root->ReleasePacket(p->root); p->root = NULL; From 7e580ed20e96d52d068647902a3beae8e982af77 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Jul 2023 07:51:02 +0200 Subject: [PATCH 5/5] stats: add drop reason counters { "accepted": 296185, "blocked": 162, "rejected": 0, "replaced": 0, "drop_reason": { "decode_error": 0, "defrag_error": 0, "defrag_memcap": 0, "flow_memcap": 0, "flow_drop": 94, "applayer_error": 0, "applayer_memcap": 0, "rules": 3, "threshold_detection_filter": 0, "stream_error": 63, "stream_memcap": 0, "stream_midstream": 2, "nfq_error": 0, "tunnel_packet_drop": 0 } } Ticket: #6230. --- etc/schema.json | 48 +++++++++++++++++++++++++++++++++++++++++++++++ src/decode.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- src/decode.h | 1 + 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/etc/schema.json b/etc/schema.json index b5238373493b..f9ea5c9f3808 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -4027,6 +4027,54 @@ }, "replaced": { "type": "integer" + }, + "drop_reason": { + "type": "object", + "properties": { + "decode_error": { + "type": "integer" + }, + "defrag_error": { + "type": "integer" + }, + "defrag_memcap": { + "type": "integer" + }, + "flow_memcap": { + "type": "integer" + }, + "flow_drop": { + "type": "integer" + }, + "applayer_error": { + "type": "integer" + }, + "applayer_memcap": { + "type": "integer" + }, + "rules": { + "type": "integer" + }, + "threshold_detection_filter": { + "type": "integer" + }, + "stream_error": { + "type": "integer" + }, + "stream_memcap": { + "type": "integer" + }, + "stream_midstream": { + "type": "integer" + }, + "nfq_error": { + "type": "integer" + }, + "tunnel_packet_drop": { + "type": "integer" + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/src/decode.c b/src/decode.c index 90d755ba78c5..b49b29838cab 100644 --- a/src/decode.c +++ b/src/decode.c @@ -817,6 +817,45 @@ const char *PacketDropReasonToString(enum PacketDropReason r) case PKT_DROP_REASON_INNER_PACKET: return "tunnel packet drop"; case PKT_DROP_REASON_NOT_SET: + case PKT_DROP_REASON_MAX: + return NULL; + } + return NULL; +} + +static const char *PacketDropReasonToJsonString(enum PacketDropReason r) +{ + switch (r) { + case PKT_DROP_REASON_DECODE_ERROR: + return "ips.drop_reason.decode_error"; + case PKT_DROP_REASON_DEFRAG_ERROR: + return "ips.drop_reason.defrag_error"; + case PKT_DROP_REASON_DEFRAG_MEMCAP: + return "ips.drop_reason.defrag_memcap"; + case PKT_DROP_REASON_FLOW_MEMCAP: + return "ips.drop_reason.flow_memcap"; + case PKT_DROP_REASON_FLOW_DROP: + return "ips.drop_reason.flow_drop"; + case PKT_DROP_REASON_STREAM_ERROR: + return "ips.drop_reason.stream_error"; + case PKT_DROP_REASON_STREAM_MEMCAP: + return "ips.drop_reason.stream_memcap"; + case PKT_DROP_REASON_STREAM_MIDSTREAM: + return "ips.drop_reason.stream_midstream"; + case PKT_DROP_REASON_APPLAYER_ERROR: + return "ips.drop_reason.applayer_error"; + case PKT_DROP_REASON_APPLAYER_MEMCAP: + return "ips.drop_reason.applayer_memcap"; + case PKT_DROP_REASON_RULES: + return "ips.drop_reason.rules"; + case PKT_DROP_REASON_RULES_THRESHOLD: + return "ips.drop_reason.threshold_detection_filter"; + case PKT_DROP_REASON_NFQ_ERROR: + return "ips.drop_reason.nfq_error"; + case PKT_DROP_REASON_INNER_PACKET: + return "ips.drop_reason.tunnel_packet_drop"; + case PKT_DROP_REASON_NOT_SET: + case PKT_DROP_REASON_MAX: return NULL; } return NULL; @@ -827,11 +866,12 @@ typedef struct CaptureStats_ { uint16_t counter_ips_blocked; uint16_t counter_ips_rejected; uint16_t counter_ips_replaced; + + uint16_t counter_drop_reason[PKT_DROP_REASON_MAX]; } CaptureStats; thread_local CaptureStats t_capture_stats; -/* TODO drop reason stats! */ void CaptureStatsUpdate(ThreadVars *tv, const Packet *p) { if (!EngineModeIsIPS() || PKT_IS_PSEUDOPKT(p)) @@ -847,6 +887,9 @@ void CaptureStatsUpdate(ThreadVars *tv, const Packet *p) } else { StatsIncr(tv, s->counter_ips_accepted); } + if (p->drop_reason != PKT_DROP_REASON_NOT_SET) { + StatsIncr(tv, s->counter_drop_reason[p->drop_reason]); + } } void CaptureStatsSetup(ThreadVars *tv) @@ -857,6 +900,11 @@ void CaptureStatsSetup(ThreadVars *tv) s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); + for (int i = PKT_DROP_REASON_NOT_SET; i < PKT_DROP_REASON_MAX; i++) { + const char *name = PacketDropReasonToJsonString(i); + if (name != NULL) + s->counter_drop_reason[i] = StatsRegisterCounter(name, tv); + } } } diff --git a/src/decode.h b/src/decode.h index b50324c98d1b..fe42924bb628 100644 --- a/src/decode.h +++ b/src/decode.h @@ -403,6 +403,7 @@ enum PacketDropReason { PKT_DROP_REASON_STREAM_MIDSTREAM, PKT_DROP_REASON_NFQ_ERROR, /**< no nfq verdict, must be error */ PKT_DROP_REASON_INNER_PACKET, /**< drop issued by inner (tunnel) packet */ + PKT_DROP_REASON_MAX, }; /* forward declaration since Packet struct definition requires this */