aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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