All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] [NETFILTER] nf_conntrack: more efficient helper lookup
@ 2006-02-12 18:16 Harald Welte
  2006-02-12 21:25 ` Pablo Neira Ayuso
  0 siblings, 1 reply; 4+ messages in thread
From: Harald Welte @ 2006-02-12 18:16 UTC (permalink / raw)
  To: Netfilter Development Mailinglist; +Cc: Patrick McHardy

[-- Attachment #1: Type: text/plain, Size: 8945 bytes --]

Hi!

As Patrick and I discussed about two weeks ago, the linear iteration
over the list of helpers with a full tuple compare per helper is
overkill.

Please review this suggested patch and comment, thanks.

Cheers,
	Harald


[NETFILTER] nf_conntrack: more efficient helper lookup

Instead of iterating over a linear list of helpers, we now keep a hash
table of them.  Also, we restrict helper match lookup to (l3proto, l4proto,
dstport) instead of a full-blown tuple/mask lookup.

Signed-off-by: Harald Welte <laforge@netfilter.org>

---
commit 06d95115655ba6df96d8ad7c92a3d5e91eee39f7
tree 21a21e59e9ce5eccdbafb6026106c49691674dba
parent 904a871a628c42031c3093c2b90bde526f0f35f0
author Harald Welte <laforge@netfilter.org> Wed, 01 Feb 2006 21:29:32 +0100
committer Harald Welte <laforge@netfilter.org> Wed, 01 Feb 2006 21:29:32 +0100

 include/net/netfilter/nf_conntrack_helper.h |   10 ++--
 net/netfilter/nf_conntrack_core.c           |   72 +++++++++++++++++++++++----
 net/netfilter/nf_conntrack_ftp.c            |   12 ++---
 3 files changed, 70 insertions(+), 24 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 86ec817..3cca3c8 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -15,7 +15,7 @@ struct module;
 
 struct nf_conntrack_helper
 {	
-	struct list_head list; 		/* Internal use. */
+	struct hlist_node list;		/* Internal use. */
 
 	const char *name;		/* name of the module */
 	struct module *me;		/* pointer to self */
@@ -23,10 +23,10 @@ struct nf_conntrack_helper
 					 * expected connections */
 	unsigned int timeout;		/* timeout for expecteds */
 
-	/* Mask of things we will help (compared against server response) */
-	struct nf_conntrack_tuple tuple;
-	struct nf_conntrack_tuple mask;
-	
+	union nf_conntrack_man_proto l4;
+	u_int8_t l4proto;
+	u_int8_t l3proto;
+
 	/* Function to call when data passes; return verdict, or -1 to
            invalidate. */
 	int (*help)(struct sk_buff **pskb,
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f136e0d..451e8b3 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -23,6 +23,8 @@
  * 26 Jan 2006: Harald Welte <laforge@netfilter.org>
  * 	- restructure nf_conn (introduce nf_conn_help)
  * 	- redesign 'features' how they were originally intended
+ * 02 Feb 2006: Harald Welte <laforge@netfilter.org>
+ * 	- replace tuple/mask helper lookup by more efficient method
  *
  * Derived from net/ipv4/netfilter/ip_conntrack_core.c
  */
@@ -58,7 +60,7 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
-#define NF_CONNTRACK_VERSION	"0.5.0"
+#define NF_CONNTRACK_VERSION	"0.5.1"
 
 #if 0
 #define DEBUGP printk
@@ -75,7 +77,6 @@ void (*nf_conntrack_destroyed)(struct nf
 LIST_HEAD(nf_conntrack_expect_list);
 struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
 struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX];
-static LIST_HEAD(helpers);
 unsigned int nf_conntrack_htable_size = 0;
 int nf_conntrack_max;
 struct list_head *nf_conntrack_hash;
@@ -85,6 +86,11 @@ unsigned int nf_ct_log_invalid;
 static LIST_HEAD(unconfirmed);
 static int nf_conntrack_vmalloc;
 
+/* normally the number of helpers is small, so we try to save some cache */
+#define NFCT_HELPER_BUCKETS 	8
+#define NFCT_HELPER_INITVAL	0x23424223
+static struct hlist_head *helpers;
+
 static unsigned int nf_conntrack_next_id = 1;
 static unsigned int nf_conntrack_expect_next_id = 1;
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
@@ -787,18 +793,31 @@ static int early_drop(struct list_head *
 	return dropped;
 }
 
+static unsigned int helper_hashfn(const struct nf_conntrack_tuple *tuple)
+{
+	return jhash_2words(tuple->dst.protonum, tuple->src.u.all, 
+			    NFCT_HELPER_INITVAL) % NFCT_HELPER_BUCKETS;
+}
+
 static inline int helper_cmp(const struct nf_conntrack_helper *i,
 			     const struct nf_conntrack_tuple *rtuple)
 {
-	return nf_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
+	return ((i->l4proto == rtuple->dst.protonum)
+		&& (i->l3proto == rtuple->src.l3num)
+		&& (i->l4.all == rtuple->src.u.all));
 }
 
 static struct nf_conntrack_helper *
 __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
 {
-	return LIST_FIND(&helpers, helper_cmp,
-			 struct nf_conntrack_helper *,
-			 tuple);
+	struct nf_conntrack_helper *h;
+	struct hlist_node *pos;
+
+	hlist_for_each_entry(h, pos, &helpers[helper_hashfn(tuple)], list)
+		if (helper_cmp(h, tuple))
+			return h;
+
+	return NULL;
 }
 
 struct nf_conntrack_helper *
@@ -1283,9 +1302,20 @@ out:
 	return ret;
 }
 
+static void helper2tuple(struct nf_conntrack_tuple *fake_tuple,
+			 const struct nf_conntrack_helper *me)
+{
+	memset(fake_tuple, 0, sizeof(*fake_tuple));
+	fake_tuple->src.l3num = me->l3proto;
+	fake_tuple->dst.protonum = me->l4proto;
+	fake_tuple->dst.u.all = me->l4.all;
+}
+
 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 {
 	int ret;
+	struct nf_conntrack_tuple fake_tuple;
+
 	BUG_ON(me->timeout == 0);
 
 	ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
@@ -1296,8 +1326,11 @@ int nf_conntrack_helper_register(struct 
 		printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n");
 		return ret;
 	}
+
+	helper2tuple(&fake_tuple, me);
+
 	write_lock_bh(&nf_conntrack_lock);
-	list_prepend(&helpers, me);
+	hlist_add_head(&me->list, &helpers[helper_hashfn(&fake_tuple)]);
 	write_unlock_bh(&nf_conntrack_lock);
 
 	return 0;
@@ -1306,11 +1339,16 @@ int nf_conntrack_helper_register(struct 
 struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name)
 {
-	struct nf_conntrack_helper *h;
+	unsigned int i;
 
-	list_for_each_entry(h, &helpers, list) {
-		if (!strcmp(h->name, name))
-			return h;
+	for (i = 0; i < NFCT_HELPER_BUCKETS; i++) {
+		struct nf_conntrack_helper *h;
+		struct hlist_node *pos;
+
+		hlist_for_each_entry(h, pos, &helpers[i], list) {
+			if (!strcmp(h->name, name))
+				return h;
+		}
 	}
 
 	return NULL;
@@ -1333,10 +1371,13 @@ void nf_conntrack_helper_unregister(stru
 {
 	unsigned int i;
 	struct nf_conntrack_expect *exp, *tmp;
+	struct nf_conntrack_tuple fake_tuple;
+
+	helper2tuple(&fake_tuple, me);
 
 	/* Need write lock here, to delete helper. */
 	write_lock_bh(&nf_conntrack_lock);
-	LIST_DELETE(&helpers, me);
+	hlist_del(&me->list);
 
 	/* Get rid of expectations */
 	list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
@@ -1694,6 +1735,11 @@ int __init nf_conntrack_init(void)
 		goto err_free_conntrack_slab;
 	}
 
+	helpers = kmalloc(sizeof(struct hlist_head) * NFCT_HELPER_BUCKETS,
+			  GFP_KERNEL);
+	if (!helpers)
+		goto err_free_expect_slab;
+
 	/* Don't NEED lock here, but good form anyway. */
 	write_lock_bh(&nf_conntrack_lock);
         for (i = 0; i < PF_MAX; i++)
@@ -1708,6 +1754,8 @@ int __init nf_conntrack_init(void)
 
 	return ret;
 
+err_free_expect_slab:
+	kmem_cache_destroy(nf_conntrack_expect_cachep);
 err_free_conntrack_slab:
 	nf_conntrack_unregister_cache(NF_CT_F_BASIC);
 err_free_hash:
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 280c5c2..daff4d3 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -659,13 +659,11 @@ static int __init init(void)
 	for (i = 0; i < ports_c; i++) {
 		memset(&ftp[i], 0, sizeof(struct nf_conntrack_helper));
 
-		ftp[i][0].tuple.src.l3num = PF_INET;
-		ftp[i][1].tuple.src.l3num = PF_INET6;
+		ftp[i][0].l3proto = PF_INET;
+		ftp[i][1].l3proto = PF_INET6;
 		for (j = 0; j < 2; j++) {
-			ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
-			ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
-			ftp[i][j].mask.src.u.tcp.port = 0xFFFF;
-			ftp[i][j].mask.dst.protonum = 0xFF;
+			ftp[i][j].l4.tcp.port = htons(ports[i]);
+			ftp[i][j].l4proto = IPPROTO_TCP;
 			ftp[i][j].max_expected = 1;
 			ftp[i][j].timeout = 5 * 60;	/* 5 Minutes */
 			ftp[i][j].me = THIS_MODULE;
@@ -684,7 +682,7 @@ static int __init init(void)
 			if (ret) {
 				printk("nf_ct_ftp: failed to register helper "
 				       " for pf: %d port: %d\n",
-					ftp[i][j].tuple.src.l3num, ports[i]);
+					ftp[i][j].l3proto, ports[i]);
 				fini();
 				return ret;
 			}
-- 
- Harald Welte <laforge@netfilter.org>                 http://netfilter.org/
============================================================================
  "Fragmentation is like classful addressing -- an interesting early
   architectural error that shows how much experimentation was going
   on while IP was being designed."                    -- Paul Vixie

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-02-13 11:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-12 18:16 [RFC] [NETFILTER] nf_conntrack: more efficient helper lookup Harald Welte
2006-02-12 21:25 ` Pablo Neira Ayuso
2006-02-13  9:59   ` Balazs Scheidler
2006-02-13 11:33   ` Harald Welte

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.