mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-08 13:44:56 +02:00
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:
@@ -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,
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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 */
|
||||||
|
Reference in New Issue
Block a user