condition: greatly improve processing speed

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.
This commit is contained in:
Jan Engelhardt
2008-04-02 10:19:52 +02:00
parent 32f06cbedf
commit e304252f4b
3 changed files with 27 additions and 37 deletions

View File

@@ -1,5 +1,6 @@
/* Shared library add-on to iptables for condition match */ /* Shared library add-on to iptables for condition match */
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -88,7 +89,7 @@ static struct xtables_match condition_mt6_reg = {
.family = PF_INET6, .family = PF_INET6,
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), .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, .help = condition_help,
.parse = condition_parse, .parse = condition_parse,
.final_check = condition_check, .final_check = condition_check,

View File

@@ -104,19 +104,14 @@ condition_mt(const struct sk_buff *skb, const struct net_device *in,
bool *hotdrop) bool *hotdrop)
{ {
const struct xt_condition_mtinfo *info = matchinfo; const struct xt_condition_mtinfo *info = matchinfo;
struct condition_variable *var; const struct condition_variable *var = info->condvar;
int condition_status = 0; bool x;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(var, &conditions_list, list) { x = rcu_dereference(var->enabled);
if (strcmp(info->name, var->status_proc->name) == 0) {
condition_status = var->enabled;
break;
}
}
rcu_read_unlock(); rcu_read_unlock();
return condition_status ^ info->invert; return x ^ info->invert;
} }
static bool static bool
@@ -124,8 +119,7 @@ condition_mt_check(const char *tablename, const void *entry,
const struct xt_match *match, void *matchinfo, const struct xt_match *match, void *matchinfo,
unsigned int hook_mask) unsigned int hook_mask)
{ {
const struct xt_condition_mtinfo *info = matchinfo; struct xt_condition_mtinfo *info = matchinfo;
struct list_head *pos;
struct condition_variable *var; struct condition_variable *var;
/* Forbid certain names */ /* Forbid certain names */
@@ -144,11 +138,11 @@ condition_mt_check(const char *tablename, const void *entry,
if (down_interruptible(&proc_lock)) if (down_interruptible(&proc_lock))
return false; return false;
list_for_each(pos, &conditions_list) { list_for_each_entry(var, &conditions_list, list) {
var = list_entry(pos, struct condition_variable, list);
if (strcmp(info->name, var->status_proc->name) == 0) { if (strcmp(info->name, var->status_proc->name) == 0) {
var->refcount++; var->refcount++;
up(&proc_lock); up(&proc_lock);
info->condvar = var;
return true; return true;
} }
} }
@@ -185,38 +179,30 @@ condition_mt_check(const char *tablename, const void *entry,
up(&proc_lock); up(&proc_lock);
info->condvar = var;
return true; return true;
} }
static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) static void condition_mt_destroy(const struct xt_match *match, void *matchinfo)
{ {
const struct xt_condition_mtinfo *info = matchinfo; const struct xt_condition_mtinfo *info = matchinfo;
struct list_head *pos; struct condition_variable *var = info->condvar;
struct condition_variable *var;
down(&proc_lock); down(&proc_lock);
if (--var->refcount == 0) {
list_for_each(pos, &conditions_list) { list_del_rcu(&var->list);
var = list_entry(pos, struct condition_variable, list); remove_proc_entry(var->status_proc->name, proc_net_condition);
if (strcmp(info->name, var->status_proc->name) == 0) { up(&proc_lock);
if (--var->refcount == 0) { /*
list_del_rcu(pos); * synchronize_rcu() would be good enough, but
remove_proc_entry(var->status_proc->name, proc_net_condition); * synchronize_net() guarantees that no packet
up(&proc_lock); * will go out with the old rule after
/* * succesful removal.
* synchronize_rcu() would be good enough, but */
* synchronize_net() guarantees that no packet synchronize_net();
* will go out with the old rule after kfree(var);
* succesful removal. return;
*/
synchronize_net();
kfree(var);
return;
}
break;
}
} }
up(&proc_lock); up(&proc_lock);
} }

View File

@@ -8,6 +8,9 @@ enum {
struct xt_condition_mtinfo { struct xt_condition_mtinfo {
char name[CONDITION_NAME_LEN]; char name[CONDITION_NAME_LEN];
__u8 invert; __u8 invert;
/* Used internally by the kernel */
void *condvar __attribute__((aligned(8)));
}; };
#endif /* _XT_CONDITION_H */ #endif /* _XT_CONDITION_H */