Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/stream-tcp-cache.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 */
23
24
#include "suricata-common.h"
25
#include "suricata.h"
26
#include "stream-tcp-private.h"
27
#include "stream-tcp-cache.h"
28
#include "util-debug.h"
29
30
typedef struct TcpPoolCache {
31
    bool cache_enabled; /**< cache should only be enabled for worker threads */
32
    TcpSegment *segs_cache[64];
33
    uint32_t segs_cache_idx;
34
    uint32_t segs_returns_idx;
35
    TcpSegment *segs_returns[64];
36
37
    TcpSession *ssns_cache[64];
38
    uint32_t ssns_cache_idx;
39
    uint32_t ssns_returns_idx;
40
    TcpSession *ssns_returns[64];
41
} TcpPoolCache;
42
43
static thread_local TcpPoolCache tcp_pool_cache;
44
extern PoolThread *ssn_pool;
45
extern PoolThread *segment_thread_pool;
46
47
/** \brief enable segment cache. Should only be done for worker threads */
48
void StreamTcpThreadCacheEnable(void)
49
4
{
50
4
    tcp_pool_cache.cache_enabled = true;
51
4
}
52
53
void StreamTcpThreadCacheReturnSegment(TcpSegment *seg)
54
4.54M
{
55
4.54M
    SCEnter();
56
#ifdef UNITTESTS
57
    if (RunmodeIsUnittests()) {
58
        PoolThreadReturn(segment_thread_pool, seg);
59
        SCReturn;
60
    }
61
#endif
62
63
    /* cache can have segs from any pool id */
64
4.54M
    if (tcp_pool_cache.cache_enabled && tcp_pool_cache.segs_cache_idx < 64) {
65
2.31M
        tcp_pool_cache.segs_cache[tcp_pool_cache.segs_cache_idx++] = seg;
66
2.31M
    } else {
67
        /* segs_returns should only have a single pool id. If ours is different,
68
         * flush it. */
69
2.23M
        bool flush = false;
70
2.23M
        if (tcp_pool_cache.segs_returns_idx &&
71
2.23M
                tcp_pool_cache.segs_returns[0]->pool_id != seg->pool_id) {
72
0
            flush = true;
73
0
        }
74
2.23M
        if (tcp_pool_cache.segs_returns_idx == 64) {
75
34.8k
            flush = true;
76
34.8k
        }
77
78
2.23M
        if (flush) {
79
34.8k
            PoolThreadId pool_id = tcp_pool_cache.segs_returns[0]->pool_id;
80
34.8k
            PoolThreadLock(segment_thread_pool, pool_id);
81
2.26M
            for (uint32_t i = 0; i < tcp_pool_cache.segs_returns_idx; i++) {
82
2.23M
                TcpSegment *ret_seg = tcp_pool_cache.segs_returns[i];
83
2.23M
                PoolThreadReturnRaw(segment_thread_pool, pool_id, ret_seg);
84
2.23M
            }
85
34.8k
            PoolThreadUnlock(segment_thread_pool, pool_id);
86
34.8k
            tcp_pool_cache.segs_returns_idx = 0;
87
34.8k
        }
88
89
2.23M
        tcp_pool_cache.segs_returns[tcp_pool_cache.segs_returns_idx++] = seg;
90
2.23M
    }
91
4.54M
}
92
93
void StreamTcpThreadCacheReturnSession(TcpSession *ssn)
94
260k
{
95
260k
    SCEnter();
96
#ifdef UNITTESTS
97
    if (RunmodeIsUnittests()) {
98
        PoolThreadReturn(ssn_pool, ssn);
99
        SCReturn;
100
    }
101
#endif
102
103
    /* cache can have ssns from any pool id */
104
260k
    if (tcp_pool_cache.cache_enabled && tcp_pool_cache.ssns_cache_idx < 64) {
105
258k
        tcp_pool_cache.ssns_cache[tcp_pool_cache.ssns_cache_idx++] = ssn;
106
258k
    } else {
107
        /* ssns_returns should only have a single pool id. If ours is different,
108
         * flush it. */
109
1.45k
        bool flush = false;
110
1.45k
        if (tcp_pool_cache.ssns_returns_idx &&
111
1.45k
                tcp_pool_cache.ssns_returns[0]->pool_id != ssn->pool_id) {
112
0
            flush = true;
113
0
        }
114
1.45k
        if (tcp_pool_cache.ssns_returns_idx == 64) {
115
21
            flush = true;
116
21
        }
117
118
1.45k
        if (flush) {
119
21
            PoolThreadId pool_id = tcp_pool_cache.ssns_returns[0]->pool_id;
120
21
            PoolThreadLock(ssn_pool, pool_id);
121
1.36k
            for (uint32_t i = 0; i < tcp_pool_cache.ssns_returns_idx; i++) {
122
1.34k
                TcpSession *ret_ssn = tcp_pool_cache.ssns_returns[i];
123
1.34k
                PoolThreadReturnRaw(ssn_pool, pool_id, ret_ssn);
124
1.34k
            }
125
21
            PoolThreadUnlock(ssn_pool, pool_id);
126
21
            tcp_pool_cache.ssns_returns_idx = 0;
127
21
        }
128
129
1.45k
        tcp_pool_cache.ssns_returns[tcp_pool_cache.ssns_returns_idx++] = ssn;
130
1.45k
    }
131
260k
    SCReturn;
132
260k
}
133
134
void StreamTcpThreadCacheCleanup(void)
135
0
{
136
0
    SCEnter();
137
138
    /* segments */
139
0
    SCLogDebug("tcp_pool_cache.segs_cache_idx %u", tcp_pool_cache.segs_cache_idx);
140
0
    for (uint32_t i = 0; i < tcp_pool_cache.segs_cache_idx; i++) {
141
0
        PoolThreadReturn(segment_thread_pool, tcp_pool_cache.segs_cache[i]);
142
0
    }
143
0
    tcp_pool_cache.segs_cache_idx = 0;
144
145
0
    SCLogDebug("tcp_pool_cache.segs_returns_idx %u", tcp_pool_cache.segs_returns_idx);
146
0
    if (tcp_pool_cache.segs_returns_idx) {
147
0
        PoolThreadId pool_id = tcp_pool_cache.segs_returns[0]->pool_id;
148
0
        PoolThreadLock(segment_thread_pool, pool_id);
149
0
        for (uint32_t i = 0; i < tcp_pool_cache.segs_returns_idx; i++) {
150
0
            TcpSegment *ret_seg = tcp_pool_cache.segs_returns[i];
151
0
            PoolThreadReturnRaw(segment_thread_pool, pool_id, ret_seg);
152
0
        }
153
0
        PoolThreadUnlock(segment_thread_pool, pool_id);
154
0
        tcp_pool_cache.segs_returns_idx = 0;
155
0
    }
156
157
    /* sessions */
158
0
    SCLogDebug("tcp_pool_cache.ssns_cache_idx %u", tcp_pool_cache.ssns_cache_idx);
159
0
    for (uint32_t i = 0; i < tcp_pool_cache.ssns_cache_idx; i++) {
160
0
        PoolThreadReturn(ssn_pool, tcp_pool_cache.ssns_cache[i]);
161
0
    }
162
0
    tcp_pool_cache.ssns_cache_idx = 0;
163
164
0
    SCLogDebug("tcp_pool_cache.ssns_returns_idx %u", tcp_pool_cache.ssns_returns_idx);
165
0
    if (tcp_pool_cache.ssns_returns_idx) {
166
0
        PoolThreadId pool_id = tcp_pool_cache.ssns_returns[0]->pool_id;
167
0
        PoolThreadLock(ssn_pool, pool_id);
168
0
        for (uint32_t i = 0; i < tcp_pool_cache.ssns_returns_idx; i++) {
169
0
            TcpSession *ret_ssn = tcp_pool_cache.ssns_returns[i];
170
0
            PoolThreadReturnRaw(ssn_pool, pool_id, ret_ssn);
171
0
        }
172
0
        PoolThreadUnlock(ssn_pool, pool_id);
173
0
        tcp_pool_cache.ssns_returns_idx = 0;
174
0
    }
175
176
0
    SCReturn;
177
0
}
178
179
TcpSegment *StreamTcpThreadCacheGetSegment(void)
180
4.54M
{
181
4.54M
    if (tcp_pool_cache.segs_cache_idx) {
182
2.31M
        TcpSegment *seg = tcp_pool_cache.segs_cache[tcp_pool_cache.segs_cache_idx - 1];
183
2.31M
        tcp_pool_cache.segs_cache_idx--;
184
2.31M
        memset(&seg->sbseg, 0, sizeof(seg->sbseg));
185
2.31M
        return seg;
186
2.31M
    }
187
2.23M
    return NULL;
188
4.54M
}
189
190
TcpSession *StreamTcpThreadCacheGetSession(void)
191
260k
{
192
260k
    if (tcp_pool_cache.ssns_cache_idx) {
193
258k
        TcpSession *ssn = tcp_pool_cache.ssns_cache[tcp_pool_cache.ssns_cache_idx - 1];
194
258k
        tcp_pool_cache.ssns_cache_idx--;
195
258k
        return ssn;
196
258k
    }
197
1.63k
    return NULL;
198
260k
}