aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKOVACS Krisztian <hidden@balabit.hu>2005-09-16 19:59:46 -0400
committerDavid S. Miller <davem@davemloft.net>2005-09-16 19:59:46 -0400
commit4451362445b2d83886003f1d739b94e4f000eeeb (patch)
tree2f7d272bcb83011ea7df364f01ad08574701cf86
parent1cbf07478bbf3e350a2025bc5ea23fedaa95855a (diff)
[NETFILTER] CLUSTERIP: introduce reference counting for entries
The CLUSTERIP target creates a procfs entry for all different cluster IPs. Although more than one rules can refer to a single cluster IP (and thus a single config structure), removal of the procfs entry is done unconditionally in destroy(). In more complicated situations involving deferred dereferencing of the config structure by procfs and creating a new rule with the same cluster IP it's also possible that no entry will be created for the new rule. This patch fixes the problem by counting the number of entries referencing a given config structure and moving the config list manipulation and procfs entry deletion parts to the clusterip_config_entry_put() function. Signed-off-by: KOVACS Krisztian <hidden@balabit.hu> Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c80
1 files changed, 62 insertions, 18 deletions
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 7d38913754b1..adbf4d752d0f 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -49,6 +49,8 @@ MODULE_DESCRIPTION("iptables target for CLUSTERIP");
49struct clusterip_config { 49struct clusterip_config {
50 struct list_head list; /* list of all configs */ 50 struct list_head list; /* list of all configs */
51 atomic_t refcount; /* reference count */ 51 atomic_t refcount; /* reference count */
52 atomic_t entries; /* number of entries/rules
53 * referencing us */
52 54
53 u_int32_t clusterip; /* the IP address */ 55 u_int32_t clusterip; /* the IP address */
54 u_int8_t clustermac[ETH_ALEN]; /* the MAC address */ 56 u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
@@ -76,23 +78,48 @@ static struct proc_dir_entry *clusterip_procdir;
76#endif 78#endif
77 79
78static inline void 80static inline void
79clusterip_config_get(struct clusterip_config *c) { 81clusterip_config_get(struct clusterip_config *c)
82{
80 atomic_inc(&c->refcount); 83 atomic_inc(&c->refcount);
81} 84}
82 85
83static inline void 86static inline void
84clusterip_config_put(struct clusterip_config *c) { 87clusterip_config_put(struct clusterip_config *c)
85 if (atomic_dec_and_test(&c->refcount)) { 88{
89 if (atomic_dec_and_test(&c->refcount))
90 kfree(c);
91}
92
93/* increase the count of entries(rules) using/referencing this config */
94static inline void
95clusterip_config_entry_get(struct clusterip_config *c)
96{
97 atomic_inc(&c->entries);
98}
99
100/* decrease the count of entries using/referencing this config. If last
101 * entry(rule) is removed, remove the config from lists, but don't free it
102 * yet, since proc-files could still be holding references */
103static inline void
104clusterip_config_entry_put(struct clusterip_config *c)
105{
106 if (atomic_dec_and_test(&c->entries)) {
86 write_lock_bh(&clusterip_lock); 107 write_lock_bh(&clusterip_lock);
87 list_del(&c->list); 108 list_del(&c->list);
88 write_unlock_bh(&clusterip_lock); 109 write_unlock_bh(&clusterip_lock);
110
89 dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0); 111 dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0);
90 dev_put(c->dev); 112 dev_put(c->dev);
91 kfree(c); 113
114 /* In case anyone still accesses the file, the open/close
115 * functions are also incrementing the refcount on their own,
116 * so it's safe to remove the entry even if it's in use. */
117#ifdef CONFIG_PROC_FS
118 remove_proc_entry(c->pde->name, c->pde->parent);
119#endif
92 } 120 }
93} 121}
94 122
95
96static struct clusterip_config * 123static struct clusterip_config *
97__clusterip_config_find(u_int32_t clusterip) 124__clusterip_config_find(u_int32_t clusterip)
98{ 125{
@@ -111,7 +138,7 @@ __clusterip_config_find(u_int32_t clusterip)
111} 138}
112 139
113static inline struct clusterip_config * 140static inline struct clusterip_config *
114clusterip_config_find_get(u_int32_t clusterip) 141clusterip_config_find_get(u_int32_t clusterip, int entry)
115{ 142{
116 struct clusterip_config *c; 143 struct clusterip_config *c;
117 144
@@ -122,6 +149,8 @@ clusterip_config_find_get(u_int32_t clusterip)
122 return NULL; 149 return NULL;
123 } 150 }
124 atomic_inc(&c->refcount); 151 atomic_inc(&c->refcount);
152 if (entry)
153 atomic_inc(&c->entries);
125 read_unlock_bh(&clusterip_lock); 154 read_unlock_bh(&clusterip_lock);
126 155
127 return c; 156 return c;
@@ -148,6 +177,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip,
148 c->hash_mode = i->hash_mode; 177 c->hash_mode = i->hash_mode;
149 c->hash_initval = i->hash_initval; 178 c->hash_initval = i->hash_initval;
150 atomic_set(&c->refcount, 1); 179 atomic_set(&c->refcount, 1);
180 atomic_set(&c->entries, 1);
151 181
152#ifdef CONFIG_PROC_FS 182#ifdef CONFIG_PROC_FS
153 /* create proc dir entry */ 183 /* create proc dir entry */
@@ -415,8 +445,26 @@ checkentry(const char *tablename,
415 445
416 /* FIXME: further sanity checks */ 446 /* FIXME: further sanity checks */
417 447
418 config = clusterip_config_find_get(e->ip.dst.s_addr); 448 config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
419 if (!config) { 449 if (config) {
450 if (cipinfo->config != NULL) {
451 /* Case A: This is an entry that gets reloaded, since
452 * it still has a cipinfo->config pointer. Simply
453 * increase the entry refcount and return */
454 if (cipinfo->config != config) {
455 printk(KERN_ERR "CLUSTERIP: Reloaded entry "
456 "has invalid config pointer!\n");
457 return 0;
458 }
459 clusterip_config_entry_get(cipinfo->config);
460 } else {
461 /* Case B: This is a new rule referring to an existing
462 * clusterip config. */
463 cipinfo->config = config;
464 clusterip_config_entry_get(cipinfo->config);
465 }
466 } else {
467 /* Case C: This is a completely new clusterip config */
420 if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { 468 if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
421 printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr)); 469 printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr));
422 return 0; 470 return 0;
@@ -443,10 +491,9 @@ checkentry(const char *tablename,
443 } 491 }
444 dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); 492 dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0);
445 } 493 }
494 cipinfo->config = config;
446 } 495 }
447 496
448 cipinfo->config = config;
449
450 return 1; 497 return 1;
451} 498}
452 499
@@ -455,13 +502,10 @@ static void destroy(void *matchinfo, unsigned int matchinfosize)
455{ 502{
456 struct ipt_clusterip_tgt_info *cipinfo = matchinfo; 503 struct ipt_clusterip_tgt_info *cipinfo = matchinfo;
457 504
458 /* we first remove the proc entry and then drop the reference 505 /* if no more entries are referencing the config, remove it
459 * count. In case anyone still accesses the file, the open/close 506 * from the list and destroy the proc entry */
460 * functions are also incrementing the refcount on their own */ 507 clusterip_config_entry_put(cipinfo->config);
461#ifdef CONFIG_PROC_FS 508
462 remove_proc_entry(cipinfo->config->pde->name,
463 cipinfo->config->pde->parent);
464#endif
465 clusterip_config_put(cipinfo->config); 509 clusterip_config_put(cipinfo->config);
466} 510}
467 511
@@ -533,7 +577,7 @@ arp_mangle(unsigned int hook,
533 577
534 /* if there is no clusterip configuration for the arp reply's 578 /* if there is no clusterip configuration for the arp reply's
535 * source ip, we don't want to mangle it */ 579 * source ip, we don't want to mangle it */
536 c = clusterip_config_find_get(payload->src_ip); 580 c = clusterip_config_find_get(payload->src_ip, 0);
537 if (!c) 581 if (!c)
538 return NF_ACCEPT; 582 return NF_ACCEPT;
539 583