]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - net/ipv4/netfilter/ipt_CLUSTERIP.c
[NETFILTER]: remove remaining ASSERT_{READ,WRITE}_LOCK
[mirror_ubuntu-zesty-kernel.git] / net / ipv4 / netfilter / ipt_CLUSTERIP.c
CommitLineData
1da177e4
LT
1/* Cluster IP hashmark target
2 * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
3 * based on ideas of Fabio Olive Leite <olive@unixforge.org>
4 *
5 * Development of this code funded by SuSE Linux AG, http://www.suse.com/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/module.h>
1da177e4
LT
13#include <linux/proc_fs.h>
14#include <linux/jhash.h>
136e92bb 15#include <linux/bitops.h>
1da177e4
LT
16#include <linux/skbuff.h>
17#include <linux/ip.h>
18#include <linux/tcp.h>
19#include <linux/udp.h>
20#include <linux/icmp.h>
21#include <linux/if_arp.h>
22#include <linux/proc_fs.h>
23#include <linux/seq_file.h>
24
25#include <net/checksum.h>
26
27#include <linux/netfilter_arp.h>
28
29#include <linux/netfilter_ipv4/ip_tables.h>
30#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
9fb9cbb1 31#include <net/netfilter/nf_conntrack_compat.h>
1da177e4 32
136e92bb 33#define CLUSTERIP_VERSION "0.8"
1da177e4
LT
34
35#define DEBUG_CLUSTERIP
36
37#ifdef DEBUG_CLUSTERIP
38#define DEBUGP printk
39#else
40#define DEBUGP
41#endif
42
43MODULE_LICENSE("GPL");
44MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
45MODULE_DESCRIPTION("iptables target for CLUSTERIP");
46
47struct clusterip_config {
48 struct list_head list; /* list of all configs */
49 atomic_t refcount; /* reference count */
44513624
KK
50 atomic_t entries; /* number of entries/rules
51 * referencing us */
1da177e4 52
6a19d614 53 __be32 clusterip; /* the IP address */
1da177e4
LT
54 u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
55 struct net_device *dev; /* device */
56 u_int16_t num_total_nodes; /* total number of nodes */
136e92bb 57 unsigned long local_nodes; /* node number array */
1da177e4
LT
58
59#ifdef CONFIG_PROC_FS
60 struct proc_dir_entry *pde; /* proc dir entry */
61#endif
62 enum clusterip_hashmode hash_mode; /* which hashing mode */
63 u_int32_t hash_initval; /* hash initialization */
64};
65
66static LIST_HEAD(clusterip_configs);
67
136e92bb 68/* clusterip_lock protects the clusterip_configs list */
e45b1be8 69static DEFINE_RWLOCK(clusterip_lock);
1da177e4
LT
70
71#ifdef CONFIG_PROC_FS
72static struct file_operations clusterip_proc_fops;
73static struct proc_dir_entry *clusterip_procdir;
74#endif
75
76static inline void
44513624
KK
77clusterip_config_get(struct clusterip_config *c)
78{
1da177e4
LT
79 atomic_inc(&c->refcount);
80}
81
82static inline void
44513624
KK
83clusterip_config_put(struct clusterip_config *c)
84{
85 if (atomic_dec_and_test(&c->refcount))
86 kfree(c);
87}
88
89/* increase the count of entries(rules) using/referencing this config */
90static inline void
91clusterip_config_entry_get(struct clusterip_config *c)
92{
93 atomic_inc(&c->entries);
94}
95
96/* decrease the count of entries using/referencing this config. If last
97 * entry(rule) is removed, remove the config from lists, but don't free it
98 * yet, since proc-files could still be holding references */
99static inline void
100clusterip_config_entry_put(struct clusterip_config *c)
101{
102 if (atomic_dec_and_test(&c->entries)) {
e45b1be8 103 write_lock_bh(&clusterip_lock);
1da177e4 104 list_del(&c->list);
e45b1be8 105 write_unlock_bh(&clusterip_lock);
44513624 106
1da177e4
LT
107 dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0);
108 dev_put(c->dev);
44513624
KK
109
110 /* In case anyone still accesses the file, the open/close
111 * functions are also incrementing the refcount on their own,
112 * so it's safe to remove the entry even if it's in use. */
113#ifdef CONFIG_PROC_FS
114 remove_proc_entry(c->pde->name, c->pde->parent);
115#endif
1da177e4
LT
116 }
117}
118
1da177e4 119static struct clusterip_config *
6a19d614 120__clusterip_config_find(__be32 clusterip)
1da177e4
LT
121{
122 struct list_head *pos;
123
1da177e4
LT
124 list_for_each(pos, &clusterip_configs) {
125 struct clusterip_config *c = list_entry(pos,
126 struct clusterip_config, list);
127 if (c->clusterip == clusterip) {
128 return c;
129 }
130 }
131
132 return NULL;
133}
134
135static inline struct clusterip_config *
6a19d614 136clusterip_config_find_get(__be32 clusterip, int entry)
1da177e4
LT
137{
138 struct clusterip_config *c;
139
e45b1be8 140 read_lock_bh(&clusterip_lock);
1da177e4
LT
141 c = __clusterip_config_find(clusterip);
142 if (!c) {
e45b1be8 143 read_unlock_bh(&clusterip_lock);
1da177e4
LT
144 return NULL;
145 }
146 atomic_inc(&c->refcount);
44513624
KK
147 if (entry)
148 atomic_inc(&c->entries);
e45b1be8 149 read_unlock_bh(&clusterip_lock);
1da177e4
LT
150
151 return c;
152}
153
136e92bb
KK
154static void
155clusterip_config_init_nodelist(struct clusterip_config *c,
156 const struct ipt_clusterip_tgt_info *i)
157{
158 int n;
159
160 for (n = 0; n < i->num_local_nodes; n++) {
161 set_bit(i->local_nodes[n] - 1, &c->local_nodes);
162 }
163}
164
1da177e4 165static struct clusterip_config *
6a19d614 166clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
1da177e4
LT
167 struct net_device *dev)
168{
169 struct clusterip_config *c;
170 char buffer[16];
171
0da974f4 172 c = kzalloc(sizeof(*c), GFP_ATOMIC);
1da177e4
LT
173 if (!c)
174 return NULL;
175
1da177e4
LT
176 c->dev = dev;
177 c->clusterip = ip;
178 memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
179 c->num_total_nodes = i->num_total_nodes;
136e92bb 180 clusterip_config_init_nodelist(c, i);
1da177e4
LT
181 c->hash_mode = i->hash_mode;
182 c->hash_initval = i->hash_initval;
183 atomic_set(&c->refcount, 1);
44513624 184 atomic_set(&c->entries, 1);
1da177e4
LT
185
186#ifdef CONFIG_PROC_FS
187 /* create proc dir entry */
188 sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
189 c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, clusterip_procdir);
190 if (!c->pde) {
191 kfree(c);
192 return NULL;
193 }
194 c->pde->proc_fops = &clusterip_proc_fops;
195 c->pde->data = c;
196#endif
197
e45b1be8 198 write_lock_bh(&clusterip_lock);
1da177e4 199 list_add(&c->list, &clusterip_configs);
e45b1be8 200 write_unlock_bh(&clusterip_lock);
1da177e4
LT
201
202 return c;
203}
204
205static int
206clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
207{
1da177e4 208
136e92bb
KK
209 if (nodenum == 0 ||
210 nodenum > c->num_total_nodes)
1da177e4 211 return 1;
1da177e4 212
136e92bb
KK
213 /* check if we already have this number in our bitfield */
214 if (test_and_set_bit(nodenum - 1, &c->local_nodes))
215 return 1;
1da177e4 216
1da177e4
LT
217 return 0;
218}
219
220static int
221clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum)
222{
136e92bb
KK
223 if (nodenum == 0 ||
224 nodenum > c->num_total_nodes)
1da177e4 225 return 1;
1da177e4 226
136e92bb
KK
227 if (test_and_clear_bit(nodenum - 1, &c->local_nodes))
228 return 0;
1da177e4 229
1da177e4
LT
230 return 1;
231}
232
233static inline u_int32_t
234clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
235{
236 struct iphdr *iph = skb->nh.iph;
237 unsigned long hashval;
238 u_int16_t sport, dport;
957dc80a 239 u_int16_t *ports;
1da177e4
LT
240
241 switch (iph->protocol) {
242 case IPPROTO_TCP:
1da177e4 243 case IPPROTO_UDP:
957dc80a
PM
244 case IPPROTO_SCTP:
245 case IPPROTO_DCCP:
1da177e4 246 case IPPROTO_ICMP:
957dc80a
PM
247 ports = (void *)iph+iph->ihl*4;
248 sport = ports[0];
249 dport = ports[1];
1da177e4
LT
250 break;
251 default:
252 if (net_ratelimit()) {
253 printk(KERN_NOTICE "CLUSTERIP: unknown protocol `%u'\n",
254 iph->protocol);
255 }
256 sport = dport = 0;
257 }
258
259 switch (config->hash_mode) {
260 case CLUSTERIP_HASHMODE_SIP:
261 hashval = jhash_1word(ntohl(iph->saddr),
262 config->hash_initval);
263 break;
264 case CLUSTERIP_HASHMODE_SIP_SPT:
265 hashval = jhash_2words(ntohl(iph->saddr), sport,
266 config->hash_initval);
267 break;
268 case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
269 hashval = jhash_3words(ntohl(iph->saddr), sport, dport,
270 config->hash_initval);
271 break;
272 default:
273 /* to make gcc happy */
274 hashval = 0;
275 /* This cannot happen, unless the check function wasn't called
276 * at rule load time */
277 printk("CLUSTERIP: unknown mode `%u'\n", config->hash_mode);
278 BUG();
279 break;
280 }
281
282 /* node numbers are 1..n, not 0..n */
283 return ((hashval % config->num_total_nodes)+1);
284}
285
286static inline int
287clusterip_responsible(struct clusterip_config *config, u_int32_t hash)
288{
136e92bb 289 return test_bit(hash - 1, &config->local_nodes);
1da177e4
LT
290}
291
292/***********************************************************************
293 * IPTABLES TARGET
294 ***********************************************************************/
295
296static unsigned int
297target(struct sk_buff **pskb,
298 const struct net_device *in,
299 const struct net_device *out,
300 unsigned int hooknum,
c4986734 301 const struct xt_target *target,
fe1cb108 302 const void *targinfo)
1da177e4
LT
303{
304 const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
305 enum ip_conntrack_info ctinfo;
9fb9cbb1 306 u_int32_t *mark, hash;
1da177e4
LT
307
308 /* don't need to clusterip_config_get() here, since refcount
309 * is only decremented by destroy() - and ip_tables guarantees
310 * that the ->target() function isn't called after ->destroy() */
311
9fb9cbb1
YK
312 mark = nf_ct_get_mark((*pskb), &ctinfo);
313 if (mark == NULL) {
1da177e4
LT
314 printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
315 /* FIXME: need to drop invalid ones, since replies
316 * to outgoing connections of other nodes will be
317 * marked as INVALID */
318 return NF_DROP;
319 }
320
321 /* special case: ICMP error handling. conntrack distinguishes between
322 * error messages (RELATED) and information requests (see below) */
323 if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
324 && (ctinfo == IP_CT_RELATED
5d927eb0 325 || ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY))
1da177e4
LT
326 return IPT_CONTINUE;
327
328 /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO,
329 * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
330 * on, which all have an ID field [relevant for hashing]. */
331
332 hash = clusterip_hashfn(*pskb, cipinfo->config);
333
334 switch (ctinfo) {
335 case IP_CT_NEW:
9fb9cbb1 336 *mark = hash;
1da177e4
LT
337 break;
338 case IP_CT_RELATED:
339 case IP_CT_RELATED+IP_CT_IS_REPLY:
340 /* FIXME: we don't handle expectations at the
341 * moment. they can arrive on a different node than
342 * the master connection (e.g. FTP passive mode) */
343 case IP_CT_ESTABLISHED:
344 case IP_CT_ESTABLISHED+IP_CT_IS_REPLY:
345 break;
346 default:
347 break;
348 }
349
350#ifdef DEBUG_CLUSTERP
351 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
352#endif
9fb9cbb1 353 DEBUGP("hash=%u ct_hash=%u ", hash, *mark);
1da177e4
LT
354 if (!clusterip_responsible(cipinfo->config, hash)) {
355 DEBUGP("not responsible\n");
356 return NF_DROP;
357 }
358 DEBUGP("responsible\n");
359
360 /* despite being received via linklayer multicast, this is
361 * actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
362 (*pskb)->pkt_type = PACKET_HOST;
363
364 return IPT_CONTINUE;
365}
366
367static int
368checkentry(const char *tablename,
2e4e6a17 369 const void *e_void,
c4986734 370 const struct xt_target *target,
1da177e4 371 void *targinfo,
1da177e4
LT
372 unsigned int hook_mask)
373{
374 struct ipt_clusterip_tgt_info *cipinfo = targinfo;
2e4e6a17 375 const struct ipt_entry *e = e_void;
1da177e4
LT
376
377 struct clusterip_config *config;
378
1da177e4
LT
379 if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
380 cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
381 cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
382 printk(KERN_WARNING "CLUSTERIP: unknown mode `%u'\n",
383 cipinfo->hash_mode);
384 return 0;
385
386 }
6a19d614 387 if (e->ip.dmsk.s_addr != htonl(0xffffffff)
1da177e4
LT
388 || e->ip.dst.s_addr == 0) {
389 printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
390 return 0;
391 }
392
393 /* FIXME: further sanity checks */
394
44513624
KK
395 config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
396 if (config) {
397 if (cipinfo->config != NULL) {
398 /* Case A: This is an entry that gets reloaded, since
399 * it still has a cipinfo->config pointer. Simply
400 * increase the entry refcount and return */
401 if (cipinfo->config != config) {
402 printk(KERN_ERR "CLUSTERIP: Reloaded entry "
403 "has invalid config pointer!\n");
404 return 0;
405 }
406 clusterip_config_entry_get(cipinfo->config);
407 } else {
408 /* Case B: This is a new rule referring to an existing
409 * clusterip config. */
410 cipinfo->config = config;
411 clusterip_config_entry_get(cipinfo->config);
412 }
413 } else {
414 /* Case C: This is a completely new clusterip config */
1da177e4
LT
415 if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
416 printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr));
417 return 0;
418 } else {
419 struct net_device *dev;
420
421 if (e->ip.iniface[0] == '\0') {
422 printk(KERN_WARNING "CLUSTERIP: Please specify an interface name\n");
423 return 0;
424 }
425
426 dev = dev_get_by_name(e->ip.iniface);
427 if (!dev) {
428 printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface);
429 return 0;
430 }
431
432 config = clusterip_config_init(cipinfo,
433 e->ip.dst.s_addr, dev);
434 if (!config) {
435 printk(KERN_WARNING "CLUSTERIP: cannot allocate config\n");
436 dev_put(dev);
437 return 0;
438 }
439 dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0);
440 }
44513624 441 cipinfo->config = config;
1da177e4
LT
442 }
443
1da177e4
LT
444 return 1;
445}
446
447/* drop reference count of cluster config when rule is deleted */
efa74165 448static void destroy(const struct xt_target *target, void *targinfo)
1da177e4 449{
c4986734 450 struct ipt_clusterip_tgt_info *cipinfo = targinfo;
1da177e4 451
44513624
KK
452 /* if no more entries are referencing the config, remove it
453 * from the list and destroy the proc entry */
454 clusterip_config_entry_put(cipinfo->config);
455
1da177e4
LT
456 clusterip_config_put(cipinfo->config);
457}
458
1d5cd909
PM
459static struct ipt_target clusterip_tgt = {
460 .name = "CLUSTERIP",
461 .target = target,
462 .targetsize = sizeof(struct ipt_clusterip_tgt_info),
463 .checkentry = checkentry,
464 .destroy = destroy,
465 .me = THIS_MODULE
1da177e4
LT
466};
467
468
469/***********************************************************************
470 * ARP MANGLING CODE
471 ***********************************************************************/
472
473/* hardcoded for 48bit ethernet and 32bit ipv4 addresses */
474struct arp_payload {
475 u_int8_t src_hw[ETH_ALEN];
6a19d614 476 __be32 src_ip;
1da177e4 477 u_int8_t dst_hw[ETH_ALEN];
6a19d614 478 __be32 dst_ip;
1da177e4
LT
479} __attribute__ ((packed));
480
481#ifdef CLUSTERIP_DEBUG
482static void arp_print(struct arp_payload *payload)
483{
484#define HBUFFERLEN 30
485 char hbuffer[HBUFFERLEN];
486 int j,k;
487 const char hexbuf[]= "0123456789abcdef";
488
489 for (k=0, j=0; k < HBUFFERLEN-3 && j < ETH_ALEN; j++) {
490 hbuffer[k++]=hexbuf[(payload->src_hw[j]>>4)&15];
491 hbuffer[k++]=hexbuf[payload->src_hw[j]&15];
492 hbuffer[k++]=':';
493 }
494 hbuffer[--k]='\0';
495
496 printk("src %u.%u.%u.%u@%s, dst %u.%u.%u.%u\n",
497 NIPQUAD(payload->src_ip), hbuffer,
498 NIPQUAD(payload->dst_ip));
499}
500#endif
501
502static unsigned int
503arp_mangle(unsigned int hook,
504 struct sk_buff **pskb,
505 const struct net_device *in,
506 const struct net_device *out,
507 int (*okfn)(struct sk_buff *))
508{
509 struct arphdr *arp = (*pskb)->nh.arph;
510 struct arp_payload *payload;
511 struct clusterip_config *c;
512
513 /* we don't care about non-ethernet and non-ipv4 ARP */
514 if (arp->ar_hrd != htons(ARPHRD_ETHER)
515 || arp->ar_pro != htons(ETH_P_IP)
516 || arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN)
517 return NF_ACCEPT;
518
4095ebf1
HW
519 /* we only want to mangle arp requests and replies */
520 if (arp->ar_op != htons(ARPOP_REPLY)
521 && arp->ar_op != htons(ARPOP_REQUEST))
1da177e4
LT
522 return NF_ACCEPT;
523
524 payload = (void *)(arp+1);
525
526 /* if there is no clusterip configuration for the arp reply's
527 * source ip, we don't want to mangle it */
44513624 528 c = clusterip_config_find_get(payload->src_ip, 0);
1da177e4
LT
529 if (!c)
530 return NF_ACCEPT;
531
532 /* normally the linux kernel always replies to arp queries of
533 * addresses on different interfacs. However, in the CLUSTERIP case
534 * this wouldn't work, since we didn't subscribe the mcast group on
535 * other interfaces */
536 if (c->dev != out) {
537 DEBUGP("CLUSTERIP: not mangling arp reply on different "
538 "interface: cip'%s'-skb'%s'\n", c->dev->name, out->name);
539 clusterip_config_put(c);
540 return NF_ACCEPT;
541 }
542
543 /* mangle reply hardware address */
544 memcpy(payload->src_hw, c->clustermac, arp->ar_hln);
545
546#ifdef CLUSTERIP_DEBUG
547 DEBUGP(KERN_DEBUG "CLUSTERIP mangled arp reply: ");
548 arp_print(payload);
549#endif
550
551 clusterip_config_put(c);
552
553 return NF_ACCEPT;
554}
555
556static struct nf_hook_ops cip_arp_ops = {
557 .hook = arp_mangle,
558 .pf = NF_ARP,
559 .hooknum = NF_ARP_OUT,
560 .priority = -1
561};
562
563/***********************************************************************
564 * PROC DIR HANDLING
565 ***********************************************************************/
566
567#ifdef CONFIG_PROC_FS
568
136e92bb
KK
569struct clusterip_seq_position {
570 unsigned int pos; /* position */
571 unsigned int weight; /* number of bits set == size */
572 unsigned int bit; /* current bit */
573 unsigned long val; /* current value */
574};
575
1da177e4
LT
576static void *clusterip_seq_start(struct seq_file *s, loff_t *pos)
577{
578 struct proc_dir_entry *pde = s->private;
579 struct clusterip_config *c = pde->data;
136e92bb
KK
580 unsigned int weight;
581 u_int32_t local_nodes;
582 struct clusterip_seq_position *idx;
583
584 /* FIXME: possible race */
585 local_nodes = c->local_nodes;
586 weight = hweight32(local_nodes);
587 if (*pos >= weight)
1da177e4
LT
588 return NULL;
589
136e92bb
KK
590 idx = kmalloc(sizeof(struct clusterip_seq_position), GFP_KERNEL);
591 if (!idx)
1da177e4
LT
592 return ERR_PTR(-ENOMEM);
593
136e92bb
KK
594 idx->pos = *pos;
595 idx->weight = weight;
596 idx->bit = ffs(local_nodes);
597 idx->val = local_nodes;
598 clear_bit(idx->bit - 1, &idx->val);
599
600 return idx;
1da177e4
LT
601}
602
603static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos)
604{
136e92bb 605 struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v;
1da177e4 606
136e92bb
KK
607 *pos = ++idx->pos;
608 if (*pos >= idx->weight) {
1da177e4
LT
609 kfree(v);
610 return NULL;
611 }
136e92bb
KK
612 idx->bit = ffs(idx->val);
613 clear_bit(idx->bit - 1, &idx->val);
614 return idx;
1da177e4
LT
615}
616
617static void clusterip_seq_stop(struct seq_file *s, void *v)
618{
619 kfree(v);
1da177e4
LT
620}
621
622static int clusterip_seq_show(struct seq_file *s, void *v)
623{
136e92bb 624 struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v;
1da177e4 625
136e92bb 626 if (idx->pos != 0)
1da177e4 627 seq_putc(s, ',');
1da177e4 628
136e92bb
KK
629 seq_printf(s, "%u", idx->bit);
630
631 if (idx->pos == idx->weight - 1)
1da177e4
LT
632 seq_putc(s, '\n');
633
634 return 0;
635}
636
637static struct seq_operations clusterip_seq_ops = {
638 .start = clusterip_seq_start,
639 .next = clusterip_seq_next,
640 .stop = clusterip_seq_stop,
641 .show = clusterip_seq_show,
642};
643
644static int clusterip_proc_open(struct inode *inode, struct file *file)
645{
646 int ret = seq_open(file, &clusterip_seq_ops);
647
648 if (!ret) {
649 struct seq_file *sf = file->private_data;
650 struct proc_dir_entry *pde = PDE(inode);
651 struct clusterip_config *c = pde->data;
652
653 sf->private = pde;
654
655 clusterip_config_get(c);
656 }
657
658 return ret;
659}
660
661static int clusterip_proc_release(struct inode *inode, struct file *file)
662{
663 struct proc_dir_entry *pde = PDE(inode);
664 struct clusterip_config *c = pde->data;
665 int ret;
666
667 ret = seq_release(inode, file);
668
669 if (!ret)
670 clusterip_config_put(c);
671
672 return ret;
673}
674
675static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
676 size_t size, loff_t *ofs)
677{
678#define PROC_WRITELEN 10
679 char buffer[PROC_WRITELEN+1];
680 struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
681 struct clusterip_config *c = pde->data;
682 unsigned long nodenum;
683
684 if (copy_from_user(buffer, input, PROC_WRITELEN))
685 return -EFAULT;
686
687 if (*buffer == '+') {
688 nodenum = simple_strtoul(buffer+1, NULL, 10);
689 if (clusterip_add_node(c, nodenum))
690 return -ENOMEM;
691 } else if (*buffer == '-') {
692 nodenum = simple_strtoul(buffer+1, NULL,10);
693 if (clusterip_del_node(c, nodenum))
694 return -ENOENT;
695 } else
696 return -EIO;
697
698 return size;
699}
700
701static struct file_operations clusterip_proc_fops = {
702 .owner = THIS_MODULE,
703 .open = clusterip_proc_open,
704 .read = seq_read,
705 .write = clusterip_proc_write,
706 .llseek = seq_lseek,
707 .release = clusterip_proc_release,
708};
709
710#endif /* CONFIG_PROC_FS */
711
32292a7f 712static int __init ipt_clusterip_init(void)
1da177e4
LT
713{
714 int ret;
715
32292a7f
PM
716 ret = ipt_register_target(&clusterip_tgt);
717 if (ret < 0)
718 return ret;
1da177e4 719
32292a7f
PM
720 ret = nf_register_hook(&cip_arp_ops);
721 if (ret < 0)
1da177e4 722 goto cleanup_target;
1da177e4
LT
723
724#ifdef CONFIG_PROC_FS
725 clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net);
726 if (!clusterip_procdir) {
727 printk(KERN_ERR "CLUSTERIP: Unable to proc dir entry\n");
728 ret = -ENOMEM;
729 goto cleanup_hook;
730 }
731#endif /* CONFIG_PROC_FS */
732
733 printk(KERN_NOTICE "ClusterIP Version %s loaded successfully\n",
734 CLUSTERIP_VERSION);
1da177e4
LT
735 return 0;
736
1da177e4
LT
737cleanup_hook:
738 nf_unregister_hook(&cip_arp_ops);
739cleanup_target:
740 ipt_unregister_target(&clusterip_tgt);
32292a7f 741 return ret;
1da177e4
LT
742}
743
65b4b4e8 744static void __exit ipt_clusterip_fini(void)
1da177e4 745{
32292a7f
PM
746 printk(KERN_NOTICE "ClusterIP Version %s unloading\n",
747 CLUSTERIP_VERSION);
748#ifdef CONFIG_PROC_FS
749 remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
750#endif
751 nf_unregister_hook(&cip_arp_ops);
752 ipt_unregister_target(&clusterip_tgt);
1da177e4
LT
753}
754
65b4b4e8
AM
755module_init(ipt_clusterip_init);
756module_exit(ipt_clusterip_fini);