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 */
#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,

View 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);
}

View 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 */