diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-12-18 12:35:15 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2011-01-13 06:05:12 -0500 |
commit | 255d0dc34068a976550ce555e153c0bfcfec7cc6 (patch) | |
tree | e936c3d55eaf144cbc4edf8f9332d8089719d0d4 /net/ipv4 | |
parent | b017900aac4a158b9bf7ffdcb8a369a91115b3e4 (diff) |
netfilter: x_table: speedup compat operations
One iptables invocation with 135000 rules takes 35 seconds of cpu time
on a recent server, using a 32bit distro and a 64bit kernel.
We eventually trigger NMI/RCU watchdog.
INFO: rcu_sched_state detected stall on CPU 3 (t=6000 jiffies)
COMPAT mode has quadratic behavior and consume 16 bytes of memory per
rule.
Switch the xt_compat algos to use an array instead of list, and use a
binary search to locate an offset in the sorted array.
This halves memory need (8 bytes per rule), and removes quadratic
behavior [ O(N*N) -> O(N*log2(N)) ]
Time of iptables goes from 35 s to 150 ms.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 2 |
2 files changed, 4 insertions, 0 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 3fac340a28d5..47e5178b998b 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -883,6 +883,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
883 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 883 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
884 | newinfo->initial_entries = 0; | 884 | newinfo->initial_entries = 0; |
885 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 885 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
886 | xt_compat_init_offsets(NFPROTO_ARP, info->number); | ||
886 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { | 887 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
887 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); | 888 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
888 | if (ret != 0) | 889 | if (ret != 0) |
@@ -1350,6 +1351,7 @@ static int translate_compat_table(const char *name, | |||
1350 | duprintf("translate_compat_table: size %u\n", info->size); | 1351 | duprintf("translate_compat_table: size %u\n", info->size); |
1351 | j = 0; | 1352 | j = 0; |
1352 | xt_compat_lock(NFPROTO_ARP); | 1353 | xt_compat_lock(NFPROTO_ARP); |
1354 | xt_compat_init_offsets(NFPROTO_ARP, number); | ||
1353 | /* Walk through entries, checking offsets. */ | 1355 | /* Walk through entries, checking offsets. */ |
1354 | xt_entry_foreach(iter0, entry0, total_size) { | 1356 | xt_entry_foreach(iter0, entry0, total_size) { |
1355 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, | 1357 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a846d633b3b6..c5a75d70970f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -1080,6 +1080,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1080 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1080 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
1081 | newinfo->initial_entries = 0; | 1081 | newinfo->initial_entries = 0; |
1082 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1082 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
1083 | xt_compat_init_offsets(AF_INET, info->number); | ||
1083 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { | 1084 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1084 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); | 1085 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1085 | if (ret != 0) | 1086 | if (ret != 0) |
@@ -1681,6 +1682,7 @@ translate_compat_table(struct net *net, | |||
1681 | duprintf("translate_compat_table: size %u\n", info->size); | 1682 | duprintf("translate_compat_table: size %u\n", info->size); |
1682 | j = 0; | 1683 | j = 0; |
1683 | xt_compat_lock(AF_INET); | 1684 | xt_compat_lock(AF_INET); |
1685 | xt_compat_init_offsets(AF_INET, number); | ||
1684 | /* Walk through entries, checking offsets. */ | 1686 | /* Walk through entries, checking offsets. */ |
1685 | xt_entry_foreach(iter0, entry0, total_size) { | 1687 | xt_entry_foreach(iter0, entry0, total_size) { |
1686 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, | 1688 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |