Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: nf_conntrack_helper: use hashtable for conntrack helpers

Eliminate the last global list searched for every new connection.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Patrick McHardy and committed by
David S. Miller
b8a7fe6c f264a7df

+59 -15
+2 -2
include/net/netfilter/nf_conntrack_helper.h
··· 15 15 struct module; 16 16 17 17 struct nf_conntrack_helper 18 - { 19 - struct list_head list; /* Internal use. */ 18 + { 19 + struct hlist_node hnode; /* Internal use. */ 20 20 21 21 const char *name; /* name of the module */ 22 22 struct module *me; /* pointer to self */
+57 -13
net/netfilter/nf_conntrack_helper.c
··· 28 28 #include <net/netfilter/nf_conntrack_core.h> 29 29 #include <net/netfilter/nf_conntrack_extend.h> 30 30 31 - static __read_mostly LIST_HEAD(helpers); 31 + static struct hlist_head *nf_ct_helper_hash __read_mostly; 32 + static unsigned int nf_ct_helper_hsize __read_mostly; 33 + static unsigned int nf_ct_helper_count __read_mostly; 34 + static int nf_ct_helper_vmalloc; 35 + 36 + 37 + /* Stupid hash, but collision free for the default registrations of the 38 + * helpers currently in the kernel. */ 39 + static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple) 40 + { 41 + return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^ 42 + tuple->src.u.all) % nf_ct_helper_hsize; 43 + } 32 44 33 45 struct nf_conntrack_helper * 34 46 __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) 35 47 { 36 - struct nf_conntrack_helper *h; 48 + struct nf_conntrack_helper *helper; 37 49 struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) }; 50 + struct hlist_node *n; 51 + unsigned int h; 38 52 39 - list_for_each_entry(h, &helpers, list) { 40 - if (nf_ct_tuple_src_mask_cmp(tuple, &h->tuple, &mask)) 41 - return h; 53 + if (!nf_ct_helper_count) 54 + return NULL; 55 + 56 + h = helper_hash(tuple); 57 + hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) { 58 + if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) 59 + return helper; 42 60 } 43 61 return NULL; 44 62 } 45 63 46 64 struct nf_conntrack_helper * 47 - nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple) 65 + nf_ct_helper_find_get(const struct nf_conntrack_tuple *tuple) 48 66 { 49 67 struct nf_conntrack_helper *helper; 50 68 ··· 95 77 __nf_conntrack_helper_find_byname(const char *name) 96 78 { 97 79 struct nf_conntrack_helper *h; 80 + struct hlist_node *n; 81 + unsigned int i; 98 82 99 - list_for_each_entry(h, &helpers, list) { 100 - if (!strcmp(h->name, name)) 101 - return h; 83 + for (i = 0; i < nf_ct_helper_hsize; i++) { 84 + hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) { 85 + if (!strcmp(h->name, name)) 86 + return h; 87 + } 102 88 } 103 - 104 89 return NULL; 105 90 } 106 91 EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname); ··· 136 115 137 116 int nf_conntrack_helper_register(struct nf_conntrack_helper *me) 138 117 { 118 + unsigned int h = helper_hash(&me->tuple); 119 + 139 120 BUG_ON(me->timeout == 0); 140 121 141 122 write_lock_bh(&nf_conntrack_lock); 142 - list_add(&me->list, &helpers); 123 + hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]); 124 + nf_ct_helper_count++; 143 125 write_unlock_bh(&nf_conntrack_lock); 144 126 145 127 return 0; ··· 158 134 159 135 /* Need write lock here, to delete helper. */ 160 136 write_lock_bh(&nf_conntrack_lock); 161 - list_del(&me->list); 137 + hlist_del(&me->hnode); 138 + nf_ct_helper_count--; 162 139 163 140 /* Get rid of expectations */ 164 141 for (i = 0; i < nf_ct_expect_hsize; i++) { ··· 196 171 197 172 int nf_conntrack_helper_init() 198 173 { 199 - return nf_ct_extend_register(&helper_extend); 174 + int err; 175 + 176 + nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ 177 + nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 178 + &nf_ct_helper_vmalloc); 179 + if (!nf_ct_helper_hash) 180 + return -ENOMEM; 181 + 182 + err = nf_ct_extend_register(&helper_extend); 183 + if (err < 0) 184 + goto err1; 185 + 186 + return 0; 187 + 188 + err1: 189 + nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc, 190 + nf_ct_helper_hsize); 191 + return err; 200 192 } 201 193 202 194 void nf_conntrack_helper_fini() 203 195 { 204 196 nf_ct_extend_unregister(&helper_extend); 197 + nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc, 198 + nf_ct_helper_hsize); 205 199 }