]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
condition: greatly improve processing speed
authorJan Engelhardt <jengelh@computergmbh.de>
Wed, 2 Apr 2008 08:19:52 +0000 (10:19 +0200)
committerJan Engelhardt <jengelh@computergmbh.de>
Tue, 8 Apr 2008 09:58:35 +0000 (11:58 +0200)
Replace the loop over all possible condvars by a simple deref. This
changes the runtime from O(n) to O(1) at the expense of only 8 bytes
for rule.

extensions/libxt_condition.c
extensions/xt_condition.c
extensions/xt_condition.h

index 1719c585b83131ba1e9614fd25f131571856d187..71ad6dc319157e1f40e2e8e1ad367ff761326a25 100644 (file)
@@ -1,5 +1,6 @@
 /* Shared library add-on to iptables for condition match */
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -88,7 +89,7 @@ static struct xtables_match condition_mt6_reg = {
        .family         = PF_INET6,
        .version        = XTABLES_VERSION,
        .size           = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
-       .userspacesize  = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
+       .userspacesize  = offsetof(struct xt_condition_mtinfo, condvar),
        .help           = condition_help,
        .parse          = condition_parse,
        .final_check    = condition_check,
index 536ed51eac910fffac70cdae322e9f7647cf6850..5bfe24230c00155f9ed23034f5c0bed05d3acd2e 100644 (file)
@@ -104,19 +104,14 @@ condition_mt(const struct sk_buff *skb, const struct net_device *in,
              bool *hotdrop)
 {
        const struct xt_condition_mtinfo *info = matchinfo;
-       struct condition_variable *var;
-       int condition_status = 0;
+       const struct condition_variable *var   = info->condvar;
+       bool x;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(var, &conditions_list, list) {
-               if (strcmp(info->name, var->status_proc->name) == 0) {
-                       condition_status = var->enabled;
-                       break;
-               }
-       }
+       x = rcu_dereference(var->enabled);
        rcu_read_unlock();
 
-       return condition_status ^ info->invert;
+       return x ^ info->invert;
 }
 
 static bool
@@ -124,8 +119,7 @@ condition_mt_check(const char *tablename, const void *entry,
                    const struct xt_match *match, void *matchinfo,
                    unsigned int hook_mask)
 {
-       const struct xt_condition_mtinfo *info = matchinfo;
-       struct list_head *pos;
+       struct xt_condition_mtinfo *info = matchinfo;
        struct condition_variable *var;
 
        /* Forbid certain names */
@@ -144,11 +138,11 @@ condition_mt_check(const char *tablename, const void *entry,
        if (down_interruptible(&proc_lock))
                return false;
 
-       list_for_each(pos, &conditions_list) {
-               var = list_entry(pos, struct condition_variable, list);
+       list_for_each_entry(var, &conditions_list, list) {
                if (strcmp(info->name, var->status_proc->name) == 0) {
                        var->refcount++;
                        up(&proc_lock);
+                       info->condvar = var;
                        return true;
                }
        }
@@ -185,38 +179,30 @@ condition_mt_check(const char *tablename, const void *entry,
 
        up(&proc_lock);
 
+       info->condvar = var;
        return true;
 }
 
 static void condition_mt_destroy(const struct xt_match *match, void *matchinfo)
 {
        const struct xt_condition_mtinfo *info = matchinfo;
-       struct list_head *pos;
-       struct condition_variable *var;
+       struct condition_variable *var = info->condvar;
 
        down(&proc_lock);
-
-       list_for_each(pos, &conditions_list) {
-               var = list_entry(pos, struct condition_variable, list);
-               if (strcmp(info->name, var->status_proc->name) == 0) {
-                       if (--var->refcount == 0) {
-                               list_del_rcu(pos);
-                               remove_proc_entry(var->status_proc->name, proc_net_condition);
-                               up(&proc_lock);
-                               /*
-                                * synchronize_rcu() would be good enough, but
-                                * synchronize_net() guarantees that no packet
-                                * will go out with the old rule after
-                                * succesful removal.
-                                */
-                               synchronize_net();
-                               kfree(var);
-                               return;
-                       }
-                       break;
-               }
+       if (--var->refcount == 0) {
+               list_del_rcu(&var->list);
+               remove_proc_entry(var->status_proc->name, proc_net_condition);
+               up(&proc_lock);
+               /*
+                * synchronize_rcu() would be good enough, but
+                * synchronize_net() guarantees that no packet
+                * will go out with the old rule after
+                * succesful removal.
+                */
+               synchronize_net();
+               kfree(var);
+               return;
        }
-
        up(&proc_lock);
 }
 
index f8751ea1ee4b67b4dfec6ea37d5c63f774946f09..db37a31c80a720caf377275318fe0e83e51f8590 100644 (file)
@@ -8,6 +8,9 @@ enum {
 struct xt_condition_mtinfo {
        char name[CONDITION_NAME_LEN];
        __u8 invert;
+
+       /* Used internally by the kernel */
+       void *condvar __attribute__((aligned(8)));
 };
 
 #endif /* _XT_CONDITION_H */