aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-12-18 12:35:15 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2011-01-13 06:05:12 -0500
commit255d0dc34068a976550ce555e153c0bfcfec7cc6 (patch)
treee936c3d55eaf144cbc4edf8f9332d8089719d0d4 /net/ipv4
parentb017900aac4a158b9bf7ffdcb8a369a91115b3e4 (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.c2
-rw-r--r--net/ipv4/netfilter/ip_tables.c2
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,