Background
I occasionally have firewall rules that I need to use for maintenance windows, but don't want active (and therefore consuming CPU cycles or slowing the network interface) the rest of the time. I add the rules when I need them, and then want to wipe the slate clean and stop iptables from counting packets and bytes flowing through the filter chains.
Problem: Filter Table Keeps Counting Anyway
The first time I check iptables in verbose mode, packet and byte counts are
always zero. For example:
$ sudo iptables -L -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
However, once the filter table has been initialized, flushing the table or resetting the counters doesn't stop the table from continuing to count packets and bytes. For example:
$ sudo iptables -F; sleep 5; sudo iptables -L -n -v
Chain INPUT (policy ACCEPT 395 packets, 577K bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 199 packets, 11135 bytes)
pkts bytes target prot opt in out source destination
Current Solution
While I suspect that the actual CPU usage isn't all that high for an empty table, it seems wasteful to have the kernel inspect packets or count bytes that I don't care about. In order to prevent the filter table from consuming CPU cycles when there are no active rules, I've been doing the following:
$ sudo iptables -F; sudo iptables -X; sudo modprobe -r iptable_filter
This removes the rules and the filter table, allowing the iptables filter module to be removed from the running kernel. Once I do that, then counters remain zeroed until I once again initialize the table.
The Actual Question
My two-part question is:
- Whether the counters for empty chains even have a measurable impact on performance. Intuitively, it seems like they would on a busy network interface, but I have no idea how to measure whether the impact exists.
- Assuming there is an impact, whether there's a more elegant way to stop iptables from counting bytes/packets on empty chains than unloading the related kernel modules.
Best Answer
You can't unless you patch the kernel. And you have better things to do.
The counters are incremented
__nf_ct_refresh_acct
if the parameterdo_acct
is nonzero. This function is called through two wrappers:nf_ct_refresh_acct
, which increments the counters, andnf_ct_refresh
, which doesn't. The choice of wrapper is made according to the protocol type: protocols that can track do, the ones that can't don't.The amount of computation is tiny. It's just two synchronized additions. Modern processors have very deep instruction pipelines, which makes conditional instructions expensive: the processor tries to predict which branch will be taken to start executing the next few instructions before it's determined the result of the test, and if the prediction is wrong, a lot of work needs to be discarded. The additions do require synchronization between the CPUs, because all CPUs have to be updating the same counter; on typical multicore architecture, this means that the core has to lock the cache line containing the counters. If the feature was optional, the CPU would have to read the configuration value, which doesn't require exclusive access so is a little less expensive. Still it would be an extremely tiny gain, to be balanced by the slightly less tiny loss for the majority of users who want the counters. It's just not worth having an option to disable this feature.