Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8a7fe6c authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: nf_conntrack_helper: use hashtable for conntrack helpers



Eliminate the last global list searched for every new connection.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f264a7df
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@ struct module;


struct nf_conntrack_helper
struct nf_conntrack_helper
{
{
	struct list_head list; 		/* Internal use. */
	struct hlist_node hnode;	/* Internal use. */


	const char *name;		/* name of the module */
	const char *name;		/* name of the module */
	struct module *me;		/* pointer to self */
	struct module *me;		/* pointer to self */
+57 −13
Original line number Original line Diff line number Diff line
@@ -28,17 +28,35 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_conntrack_extend.h>


static __read_mostly LIST_HEAD(helpers);
static struct hlist_head *nf_ct_helper_hash __read_mostly;
static unsigned int nf_ct_helper_hsize __read_mostly;
static unsigned int nf_ct_helper_count __read_mostly;
static int nf_ct_helper_vmalloc;


/* Stupid hash, but collision free for the default registrations of the
 * helpers currently in the kernel. */
static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
{
	return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
		tuple->src.u.all) % nf_ct_helper_hsize;
}


struct nf_conntrack_helper *
struct nf_conntrack_helper *
__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
{
{
	struct nf_conntrack_helper *h;
	struct nf_conntrack_helper *helper;
	struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
	struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
	struct hlist_node *n;
	unsigned int h;


	list_for_each_entry(h, &helpers, list) {
	if (!nf_ct_helper_count)
		if (nf_ct_tuple_src_mask_cmp(tuple, &h->tuple, &mask))
		return NULL;
			return h;

	h = helper_hash(tuple);
	hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) {
		if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
			return helper;
	}
	}
	return NULL;
	return NULL;
}
}
@@ -77,12 +95,15 @@ struct nf_conntrack_helper *
__nf_conntrack_helper_find_byname(const char *name)
__nf_conntrack_helper_find_byname(const char *name)
{
{
	struct nf_conntrack_helper *h;
	struct nf_conntrack_helper *h;
	struct hlist_node *n;
	unsigned int i;


	list_for_each_entry(h, &helpers, list) {
	for (i = 0; i < nf_ct_helper_hsize; i++) {
		hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) {
			if (!strcmp(h->name, name))
			if (!strcmp(h->name, name))
				return h;
				return h;
		}
		}

	}
	return NULL;
	return NULL;
}
}
EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname);
EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname);
@@ -115,10 +136,13 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i,


int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
{
{
	unsigned int h = helper_hash(&me->tuple);

	BUG_ON(me->timeout == 0);
	BUG_ON(me->timeout == 0);


	write_lock_bh(&nf_conntrack_lock);
	write_lock_bh(&nf_conntrack_lock);
	list_add(&me->list, &helpers);
	hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]);
	nf_ct_helper_count++;
	write_unlock_bh(&nf_conntrack_lock);
	write_unlock_bh(&nf_conntrack_lock);


	return 0;
	return 0;
@@ -134,7 +158,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)


	/* Need write lock here, to delete helper. */
	/* Need write lock here, to delete helper. */
	write_lock_bh(&nf_conntrack_lock);
	write_lock_bh(&nf_conntrack_lock);
	list_del(&me->list);
	hlist_del(&me->hnode);
	nf_ct_helper_count--;


	/* Get rid of expectations */
	/* Get rid of expectations */
	for (i = 0; i < nf_ct_expect_hsize; i++) {
	for (i = 0; i < nf_ct_expect_hsize; i++) {
@@ -171,10 +196,29 @@ static struct nf_ct_ext_type helper_extend __read_mostly = {


int nf_conntrack_helper_init()
int nf_conntrack_helper_init()
{
{
	return nf_ct_extend_register(&helper_extend);
	int err;

	nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
	nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize,
						  &nf_ct_helper_vmalloc);
	if (!nf_ct_helper_hash)
		return -ENOMEM;

	err = nf_ct_extend_register(&helper_extend);
	if (err < 0)
		goto err1;

	return 0;

err1:
	nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
			     nf_ct_helper_hsize);
	return err;
}
}


void nf_conntrack_helper_fini()
void nf_conntrack_helper_fini()
{
{
	nf_ct_extend_unregister(&helper_extend);
	nf_ct_extend_unregister(&helper_extend);
	nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
			     nf_ct_helper_hsize);
}
}