aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2010-01-18 02:33:28 -0500
committerPatrick McHardy <kaber@trash.net>2010-01-18 02:33:28 -0500
commite89fc3f1b06d9241f65e580b002789abaa6d11ac (patch)
tree565133f45c0d50ee0f631c134f08309256426831
parent7d07d5632b672c892a65882c2a119345fd9596c9 (diff)
netfilter: xt_hashlimit: netns support
Make hashtable per-netns. Make proc files per-netns. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--net/netfilter/xt_hashlimit.c141
1 files changed, 98 insertions, 43 deletions
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 944fd11c8989..fb7fcb773a3f 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include <net/net_namespace.h> 28#include <net/net_namespace.h>
29#include <net/netns/generic.h>
29 30
30#include <linux/netfilter/x_tables.h> 31#include <linux/netfilter/x_tables.h>
31#include <linux/netfilter_ipv4/ip_tables.h> 32#include <linux/netfilter_ipv4/ip_tables.h>
@@ -40,9 +41,19 @@ MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match");
40MODULE_ALIAS("ipt_hashlimit"); 41MODULE_ALIAS("ipt_hashlimit");
41MODULE_ALIAS("ip6t_hashlimit"); 42MODULE_ALIAS("ip6t_hashlimit");
42 43
44struct hashlimit_net {
45 struct hlist_head htables;
46 struct proc_dir_entry *ipt_hashlimit;
47 struct proc_dir_entry *ip6t_hashlimit;
48};
49
50static int hashlimit_net_id;
51static inline struct hashlimit_net *hashlimit_pernet(struct net *net)
52{
53 return net_generic(net, hashlimit_net_id);
54}
55
43/* need to declare this at the top */ 56/* need to declare this at the top */
44static struct proc_dir_entry *hashlimit_procdir4;
45static struct proc_dir_entry *hashlimit_procdir6;
46static const struct file_operations dl_file_ops; 57static const struct file_operations dl_file_ops;
47 58
48/* hash table crap */ 59/* hash table crap */
@@ -93,13 +104,13 @@ struct xt_hashlimit_htable {
93 104
94 /* seq_file stuff */ 105 /* seq_file stuff */
95 struct proc_dir_entry *pde; 106 struct proc_dir_entry *pde;
107 struct net *net;
96 108
97 struct hlist_head hash[0]; /* hashtable itself */ 109 struct hlist_head hash[0]; /* hashtable itself */
98}; 110};
99 111
100static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ 112static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */
101static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ 113static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */
102static HLIST_HEAD(hashlimit_htables);
103static struct kmem_cache *hashlimit_cachep __read_mostly; 114static struct kmem_cache *hashlimit_cachep __read_mostly;
104 115
105static inline bool dst_cmp(const struct dsthash_ent *ent, 116static inline bool dst_cmp(const struct dsthash_ent *ent,
@@ -185,8 +196,9 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
185} 196}
186static void htable_gc(unsigned long htlong); 197static void htable_gc(unsigned long htlong);
187 198
188static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family) 199static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_int8_t family)
189{ 200{
201 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
190 struct xt_hashlimit_htable *hinfo; 202 struct xt_hashlimit_htable *hinfo;
191 unsigned int size; 203 unsigned int size;
192 unsigned int i; 204 unsigned int i;
@@ -239,26 +251,29 @@ static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family)
239 spin_lock_init(&hinfo->lock); 251 spin_lock_init(&hinfo->lock);
240 hinfo->pde = proc_create_data(minfo->name, 0, 252 hinfo->pde = proc_create_data(minfo->name, 0,
241 (family == NFPROTO_IPV4) ? 253 (family == NFPROTO_IPV4) ?
242 hashlimit_procdir4 : hashlimit_procdir6, 254 hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit,
243 &dl_file_ops, hinfo); 255 &dl_file_ops, hinfo);
244 if (!hinfo->pde) { 256 if (!hinfo->pde) {
245 vfree(hinfo); 257 vfree(hinfo);
246 return -1; 258 return -1;
247 } 259 }
260 hinfo->net = net;
248 261
249 setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo); 262 setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo);
250 hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); 263 hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
251 add_timer(&hinfo->timer); 264 add_timer(&hinfo->timer);
252 265
253 spin_lock_bh(&hashlimit_lock); 266 spin_lock_bh(&hashlimit_lock);
254 hlist_add_head(&hinfo->node, &hashlimit_htables); 267 hlist_add_head(&hinfo->node, &hashlimit_net->htables);
255 spin_unlock_bh(&hashlimit_lock); 268 spin_unlock_bh(&hashlimit_lock);
256 269
257 return 0; 270 return 0;
258} 271}
259 272
260static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) 273static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
274 u_int8_t family)
261{ 275{
276 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
262 struct xt_hashlimit_htable *hinfo; 277 struct xt_hashlimit_htable *hinfo;
263 unsigned int size; 278 unsigned int size;
264 unsigned int i; 279 unsigned int i;
@@ -301,19 +316,20 @@ static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family)
301 316
302 hinfo->pde = proc_create_data(minfo->name, 0, 317 hinfo->pde = proc_create_data(minfo->name, 0,
303 (family == NFPROTO_IPV4) ? 318 (family == NFPROTO_IPV4) ?
304 hashlimit_procdir4 : hashlimit_procdir6, 319 hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit,
305 &dl_file_ops, hinfo); 320 &dl_file_ops, hinfo);
306 if (hinfo->pde == NULL) { 321 if (hinfo->pde == NULL) {
307 vfree(hinfo); 322 vfree(hinfo);
308 return -1; 323 return -1;
309 } 324 }
325 hinfo->net = net;
310 326
311 setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo); 327 setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo);
312 hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); 328 hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
313 add_timer(&hinfo->timer); 329 add_timer(&hinfo->timer);
314 330
315 spin_lock_bh(&hashlimit_lock); 331 spin_lock_bh(&hashlimit_lock);
316 hlist_add_head(&hinfo->node, &hashlimit_htables); 332 hlist_add_head(&hinfo->node, &hashlimit_net->htables);
317 spin_unlock_bh(&hashlimit_lock); 333 spin_unlock_bh(&hashlimit_lock);
318 334
319 return 0; 335 return 0;
@@ -364,24 +380,30 @@ static void htable_gc(unsigned long htlong)
364 380
365static void htable_destroy(struct xt_hashlimit_htable *hinfo) 381static void htable_destroy(struct xt_hashlimit_htable *hinfo)
366{ 382{
383 struct hashlimit_net *hashlimit_net = hashlimit_pernet(hinfo->net);
384 struct proc_dir_entry *parent;
385
367 del_timer_sync(&hinfo->timer); 386 del_timer_sync(&hinfo->timer);
368 387
369 /* remove proc entry */ 388 if (hinfo->family == NFPROTO_IPV4)
370 remove_proc_entry(hinfo->pde->name, 389 parent = hashlimit_net->ipt_hashlimit;
371 hinfo->family == NFPROTO_IPV4 ? hashlimit_procdir4 : 390 else
372 hashlimit_procdir6); 391 parent = hashlimit_net->ip6t_hashlimit;
392 remove_proc_entry(hinfo->pde->name, parent);
373 htable_selective_cleanup(hinfo, select_all); 393 htable_selective_cleanup(hinfo, select_all);
374 vfree(hinfo); 394 vfree(hinfo);
375} 395}
376 396
377static struct xt_hashlimit_htable *htable_find_get(const char *name, 397static struct xt_hashlimit_htable *htable_find_get(struct net *net,
398 const char *name,
378 u_int8_t family) 399 u_int8_t family)
379{ 400{
401 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
380 struct xt_hashlimit_htable *hinfo; 402 struct xt_hashlimit_htable *hinfo;
381 struct hlist_node *pos; 403 struct hlist_node *pos;
382 404
383 spin_lock_bh(&hashlimit_lock); 405 spin_lock_bh(&hashlimit_lock);
384 hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { 406 hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node) {
385 if (!strcmp(name, hinfo->pde->name) && 407 if (!strcmp(name, hinfo->pde->name) &&
386 hinfo->family == family) { 408 hinfo->family == family) {
387 atomic_inc(&hinfo->use); 409 atomic_inc(&hinfo->use);
@@ -665,6 +687,7 @@ hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
665 687
666static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) 688static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
667{ 689{
690 struct net *net = par->net;
668 struct xt_hashlimit_info *r = par->matchinfo; 691 struct xt_hashlimit_info *r = par->matchinfo;
669 692
670 /* Check for overflow. */ 693 /* Check for overflow. */
@@ -694,8 +717,8 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
694 * the list of htable's in htable_create(), since then we would 717 * the list of htable's in htable_create(), since then we would
695 * create duplicate proc files. -HW */ 718 * create duplicate proc files. -HW */
696 mutex_lock(&hlimit_mutex); 719 mutex_lock(&hlimit_mutex);
697 r->hinfo = htable_find_get(r->name, par->match->family); 720 r->hinfo = htable_find_get(net, r->name, par->match->family);
698 if (!r->hinfo && htable_create_v0(r, par->match->family) != 0) { 721 if (!r->hinfo && htable_create_v0(net, r, par->match->family) != 0) {
699 mutex_unlock(&hlimit_mutex); 722 mutex_unlock(&hlimit_mutex);
700 return false; 723 return false;
701 } 724 }
@@ -706,6 +729,7 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
706 729
707static bool hashlimit_mt_check(const struct xt_mtchk_param *par) 730static bool hashlimit_mt_check(const struct xt_mtchk_param *par)
708{ 731{
732 struct net *net = par->net;
709 struct xt_hashlimit_mtinfo1 *info = par->matchinfo; 733 struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
710 734
711 /* Check for overflow. */ 735 /* Check for overflow. */
@@ -735,8 +759,8 @@ static bool hashlimit_mt_check(const struct xt_mtchk_param *par)
735 * the list of htable's in htable_create(), since then we would 759 * the list of htable's in htable_create(), since then we would
736 * create duplicate proc files. -HW */ 760 * create duplicate proc files. -HW */
737 mutex_lock(&hlimit_mutex); 761 mutex_lock(&hlimit_mutex);
738 info->hinfo = htable_find_get(info->name, par->match->family); 762 info->hinfo = htable_find_get(net, info->name, par->match->family);
739 if (!info->hinfo && htable_create(info, par->match->family) != 0) { 763 if (!info->hinfo && htable_create(net, info, par->match->family) != 0) {
740 mutex_unlock(&hlimit_mutex); 764 mutex_unlock(&hlimit_mutex);
741 return false; 765 return false;
742 } 766 }
@@ -953,10 +977,61 @@ static const struct file_operations dl_file_ops = {
953 .release = seq_release 977 .release = seq_release
954}; 978};
955 979
980static int __net_init hashlimit_proc_net_init(struct net *net)
981{
982 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
983
984 hashlimit_net->ipt_hashlimit = proc_mkdir("ipt_hashlimit", net->proc_net);
985 if (!hashlimit_net->ipt_hashlimit)
986 return -ENOMEM;
987#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
988 hashlimit_net->ip6t_hashlimit = proc_mkdir("ip6t_hashlimit", net->proc_net);
989 if (!hashlimit_net->ip6t_hashlimit) {
990 proc_net_remove(net, "ipt_hashlimit");
991 return -ENOMEM;
992 }
993#endif
994 return 0;
995}
996
997static void __net_exit hashlimit_proc_net_exit(struct net *net)
998{
999 proc_net_remove(net, "ipt_hashlimit");
1000#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
1001 proc_net_remove(net, "ip6t_hashlimit");
1002#endif
1003}
1004
1005static int __net_init hashlimit_net_init(struct net *net)
1006{
1007 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
1008
1009 INIT_HLIST_HEAD(&hashlimit_net->htables);
1010 return hashlimit_proc_net_init(net);
1011}
1012
1013static void __net_exit hashlimit_net_exit(struct net *net)
1014{
1015 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
1016
1017 BUG_ON(!hlist_empty(&hashlimit_net->htables));
1018 hashlimit_proc_net_exit(net);
1019}
1020
1021static struct pernet_operations hashlimit_net_ops = {
1022 .init = hashlimit_net_init,
1023 .exit = hashlimit_net_exit,
1024 .id = &hashlimit_net_id,
1025 .size = sizeof(struct hashlimit_net),
1026};
1027
956static int __init hashlimit_mt_init(void) 1028static int __init hashlimit_mt_init(void)
957{ 1029{
958 int err; 1030 int err;
959 1031
1032 err = register_pernet_subsys(&hashlimit_net_ops);
1033 if (err < 0)
1034 return err;
960 err = xt_register_matches(hashlimit_mt_reg, 1035 err = xt_register_matches(hashlimit_mt_reg,
961 ARRAY_SIZE(hashlimit_mt_reg)); 1036 ARRAY_SIZE(hashlimit_mt_reg));
962 if (err < 0) 1037 if (err < 0)
@@ -970,41 +1045,21 @@ static int __init hashlimit_mt_init(void)
970 printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); 1045 printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n");
971 goto err2; 1046 goto err2;
972 } 1047 }
973 hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net); 1048 return 0;
974 if (!hashlimit_procdir4) { 1049
975 printk(KERN_ERR "xt_hashlimit: unable to create proc dir "
976 "entry\n");
977 goto err3;
978 }
979 err = 0;
980#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
981 hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net);
982 if (!hashlimit_procdir6) {
983 printk(KERN_ERR "xt_hashlimit: unable to create proc dir "
984 "entry\n");
985 err = -ENOMEM;
986 }
987#endif
988 if (!err)
989 return 0;
990 remove_proc_entry("ipt_hashlimit", init_net.proc_net);
991err3:
992 kmem_cache_destroy(hashlimit_cachep);
993err2: 1050err2:
994 xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); 1051 xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
995err1: 1052err1:
1053 unregister_pernet_subsys(&hashlimit_net_ops);
996 return err; 1054 return err;
997 1055
998} 1056}
999 1057
1000static void __exit hashlimit_mt_exit(void) 1058static void __exit hashlimit_mt_exit(void)
1001{ 1059{
1002 remove_proc_entry("ipt_hashlimit", init_net.proc_net);
1003#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
1004 remove_proc_entry("ip6t_hashlimit", init_net.proc_net);
1005#endif
1006 kmem_cache_destroy(hashlimit_cachep); 1060 kmem_cache_destroy(hashlimit_cachep);
1007 xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); 1061 xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
1062 unregister_pernet_subsys(&hashlimit_net_ops);
1008} 1063}
1009 1064
1010module_init(hashlimit_mt_init); 1065module_init(hashlimit_mt_init);