~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv4/netfilter/ipt_CLUSTERIP.c

Version: ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 13 #include <linux/module.h>
 14 #include <linux/proc_fs.h>
 15 #include <linux/jhash.h>
 16 #include <linux/bitops.h>
 17 #include <linux/skbuff.h>
 18 #include <linux/slab.h>
 19 #include <linux/ip.h>
 20 #include <linux/tcp.h>
 21 #include <linux/udp.h>
 22 #include <linux/icmp.h>
 23 #include <linux/if_arp.h>
 24 #include <linux/seq_file.h>
 25 #include <linux/netfilter_arp.h>
 26 #include <linux/netfilter/x_tables.h>
 27 #include <linux/netfilter_ipv4/ip_tables.h>
 28 #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
 29 #include <net/netfilter/nf_conntrack.h>
 30 #include <net/net_namespace.h>
 31 #include <net/netns/generic.h>
 32 #include <net/checksum.h>
 33 #include <net/ip.h>
 34 
 35 #define CLUSTERIP_VERSION "0.8"
 36 
 37 MODULE_LICENSE("GPL");
 38 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 39 MODULE_DESCRIPTION("Xtables: CLUSTERIP target");
 40 
 41 struct clusterip_config {
 42         struct list_head list;                  /* list of all configs */
 43         atomic_t refcount;                      /* reference count */
 44         atomic_t entries;                       /* number of entries/rules
 45                                                  * referencing us */
 46 
 47         __be32 clusterip;                       /* the IP address */
 48         u_int8_t clustermac[ETH_ALEN];          /* the MAC address */
 49         struct net_device *dev;                 /* device */
 50         u_int16_t num_total_nodes;              /* total number of nodes */
 51         unsigned long local_nodes;              /* node number array */
 52 
 53 #ifdef CONFIG_PROC_FS
 54         struct proc_dir_entry *pde;             /* proc dir entry */
 55 #endif
 56         enum clusterip_hashmode hash_mode;      /* which hashing mode */
 57         u_int32_t hash_initval;                 /* hash initialization */
 58         struct rcu_head rcu;
 59 };
 60 
 61 #ifdef CONFIG_PROC_FS
 62 static const struct file_operations clusterip_proc_fops;
 63 #endif
 64 
 65 static unsigned int clusterip_net_id __read_mostly;
 66 
 67 struct clusterip_net {
 68         struct list_head configs;
 69         /* lock protects the configs list */
 70         spinlock_t lock;
 71 
 72 #ifdef CONFIG_PROC_FS
 73         struct proc_dir_entry *procdir;
 74 #endif
 75 };
 76 
 77 static inline void
 78 clusterip_config_get(struct clusterip_config *c)
 79 {
 80         atomic_inc(&c->refcount);
 81 }
 82 
 83 
 84 static void clusterip_config_rcu_free(struct rcu_head *head)
 85 {
 86         kfree(container_of(head, struct clusterip_config, rcu));
 87 }
 88 
 89 static inline void
 90 clusterip_config_put(struct clusterip_config *c)
 91 {
 92         if (atomic_dec_and_test(&c->refcount))
 93                 call_rcu_bh(&c->rcu, clusterip_config_rcu_free);
 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 */
 99 static inline void
100 clusterip_config_entry_put(struct clusterip_config *c)
101 {
102         struct net *net = dev_net(c->dev);
103         struct clusterip_net *cn = net_generic(net, clusterip_net_id);
104 
105         local_bh_disable();
106         if (atomic_dec_and_lock(&c->entries, &cn->lock)) {
107                 list_del_rcu(&c->list);
108                 spin_unlock(&cn->lock);
109                 local_bh_enable();
110 
111                 dev_mc_del(c->dev, c->clustermac);
112                 dev_put(c->dev);
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                 proc_remove(c->pde);
119 #endif
120                 return;
121         }
122         local_bh_enable();
123 }
124 
125 static struct clusterip_config *
126 __clusterip_config_find(struct net *net, __be32 clusterip)
127 {
128         struct clusterip_config *c;
129         struct clusterip_net *cn = net_generic(net, clusterip_net_id);
130 
131         list_for_each_entry_rcu(c, &cn->configs, list) {
132                 if (c->clusterip == clusterip)
133                         return c;
134         }
135 
136         return NULL;
137 }
138 
139 static inline struct clusterip_config *
140 clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
141 {
142         struct clusterip_config *c;
143 
144         rcu_read_lock_bh();
145         c = __clusterip_config_find(net, clusterip);
146         if (c) {
147 #ifdef CONFIG_PROC_FS
148                 if (!c->pde)
149                         c = NULL;
150                 else
151 #endif
152                 if (unlikely(!atomic_inc_not_zero(&c->refcount)))
153                         c = NULL;
154                 else if (entry)
155                         atomic_inc(&c->entries);
156         }
157         rcu_read_unlock_bh();
158 
159         return c;
160 }
161 
162 static void
163 clusterip_config_init_nodelist(struct clusterip_config *c,
164                                const struct ipt_clusterip_tgt_info *i)
165 {
166         int n;
167 
168         for (n = 0; n < i->num_local_nodes; n++)
169                 set_bit(i->local_nodes[n] - 1, &c->local_nodes);
170 }
171 
172 static struct clusterip_config *
173 clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
174                       struct net_device *dev)
175 {
176         struct net *net = dev_net(dev);
177         struct clusterip_config *c;
178         struct clusterip_net *cn = net_generic(net, clusterip_net_id);
179 
180         c = kzalloc(sizeof(*c), GFP_ATOMIC);
181         if (!c)
182                 return ERR_PTR(-ENOMEM);
183 
184         c->dev = dev;
185         c->clusterip = ip;
186         memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
187         c->num_total_nodes = i->num_total_nodes;
188         clusterip_config_init_nodelist(c, i);
189         c->hash_mode = i->hash_mode;
190         c->hash_initval = i->hash_initval;
191         atomic_set(&c->refcount, 1);
192         atomic_set(&c->entries, 1);
193 
194         spin_lock_bh(&cn->lock);
195         if (__clusterip_config_find(net, ip)) {
196                 spin_unlock_bh(&cn->lock);
197                 kfree(c);
198 
199                 return ERR_PTR(-EBUSY);
200         }
201 
202         list_add_rcu(&c->list, &cn->configs);
203         spin_unlock_bh(&cn->lock);
204 
205 #ifdef CONFIG_PROC_FS
206         {
207                 char buffer[16];
208 
209                 /* create proc dir entry */
210                 sprintf(buffer, "%pI4", &ip);
211                 c->pde = proc_create_data(buffer, S_IWUSR|S_IRUSR,
212                                           cn->procdir,
213                                           &clusterip_proc_fops, c);
214                 if (!c->pde) {
215                         spin_lock_bh(&cn->lock);
216                         list_del_rcu(&c->list);
217                         spin_unlock_bh(&cn->lock);
218                         kfree(c);
219 
220                         return ERR_PTR(-ENOMEM);
221                 }
222         }
223 #endif
224 
225         return c;
226 }
227 
228 #ifdef CONFIG_PROC_FS
229 static int
230 clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
231 {
232 
233         if (nodenum == 0 ||
234             nodenum > c->num_total_nodes)
235                 return 1;
236 
237         /* check if we already have this number in our bitfield */
238         if (test_and_set_bit(nodenum - 1, &c->local_nodes))
239                 return 1;
240 
241         return 0;
242 }
243 
244 static bool
245 clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum)
246 {
247         if (nodenum == 0 ||
248             nodenum > c->num_total_nodes)
249                 return true;
250 
251         if (test_and_clear_bit(nodenum - 1, &c->local_nodes))
252                 return false;
253 
254         return true;
255 }
256 #endif
257 
258 static inline u_int32_t
259 clusterip_hashfn(const struct sk_buff *skb,
260                  const struct clusterip_config *config)
261 {
262         const struct iphdr *iph = ip_hdr(skb);
263         unsigned long hashval;
264         u_int16_t sport = 0, dport = 0;
265         int poff;
266 
267         poff = proto_ports_offset(iph->protocol);
268         if (poff >= 0) {
269                 const u_int16_t *ports;
270                 u16 _ports[2];
271 
272                 ports = skb_header_pointer(skb, iph->ihl * 4 + poff, 4, _ports);
273                 if (ports) {
274                         sport = ports[0];
275                         dport = ports[1];
276                 }
277         } else {
278                 net_info_ratelimited("unknown protocol %u\n", iph->protocol);
279         }
280 
281         switch (config->hash_mode) {
282         case CLUSTERIP_HASHMODE_SIP:
283                 hashval = jhash_1word(ntohl(iph->saddr),
284                                       config->hash_initval);
285                 break;
286         case CLUSTERIP_HASHMODE_SIP_SPT:
287                 hashval = jhash_2words(ntohl(iph->saddr), sport,
288                                        config->hash_initval);
289                 break;
290         case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
291                 hashval = jhash_3words(ntohl(iph->saddr), sport, dport,
292                                        config->hash_initval);
293                 break;
294         default:
295                 /* to make gcc happy */
296                 hashval = 0;
297                 /* This cannot happen, unless the check function wasn't called
298                  * at rule load time */
299                 pr_info("unknown mode %u\n", config->hash_mode);
300                 BUG();
301                 break;
302         }
303 
304         /* node numbers are 1..n, not 0..n */
305         return reciprocal_scale(hashval, config->num_total_nodes) + 1;
306 }
307 
308 static inline int
309 clusterip_responsible(const struct clusterip_config *config, u_int32_t hash)
310 {
311         return test_bit(hash - 1, &config->local_nodes);
312 }
313 
314 /***********************************************************************
315  * IPTABLES TARGET
316  ***********************************************************************/
317 
318 static unsigned int
319 clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
320 {
321         const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
322         struct nf_conn *ct;
323         enum ip_conntrack_info 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         ct = nf_ct_get(skb, &ctinfo);
331         if (ct == NULL)
332                 return NF_DROP;
333 
334         /* special case: ICMP error handling. conntrack distinguishes between
335          * error messages (RELATED) and information requests (see below) */
336         if (ip_hdr(skb)->protocol == IPPROTO_ICMP &&
337             (ctinfo == IP_CT_RELATED ||
338              ctinfo == IP_CT_RELATED_REPLY))
339                 return XT_CONTINUE;
340 
341         /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO,
342          * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
343          * on, which all have an ID field [relevant for hashing]. */
344 
345         hash = clusterip_hashfn(skb, cipinfo->config);
346 
347         switch (ctinfo) {
348         case IP_CT_NEW:
349                 ct->mark = hash;
350                 break;
351         case IP_CT_RELATED:
352         case IP_CT_RELATED_REPLY:
353                 /* FIXME: we don't handle expectations at the moment.
354                  * They can arrive on a different node than
355                  * the master connection (e.g. FTP passive mode) */
356         case IP_CT_ESTABLISHED:
357         case IP_CT_ESTABLISHED_REPLY:
358                 break;
359         default:                        /* Prevent gcc warnings */
360                 break;
361         }
362 
363 #ifdef DEBUG
364         nf_ct_dump_tuple_ip(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
365 #endif
366         pr_debug("hash=%u ct_hash=%u ", hash, ct->mark);
367         if (!clusterip_responsible(cipinfo->config, hash)) {
368                 pr_debug("not responsible\n");
369                 return NF_DROP;
370         }
371         pr_debug("responsible\n");
372 
373         /* despite being received via linklayer multicast, this is
374          * actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
375         skb->pkt_type = PACKET_HOST;
376 
377         return XT_CONTINUE;
378 }
379 
380 static int clusterip_tg_check(const struct xt_tgchk_param *par)
381 {
382         struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
383         const struct ipt_entry *e = par->entryinfo;
384         struct clusterip_config *config;
385         int ret;
386 
387         if (par->nft_compat) {
388                 pr_err("cannot use CLUSTERIP target from nftables compat\n");
389                 return -EOPNOTSUPP;
390         }
391 
392         if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
393             cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
394             cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
395                 pr_info("unknown mode %u\n", cipinfo->hash_mode);
396                 return -EINVAL;
397 
398         }
399         if (e->ip.dmsk.s_addr != htonl(0xffffffff) ||
400             e->ip.dst.s_addr == 0) {
401                 pr_info("Please specify destination IP\n");
402                 return -EINVAL;
403         }
404 
405         /* FIXME: further sanity checks */
406 
407         config = clusterip_config_find_get(par->net, e->ip.dst.s_addr, 1);
408         if (!config) {
409                 if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
410                         pr_info("no config found for %pI4, need 'new'\n",
411                                 &e->ip.dst.s_addr);
412                         return -EINVAL;
413                 } else {
414                         struct net_device *dev;
415 
416                         if (e->ip.iniface[0] == '\0') {
417                                 pr_info("Please specify an interface name\n");
418                                 return -EINVAL;
419                         }
420 
421                         dev = dev_get_by_name(par->net, e->ip.iniface);
422                         if (!dev) {
423                                 pr_info("no such interface %s\n",
424                                         e->ip.iniface);
425                                 return -ENOENT;
426                         }
427 
428                         config = clusterip_config_init(cipinfo,
429                                                         e->ip.dst.s_addr, dev);
430                         if (IS_ERR(config)) {
431                                 dev_put(dev);
432                                 return PTR_ERR(config);
433                         }
434                         dev_mc_add(config->dev, config->clustermac);
435                 }
436         }
437         cipinfo->config = config;
438 
439         ret = nf_ct_netns_get(par->net, par->family);
440         if (ret < 0)
441                 pr_info("cannot load conntrack support for proto=%u\n",
442                         par->family);
443 
444         if (!par->net->xt.clusterip_deprecated_warning) {
445                 pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, "
446                         "use xt_cluster instead\n");
447                 par->net->xt.clusterip_deprecated_warning = true;
448         }
449 
450         return ret;
451 }
452 
453 /* drop reference count of cluster config when rule is deleted */
454 static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
455 {
456         const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
457 
458         /* if no more entries are referencing the config, remove it
459          * from the list and destroy the proc entry */
460         clusterip_config_entry_put(cipinfo->config);
461 
462         clusterip_config_put(cipinfo->config);
463 
464         nf_ct_netns_get(par->net, par->family);
465 }
466 
467 #ifdef CONFIG_COMPAT
468 struct compat_ipt_clusterip_tgt_info
469 {
470         u_int32_t       flags;
471         u_int8_t        clustermac[6];
472         u_int16_t       num_total_nodes;
473         u_int16_t       num_local_nodes;
474         u_int16_t       local_nodes[CLUSTERIP_MAX_NODES];
475         u_int32_t       hash_mode;
476         u_int32_t       hash_initval;
477         compat_uptr_t   config;
478 };
479 #endif /* CONFIG_COMPAT */
480 
481 static struct xt_target clusterip_tg_reg __read_mostly = {
482         .name           = "CLUSTERIP",
483         .family         = NFPROTO_IPV4,
484         .target         = clusterip_tg,
485         .checkentry     = clusterip_tg_check,
486         .destroy        = clusterip_tg_destroy,
487         .targetsize     = sizeof(struct ipt_clusterip_tgt_info),
488 #ifdef CONFIG_COMPAT
489         .compatsize     = sizeof(struct compat_ipt_clusterip_tgt_info),
490 #endif /* CONFIG_COMPAT */
491         .me             = THIS_MODULE
492 };
493 
494 
495 /***********************************************************************
496  * ARP MANGLING CODE
497  ***********************************************************************/
498 
499 /* hardcoded for 48bit ethernet and 32bit ipv4 addresses */
500 struct arp_payload {
501         u_int8_t src_hw[ETH_ALEN];
502         __be32 src_ip;
503         u_int8_t dst_hw[ETH_ALEN];
504         __be32 dst_ip;
505 } __packed;
506 
507 #ifdef DEBUG
508 static void arp_print(struct arp_payload *payload)
509 {
510 #define HBUFFERLEN 30
511         char hbuffer[HBUFFERLEN];
512         int j, k;
513 
514         for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < ETH_ALEN; j++) {
515                 hbuffer[k++] = hex_asc_hi(payload->src_hw[j]);
516                 hbuffer[k++] = hex_asc_lo(payload->src_hw[j]);
517                 hbuffer[k++] = ':';
518         }
519         hbuffer[--k] = '\0';
520 
521         pr_debug("src %pI4@%s, dst %pI4\n",
522                  &payload->src_ip, hbuffer, &payload->dst_ip);
523 }
524 #endif
525 
526 static unsigned int
527 arp_mangle(void *priv,
528            struct sk_buff *skb,
529            const struct nf_hook_state *state)
530 {
531         struct arphdr *arp = arp_hdr(skb);
532         struct arp_payload *payload;
533         struct clusterip_config *c;
534         struct net *net = state->net;
535 
536         /* we don't care about non-ethernet and non-ipv4 ARP */
537         if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
538             arp->ar_pro != htons(ETH_P_IP) ||
539             arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN)
540                 return NF_ACCEPT;
541 
542         /* we only want to mangle arp requests and replies */
543         if (arp->ar_op != htons(ARPOP_REPLY) &&
544             arp->ar_op != htons(ARPOP_REQUEST))
545                 return NF_ACCEPT;
546 
547         payload = (void *)(arp+1);
548 
549         /* if there is no clusterip configuration for the arp reply's
550          * source ip, we don't want to mangle it */
551         c = clusterip_config_find_get(net, payload->src_ip, 0);
552         if (!c)
553                 return NF_ACCEPT;
554 
555         /* normally the linux kernel always replies to arp queries of
556          * addresses on different interfacs.  However, in the CLUSTERIP case
557          * this wouldn't work, since we didn't subscribe the mcast group on
558          * other interfaces */
559         if (c->dev != state->out) {
560                 pr_debug("not mangling arp reply on different "
561                          "interface: cip'%s'-skb'%s'\n",
562                          c->dev->name, state->out->name);
563                 clusterip_config_put(c);
564                 return NF_ACCEPT;
565         }
566 
567         /* mangle reply hardware address */
568         memcpy(payload->src_hw, c->clustermac, arp->ar_hln);
569 
570 #ifdef DEBUG
571         pr_debug("mangled arp reply: ");
572         arp_print(payload);
573 #endif
574 
575         clusterip_config_put(c);
576 
577         return NF_ACCEPT;
578 }
579 
580 static struct nf_hook_ops cip_arp_ops __read_mostly = {
581         .hook = arp_mangle,
582         .pf = NFPROTO_ARP,
583         .hooknum = NF_ARP_OUT,
584         .priority = -1
585 };
586 
587 /***********************************************************************
588  * PROC DIR HANDLING
589  ***********************************************************************/
590 
591 #ifdef CONFIG_PROC_FS
592 
593 struct clusterip_seq_position {
594         unsigned int pos;       /* position */
595         unsigned int weight;    /* number of bits set == size */
596         unsigned int bit;       /* current bit */
597         unsigned long val;      /* current value */
598 };
599 
600 static void *clusterip_seq_start(struct seq_file *s, loff_t *pos)
601 {
602         struct clusterip_config *c = s->private;
603         unsigned int weight;
604         u_int32_t local_nodes;
605         struct clusterip_seq_position *idx;
606 
607         /* FIXME: possible race */
608         local_nodes = c->local_nodes;
609         weight = hweight32(local_nodes);
610         if (*pos >= weight)
611                 return NULL;
612 
613         idx = kmalloc(sizeof(struct clusterip_seq_position), GFP_KERNEL);
614         if (!idx)
615                 return ERR_PTR(-ENOMEM);
616 
617         idx->pos = *pos;
618         idx->weight = weight;
619         idx->bit = ffs(local_nodes);
620         idx->val = local_nodes;
621         clear_bit(idx->bit - 1, &idx->val);
622 
623         return idx;
624 }
625 
626 static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos)
627 {
628         struct clusterip_seq_position *idx = v;
629 
630         *pos = ++idx->pos;
631         if (*pos >= idx->weight) {
632                 kfree(v);
633                 return NULL;
634         }
635         idx->bit = ffs(idx->val);
636         clear_bit(idx->bit - 1, &idx->val);
637         return idx;
638 }
639 
640 static void clusterip_seq_stop(struct seq_file *s, void *v)
641 {
642         if (!IS_ERR(v))
643                 kfree(v);
644 }
645 
646 static int clusterip_seq_show(struct seq_file *s, void *v)
647 {
648         struct clusterip_seq_position *idx = v;
649 
650         if (idx->pos != 0)
651                 seq_putc(s, ',');
652 
653         seq_printf(s, "%u", idx->bit);
654 
655         if (idx->pos == idx->weight - 1)
656                 seq_putc(s, '\n');
657 
658         return 0;
659 }
660 
661 static const struct seq_operations clusterip_seq_ops = {
662         .start  = clusterip_seq_start,
663         .next   = clusterip_seq_next,
664         .stop   = clusterip_seq_stop,
665         .show   = clusterip_seq_show,
666 };
667 
668 static int clusterip_proc_open(struct inode *inode, struct file *file)
669 {
670         int ret = seq_open(file, &clusterip_seq_ops);
671 
672         if (!ret) {
673                 struct seq_file *sf = file->private_data;
674                 struct clusterip_config *c = PDE_DATA(inode);
675 
676                 sf->private = c;
677 
678                 clusterip_config_get(c);
679         }
680 
681         return ret;
682 }
683 
684 static int clusterip_proc_release(struct inode *inode, struct file *file)
685 {
686         struct clusterip_config *c = PDE_DATA(inode);
687         int ret;
688 
689         ret = seq_release(inode, file);
690 
691         if (!ret)
692                 clusterip_config_put(c);
693 
694         return ret;
695 }
696 
697 static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
698                                 size_t size, loff_t *ofs)
699 {
700         struct clusterip_config *c = PDE_DATA(file_inode(file));
701 #define PROC_WRITELEN   10
702         char buffer[PROC_WRITELEN+1];
703         unsigned long nodenum;
704         int rc;
705 
706         if (size > PROC_WRITELEN)
707                 return -EIO;
708         if (copy_from_user(buffer, input, size))
709                 return -EFAULT;
710         buffer[size] = 0;
711 
712         if (*buffer == '+') {
713                 rc = kstrtoul(buffer+1, 10, &nodenum);
714                 if (rc)
715                         return rc;
716                 if (clusterip_add_node(c, nodenum))
717                         return -ENOMEM;
718         } else if (*buffer == '-') {
719                 rc = kstrtoul(buffer+1, 10, &nodenum);
720                 if (rc)
721                         return rc;
722                 if (clusterip_del_node(c, nodenum))
723                         return -ENOENT;
724         } else
725                 return -EIO;
726 
727         return size;
728 }
729 
730 static const struct file_operations clusterip_proc_fops = {
731         .owner   = THIS_MODULE,
732         .open    = clusterip_proc_open,
733         .read    = seq_read,
734         .write   = clusterip_proc_write,
735         .llseek  = seq_lseek,
736         .release = clusterip_proc_release,
737 };
738 
739 #endif /* CONFIG_PROC_FS */
740 
741 static int clusterip_net_init(struct net *net)
742 {
743         struct clusterip_net *cn = net_generic(net, clusterip_net_id);
744 
745         INIT_LIST_HEAD(&cn->configs);
746 
747         spin_lock_init(&cn->lock);
748 
749 #ifdef CONFIG_PROC_FS
750         cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net);
751         if (!cn->procdir) {
752                 pr_err("Unable to proc dir entry\n");
753                 return -ENOMEM;
754         }
755 #endif /* CONFIG_PROC_FS */
756 
757         return 0;
758 }
759 
760 static void clusterip_net_exit(struct net *net)
761 {
762 #ifdef CONFIG_PROC_FS
763         struct clusterip_net *cn = net_generic(net, clusterip_net_id);
764         proc_remove(cn->procdir);
765 #endif
766 }
767 
768 static struct pernet_operations clusterip_net_ops = {
769         .init = clusterip_net_init,
770         .exit = clusterip_net_exit,
771         .id   = &clusterip_net_id,
772         .size = sizeof(struct clusterip_net),
773 };
774 
775 static int __init clusterip_tg_init(void)
776 {
777         int ret;
778 
779         ret = register_pernet_subsys(&clusterip_net_ops);
780         if (ret < 0)
781                 return ret;
782 
783         ret = xt_register_target(&clusterip_tg_reg);
784         if (ret < 0)
785                 goto cleanup_subsys;
786 
787         ret = nf_register_hook(&cip_arp_ops);
788         if (ret < 0)
789                 goto cleanup_target;
790 
791         pr_info("ClusterIP Version %s loaded successfully\n",
792                 CLUSTERIP_VERSION);
793 
794         return 0;
795 
796 cleanup_target:
797         xt_unregister_target(&clusterip_tg_reg);
798 cleanup_subsys:
799         unregister_pernet_subsys(&clusterip_net_ops);
800         return ret;
801 }
802 
803 static void __exit clusterip_tg_exit(void)
804 {
805         pr_info("ClusterIP Version %s unloading\n", CLUSTERIP_VERSION);
806 
807         nf_unregister_hook(&cip_arp_ops);
808         xt_unregister_target(&clusterip_tg_reg);
809         unregister_pernet_subsys(&clusterip_net_ops);
810 
811         /* Wait for completion of call_rcu_bh()'s (clusterip_config_rcu_free) */
812         rcu_barrier_bh();
813 }
814 
815 module_init(clusterip_tg_init);
816 module_exit(clusterip_tg_exit);
817 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp