suricata
tmqh-packetpool.c
Go to the documentation of this file.
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  * Packetpool queue handlers. Packet pool is implemented as a stack.
24  */
25 
26 #include "suricata-common.h"
27 #include "tmqh-packetpool.h"
28 #include "tm-queuehandlers.h"
29 #include "tm-threads.h"
30 #include "threads.h"
31 #include "decode.h"
32 #include "tm-modules.h"
33 #include "packet.h"
34 #include "util-profiling.h"
35 #include "util-validate.h"
36 #include "action-globals.h"
37 
38 extern uint32_t max_pending_packets;
39 
40 /* Number of freed packet to save for one pool before freeing them. */
41 #define MAX_PENDING_RETURN_PACKETS 32
42 static uint32_t max_pending_return_packets = MAX_PENDING_RETURN_PACKETS;
43 
44 thread_local PktPool thread_pkt_pool;
45 
46 static inline PktPool *GetThreadPacketPool(void)
47 {
48  return &thread_pkt_pool;
49 }
50 
51 /**
52  * \brief TmqhPacketpoolRegister
53  * \initonly
54  */
56 {
57  tmqh_table[TMQH_PACKETPOOL].name = "packetpool";
60 }
61 
62 static int PacketPoolIsEmpty(PktPool *pool)
63 {
64  /* Check local stack first. */
65  if (pool->head || pool->return_stack.head)
66  return 0;
67 
68  return 1;
69 }
70 
71 static void UpdateReturnThreshold(PktPool *pool)
72 {
73  const float perc = (float)pool->cnt / (float)max_pending_packets;
74  uint32_t threshold = (uint32_t)(perc * (float)max_pending_return_packets);
75  if (threshold != SC_ATOMIC_GET(pool->return_stack.return_threshold)) {
76  SC_ATOMIC_SET(pool->return_stack.return_threshold, threshold);
77  }
78 }
79 
80 void PacketPoolWait(void)
81 {
82  PktPool *my_pool = GetThreadPacketPool();
83 
84  if (PacketPoolIsEmpty(my_pool)) {
85  SC_ATOMIC_SET(my_pool->return_stack.return_threshold, 1);
86 
87  SCMutexLock(&my_pool->return_stack.mutex);
88  SCCondWait(&my_pool->return_stack.cond, &my_pool->return_stack.mutex);
89  SCMutexUnlock(&my_pool->return_stack.mutex);
90 
91  UpdateReturnThreshold(my_pool);
92  }
93 
94  while(PacketPoolIsEmpty(my_pool))
95  cc_barrier();
96 }
97 
98 /** \brief a initialized packet
99  *
100  * \warning Use *only* at init, not at packet runtime
101  */
102 static void PacketPoolStorePacket(Packet *p)
103 {
104  p->pool = GetThreadPacketPool();
107 }
108 
109 static void PacketPoolGetReturnedPackets(PktPool *pool)
110 {
111  SCMutexLock(&pool->return_stack.mutex);
112  /* Move all the packets from the locked return stack to the local stack. */
113  pool->head = pool->return_stack.head;
114  pool->return_stack.head = NULL;
115  pool->cnt += pool->return_stack.cnt;
116  pool->return_stack.cnt = 0;
117  SCMutexUnlock(&pool->return_stack.mutex);
118 }
119 
120 /** \brief Get a new packet from the packet pool
121  *
122  * Only allocates from the thread's local stack, or mallocs new packets.
123  * If the local stack is empty, first move all the return stack packets to
124  * the local stack.
125  * \retval Packet pointer, or NULL on failure.
126  */
128 {
129  PktPool *pool = GetThreadPacketPool();
130  DEBUG_VALIDATE_BUG_ON(pool->initialized == 0);
131  DEBUG_VALIDATE_BUG_ON(pool->destroyed == 1);
132  if (pool->head) {
133  /* Stack is not empty. */
134  Packet *p = pool->head;
135  pool->head = p->next;
136  pool->cnt--;
137  p->pool = pool;
138  PacketReinit(p);
139 
140  UpdateReturnThreshold(pool);
141  SCLogDebug("pp: %0.2f cnt:%u max:%d threshold:%u",
142  ((float)pool->cnt / (float)max_pending_packets) * (float)100, pool->cnt,
143  max_pending_packets, SC_ATOMIC_GET(pool->return_stack.return_threshold));
144  return p;
145  }
146 
147  /* Local Stack is empty, so check the return stack, which requires
148  * locking. */
149  PacketPoolGetReturnedPackets(pool);
150 
151  /* Try to allocate again. Need to check for not empty again, since the
152  * return stack might have been empty too.
153  */
154  if (pool->head) {
155  /* Stack is not empty. */
156  Packet *p = pool->head;
157  pool->head = p->next;
158  pool->cnt--;
159  p->pool = pool;
160  PacketReinit(p);
161 
162  UpdateReturnThreshold(pool);
163  SCLogDebug("pp: %0.2f cnt:%u max:%d threshold:%u",
164  ((float)pool->cnt / (float)max_pending_packets) * (float)100, pool->cnt,
165  max_pending_packets, SC_ATOMIC_GET(pool->return_stack.return_threshold));
166  return p;
167  }
168 
169  /* Failed to allocate a packet, so return NULL. */
170  /* Optionally, could allocate a new packet here. */
171  return NULL;
172 }
173 
174 /** \brief Return packet to Packet pool
175  *
176  */
178 {
179  PktPool *my_pool = GetThreadPacketPool();
180  PktPool *pool = p->pool;
181  if (pool == NULL) {
182  PacketFree(p);
183  return;
184  }
185 
187 
188 #ifdef DEBUG_VALIDATION
189  BUG_ON(pool->initialized == 0);
190  BUG_ON(pool->destroyed == 1);
191  BUG_ON(my_pool->initialized == 0);
192  BUG_ON(my_pool->destroyed == 1);
193 #endif /* DEBUG_VALIDATION */
194 
195  if (pool == my_pool) {
196  /* Push back onto this thread's own stack, so no locking. */
197  p->next = my_pool->head;
198  my_pool->head = p;
199  my_pool->cnt++;
200  } else {
201  PktPool *pending_pool = my_pool->pending_pool;
202  if (pending_pool == NULL || pending_pool == pool) {
203  if (pending_pool == NULL) {
204  /* No pending packet, so store the current packet. */
205  p->next = NULL;
206  my_pool->pending_pool = pool;
207  my_pool->pending_head = p;
208  my_pool->pending_tail = p;
209  my_pool->pending_count = 1;
210  } else if (pending_pool == pool) {
211  /* Another packet for the pending pool list. */
212  p->next = my_pool->pending_head;
213  my_pool->pending_head = p;
214  my_pool->pending_count++;
215  }
216 
217  const uint32_t threshold = SC_ATOMIC_GET(pool->return_stack.return_threshold);
218  if (my_pool->pending_count >= threshold) {
219  /* Return the entire list of pending packets. */
220  SCMutexLock(&pool->return_stack.mutex);
221  my_pool->pending_tail->next = pool->return_stack.head;
222  pool->return_stack.head = my_pool->pending_head;
223  pool->return_stack.cnt += my_pool->pending_count;
224  SCCondSignal(&pool->return_stack.cond);
225  SCMutexUnlock(&pool->return_stack.mutex);
226  /* Clear the list of pending packets to return. */
227  my_pool->pending_pool = NULL;
228  my_pool->pending_head = NULL;
229  my_pool->pending_tail = NULL;
230  my_pool->pending_count = 0;
231  }
232  } else {
233  /* Push onto return stack for this pool */
234  SCMutexLock(&pool->return_stack.mutex);
235  p->next = pool->return_stack.head;
236  pool->return_stack.head = p;
237  pool->return_stack.cnt++;
238  SCCondSignal(&pool->return_stack.cond);
239  SCMutexUnlock(&pool->return_stack.mutex);
240  }
241  }
242 }
243 
244 void PacketPoolInit(void)
245 {
246  PktPool *my_pool = GetThreadPacketPool();
247 
248 #ifdef DEBUG_VALIDATION
249  BUG_ON(my_pool->initialized);
250  my_pool->initialized = 1;
251  my_pool->destroyed = 0;
252 #endif /* DEBUG_VALIDATION */
253 
254  SCMutexInit(&my_pool->return_stack.mutex, NULL);
255  SCCondInit(&my_pool->return_stack.cond, NULL);
256  SC_ATOMIC_INIT(my_pool->return_stack.return_threshold);
257  SC_ATOMIC_SET(my_pool->return_stack.return_threshold, 32);
258 
259  /* pre allocate packets */
260  SCLogDebug("preallocating packets... packet size %" PRIuMAX "",
261  (uintmax_t)SIZE_OF_PACKET);
262  for (uint32_t i = 0; i < max_pending_packets; i++) {
263  Packet *p = PacketGetFromAlloc();
264  if (unlikely(p == NULL)) {
265  FatalError("Fatal error encountered while allocating a packet. Exiting...");
266  }
267  PacketPoolStorePacket(p);
268  }
269 
270  //SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"",
271  // max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET));
272 }
273 
275 {
276  Packet *p = NULL;
277  PktPool *my_pool = GetThreadPacketPool();
278 
279 #ifdef DEBUG_VALIDATION
280  BUG_ON(my_pool && my_pool->destroyed);
281 #endif /* DEBUG_VALIDATION */
282 
283  if (my_pool && my_pool->pending_pool != NULL) {
284  p = my_pool->pending_head;
285  while (p) {
286  Packet *next_p = p->next;
287  PacketFree(p);
288  p = next_p;
289  my_pool->pending_count--;
290  }
291 #ifdef DEBUG_VALIDATION
292  BUG_ON(my_pool->pending_count);
293 #endif /* DEBUG_VALIDATION */
294  my_pool->pending_pool = NULL;
295  my_pool->pending_head = NULL;
296  my_pool->pending_tail = NULL;
297  }
298 
299  while ((p = PacketPoolGetPacket()) != NULL) {
300  PacketFree(p);
301  }
302 
303 #ifdef DEBUG_VALIDATION
304  my_pool->initialized = 0;
305  my_pool->destroyed = 1;
306 #endif /* DEBUG_VALIDATION */
307 }
308 
310 {
311  return PacketPoolGetPacket();
312 }
313 
315 {
316  bool proot = false;
317 
318  SCEnter();
319  SCLogDebug("Packet %p, p->root %p, alloced %s", p, p->root, BOOL2STR(p->pool == NULL));
320 
321  if (PacketIsTunnel(p)) {
322  SCLogDebug("Packet %p is a tunnel packet: %s",
323  p,p->root ? "upper layer" : "tunnel root");
324 
325  /* get a lock to access root packet fields */
327  SCSpinLock(lock);
328 
329  if (PacketIsTunnelRoot(p)) {
330  SCLogDebug("IS_TUNNEL_ROOT_PKT == TRUE");
331  CaptureStatsUpdate(t, p); // TODO move out of lock
332 
333  const uint16_t outstanding = TUNNEL_PKT_TPR(p) - TUNNEL_PKT_RTV(p);
334  SCLogDebug("root pkt: outstanding %u", outstanding);
335  if (outstanding == 0) {
336  SCLogDebug("no tunnel packets outstanding, no more tunnel "
337  "packet(s) depending on this root");
338  /* if this packet is the root and there are no
339  * more tunnel packets to consider
340  *
341  * return it to the pool */
342  } else {
343  SCLogDebug("tunnel root Packet %p: outstanding > 0, so "
344  "packets are still depending on this root, setting "
345  "SET_TUNNEL_PKT_VERDICTED", p);
346  /* if this is the root and there are more tunnel
347  * packets, return this to the pool. It's still referenced
348  * by the tunnel packets, and we will return it
349  * when we handle them */
350  PacketTunnelSetVerdicted(p);
351 
354  SCReturn;
355  }
356  } else {
357  SCLogDebug("NOT IS_TUNNEL_ROOT_PKT, so tunnel pkt");
358 
360  const uint16_t outstanding = TUNNEL_PKT_TPR(p) - TUNNEL_PKT_RTV(p);
361  SCLogDebug("tunnel pkt: outstanding %u", outstanding);
362  /* all tunnel packets are processed except us. Root already
363  * processed. So return tunnel pkt and root packet to the
364  * pool. */
365  if (outstanding == 0 && p->root && PacketTunnelIsVerdicted(p->root)) {
366  SCLogDebug("root verdicted == true && no outstanding");
367 
368  /* handle freeing the root as well*/
369  SCLogDebug("setting proot = 1 for root pkt, p->root %p "
370  "(tunnel packet %p)", p->root, p);
371  proot = true;
372 
373  /* fall through */
374 
375  } else {
376  /* root not ready yet, or not the last tunnel packet,
377  * so get rid of the tunnel pkt only */
378 
379  SCLogDebug("NOT IS_TUNNEL_PKT_VERDICTED (%s) || "
380  "outstanding > 0 (%u)",
381  (p->root && PacketTunnelIsVerdicted(p->root)) ? "true" : "false",
382  outstanding);
383 
384  /* fall through */
385  }
386  }
388 
389  SCLogDebug("tunnel stuff done, move on (proot %d)", proot);
390 
391  } else {
392  CaptureStatsUpdate(t, p);
393  }
394 
395  SCLogDebug("[packet %p][%s] %s", p,
396  PacketIsTunnel(p) ? PacketIsTunnelRoot(p) ? "tunnel::root" : "tunnel::leaf"
397  : "no tunnel",
398  (p->action & ACTION_DROP) ? "DROP" : "no drop");
399 
400  /* we're done with the tunnel root now as well */
401  if (proot == true) {
402  SCLogDebug("getting rid of root pkt... alloc'd %s", BOOL2STR(p->root->pool == NULL));
403 
405  p->root->ReleasePacket(p->root);
406  p->root = NULL;
407  }
408 
410 
412  p->ReleasePacket(p);
413 
414  SCReturn;
415 }
416 
417 /**
418  * \brief Release all the packets in the queue back to the packetpool. Mainly
419  * used by threads that have failed, and wants to return the packets back
420  * to the packetpool.
421  *
422  * \param pq Pointer to the packetqueue from which the packets have to be
423  * returned back to the packetpool
424  *
425  * \warning this function assumes that the pq does not use locking
426  */
428 {
429  Packet *p = NULL;
430 
431  if (pq == NULL)
432  return;
433 
434  while ((p = PacketDequeue(pq)) != NULL) {
435  DEBUG_VALIDATE_BUG_ON(p->flow != NULL);
436  TmqhOutputPacketpool(NULL, p);
437  }
438 }
439 
440 /** number of packets to keep reserved when calculating the pending
441  * return packets count. This assumes we need at max 10 packets in one
442  * PacketPoolWaitForN call. The actual number is 9 now, so this has a
443  * bit of margin. */
444 #define RESERVED_PACKETS 10
445 
446 /**
447  * \brief Set the max_pending_return_packets value
448  *
449  * Set it to the max pending packets value, divided by the number
450  * of lister threads. Normally, in autofp these are the stream/detect/log
451  * worker threads.
452  *
453  * The max_pending_return_packets value needs to stay below the packet
454  * pool size of the 'producers' (normally pkt capture threads but also
455  * flow timeout injection ) to avoid a deadlock where all the 'workers'
456  * keep packets in their return pools, while the capture thread can't
457  * continue because its pool is empty.
458  */
460 {
461  extern uint32_t max_pending_packets;
462  uint32_t pending_packets = max_pending_packets;
463  if (pending_packets < RESERVED_PACKETS) {
464  FatalError("'max-pending-packets' setting "
465  "must be at least %d",
467  }
469  if (threads == 0)
470  return;
471 
472  uint32_t packets = (pending_packets / threads) - 1;
473  if (packets < max_pending_return_packets)
474  max_pending_return_packets = packets;
475 
476  /* make sure to have a margin in the return logic */
477  if (max_pending_return_packets >= RESERVED_PACKETS)
478  max_pending_return_packets -= RESERVED_PACKETS;
479 
480  SCLogDebug("detect threads %u, max packets %u, max_pending_return_packets %u",
481  threads, packets, max_pending_return_packets);
482 }
tm-threads.h
PktPool_::pending_tail
Packet * pending_tail
Definition: tmqh-packetpool.h:57
PktPool_::cnt
uint32_t cnt
Definition: tmqh-packetpool.h:48
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
PacketPoolReturnPacket
void PacketPoolReturnPacket(Packet *p)
Return packet to Packet pool.
Definition: tmqh-packetpool.c:177
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
Packet_::persistent
struct Packet_::@35 persistent
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
PktPool_
Definition: tmqh-packetpool.h:43
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
RESERVED_PACKETS
#define RESERVED_PACKETS
Definition: tmqh-packetpool.c:444
TM_FLAG_DETECT_TM
#define TM_FLAG_DETECT_TM
Definition: tm-modules.h:35
PacketQueue_
simple fifo queue for packets with mutex and cond Calling the mutex or triggering the cond is respons...
Definition: packet-queue.h:49
action-globals.h
Packet_::action
uint8_t action
Definition: decode.h:578
threads.h
Tmqh_::OutHandler
void(* OutHandler)(ThreadVars *, Packet *)
Definition: tm-queuehandlers.h:40
Packet_::pool
struct PktPool_ * pool
Definition: decode.h:639
PacketReleaseRefs
void PacketReleaseRefs(Packet *p)
Definition: packet.c:70
SCCondInit
#define SCCondInit
Definition: threads-debug.h:138
TmThreadCountThreadsByTmmFlags
uint32_t TmThreadCountThreadsByTmmFlags(uint8_t flags)
returns a count of all the threads that match the flag
Definition: tm-threads.c:2010
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
tm-modules.h
SCSpinLock
#define SCSpinLock
Definition: threads-debug.h:235
PktPool_::pending_count
uint32_t pending_count
Definition: tmqh-packetpool.h:58
PacketPoolPostRunmodes
void PacketPoolPostRunmodes(void)
Set the max_pending_return_packets value.
Definition: tmqh-packetpool.c:459
MAX_PENDING_RETURN_PACKETS
#define MAX_PENDING_RETURN_PACKETS
Definition: tmqh-packetpool.c:41
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:314
tmqh-packetpool.h
thread_pkt_pool
thread_local PktPool thread_pkt_pool
Definition: tmqh-packetpool.c:44
PktPool_::pending_head
Packet * pending_head
Definition: tmqh-packetpool.h:56
TmqhReleasePacketsToPacketPool
void TmqhReleasePacketsToPacketPool(PacketQueue *pq)
Release all the packets in the queue back to the packetpool. Mainly used by threads that have failed,...
Definition: tmqh-packetpool.c:427
PacketPoolInit
void PacketPoolInit(void)
Definition: tmqh-packetpool.c:244
Tmqh_::InHandler
Packet *(* InHandler)(ThreadVars *)
Definition: tm-queuehandlers.h:38
lock
HRLOCK_TYPE lock
Definition: host.h:0
decode.h
TUNNEL_PKT_TPR
#define TUNNEL_PKT_TPR(p)
Definition: decode.h:1055
PacketReinit
void PacketReinit(Packet *p)
Recycle a packet structure for reuse.
Definition: packet.c:80
SCCondWait
#define SCCondWait
Definition: threads-debug.h:141
Packet_::tunnel_lock
SCSpinlock tunnel_lock
Definition: decode.h:652
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:527
CaptureStatsUpdate
void CaptureStatsUpdate(ThreadVars *tv, const Packet *p)
Definition: decode.c:968
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:193
SCSpinUnlock
#define SCSpinUnlock
Definition: threads-debug.h:237
TmqhInputPacketpool
Packet * TmqhInputPacketpool(ThreadVars *tv)
Definition: tmqh-packetpool.c:309
SIZE_OF_PACKET
#define SIZE_OF_PACKET
Definition: decode.h:672
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
util-profiling.h
PacketPoolWait
void PacketPoolWait(void)
Definition: tmqh-packetpool.c:80
SCReturn
#define SCReturn
Definition: util-debug.h:273
Packet_
Definition: decode.h:476
Tmqh_::name
const char * name
Definition: tm-queuehandlers.h:37
max_pending_packets
uint32_t max_pending_packets
Definition: suricata.c:180
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
PktPool_::return_stack
PktPoolLockedStack return_stack
Definition: tmqh-packetpool.h:72
tm-queuehandlers.h
TmqhPacketpoolRegister
void TmqhPacketpoolRegister(void)
TmqhPacketpoolRegister \initonly.
Definition: tmqh-packetpool.c:55
Packet_::ReleasePacket
void(* ReleasePacket)(struct Packet_ *)
Definition: decode.h:560
SCCondSignal
#define SCCondSignal
Definition: threads-debug.h:139
Packet_::flow
struct Flow_ * flow
Definition: decode.h:515
suricata-common.h
packet.h
TMQH_PACKETPOOL
@ TMQH_PACKETPOOL
Definition: tm-queuehandlers.h:30
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
FatalError
#define FatalError(...)
Definition: util-debug.h:502
tmqh_table
Tmqh tmqh_table[TMQH_SIZE]
Definition: tm-queuehandlers.c:37
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
PacketDequeue
Packet * PacketDequeue(PacketQueue *q)
Definition: packet-queue.c:216
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:232
TUNNEL_PKT_RTV
#define TUNNEL_PKT_RTV(p)
Definition: decode.h:1054
Packet_::next
struct Packet_ * next
Definition: decode.h:604
Packet_::root
struct Packet_ * root
Definition: decode.h:622
TUNNEL_INCR_PKT_RTV_NOLOCK
#define TUNNEL_INCR_PKT_RTV_NOLOCK(p)
Definition: decode.h:1042
PACKET_PROFILING_END
#define PACKET_PROFILING_END(p)
Definition: util-profiling.h:86
PacketPoolGetPacket
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
Definition: tmqh-packetpool.c:127
SCSpinlock
#define SCSpinlock
Definition: threads-debug.h:234
cc_barrier
#define cc_barrier()
Definition: util-optimize.h:43
PktPool_::pending_pool
struct PktPool_ * pending_pool
Definition: tmqh-packetpool.h:55
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
PacketPoolDestroy
void PacketPoolDestroy(void)
Definition: tmqh-packetpool.c:274
PktPool_::head
Packet * head
Definition: tmqh-packetpool.h:47
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102