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