When using Snort_inline with NFQ support, it’s likely that at some point you’ve seen messages like these on the console: packet recv contents failure: No buffer space available. When the messages are appearing Snort_inline slows down significantly. I’ve been trying to find out why.
There are a number of setting that influence NFQ performance. One of them is the NFQ queue maximum length. This is a value in packets. Snort_inline takes an argument to modify the buffer length: –queue-maxlen 5000 (note: there are two dashes before queue-maxlen).
That’s not enough though. The following settings increase the buffer that NFQ seems to use for it’s queue. Since I’ve set it this high, I haven’t been able to get a single read error anymore:
sysctl -w net.core.rmem_default=’8388608′
sysctl -w net.core.wmem_default=’8388608′
The values are in bytes. The following values increase buffers for tcp traffic.
sysctl -w net.ipv4.tcp_wmem=’1048576 4194304 16777216′
sysctl -w net.ipv4.tcp_rmem=’1048576 4194304 16777216′
For more details see this page: http://www-didc.lbl.gov/TCP-tuning/linux.html
Setting these values fixed all my NFQ related slowdowns. The values probably work for ip_queue as well. If you use other values, please put them in a comment below.
Thanks to Dave Remien for helping me track this down!
The line
sysctl -w net.core.rmem_default=’8388608′
tells the kernel to allow up to 8388608 bytes worth of (received) packets to be queued for every open socket in the system. It’s dynamically allocated from free memory (Low Memory on 32 bit kernels). You *don’t* want to run out of Low Memory on a 32 bit kernel… (cat /proc/meminfo). Bad things happen – the OOM killer goes on a rampage, and random process get killed (unless protected against OOM killing (echo “-17” > /proc/pid/oom_adj)).
So the buffer sizes allocated have to be weighed against the possibility that under duress, the kernel will have too much memory used up in outstanding receive buffers, and start freeing things up in an unpleasant manner. Tuning the kernel for these condtions is an art, not a science…
D’oh! Forgot to mention the other side of the max packets on a queue versus memory conundrum…. The number of packets allowed to be outstanding on a netfilter_queue. Which is 1024. So…. Which ever you run into first (max packets outstanding) or out of memory to put ’em in is what bites…
To change the number of outstanding packets on an NFQUEUE isn’t as easy as a sysctl -w, though – you need to modify nfnetfilter_queue.c and recompile it to change the value:
#define NFQNL_QMAX_DEFAULT 1024
Here’s one way to look at it – each outstanding packet takes up one of the above QMAX spots, and some amount of memory. If your acerage traffic is 600 bytes in size, you can use up something like 650K (I think there’s a little overhead per packet) of memory. For full size TCP streams and acks the average packet size is more like 1100, so you’re looking at more like 1.2MB of buffer. If you’re using jumbo packets, order more RAM now 8-).
What you’re trying to buy by adjusting the QMAX and rmem_default settings upward is breathing space for snort, when that new PCRE rule you wrote this afternoon takes waaaaaaayyyyyy longer to match than you thought it would, or you just get slammed with a DOS attack….
Thanks for your explanations Dave. I think the number of outstanding packets nfqueue can deal with can also be changed with the –queue-maxlen option. It uses the nfq_set_queue_maxlen() call for that…
You’re right – I’d forgotten that you can do it that way. Actually, I expose the queue_max in /sys, so I just change it once and forget it 8-).
Just to make sure that OOM killing will not nuke something undesirable, you should adjust OOM to kill snort_inline first: echo “15″ > /proc/(snort_inline_pid)/oom_adj
Better safe than sorry and snort_inline can always be restarted by watchdog.