removed function signature
[ana-net.git] / src / xt_fblock.c
blob23b10a4445c30033ba2391c3a8d48703243150c6
1 /*
2 * Lightweight Autonomic Network Architecture
4 * Global LANA IDP translation tables, core backend.
6 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
7 * Swiss federal institute of technology (ETH Zurich)
8 * Subject to the GPL.
9 */
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/rcupdate.h>
14 #include <linux/atomic.h>
15 #include <linux/types.h>
16 #include <linux/cpu.h>
17 #include <linux/spinlock.h>
18 #include <linux/rwlock.h>
19 #include <linux/slab.h>
20 #include <linux/proc_fs.h>
22 #include "xt_fblock.h"
23 #include "xt_idp.h"
24 #include "xt_hash.h"
25 #include "xt_critbit.h"
27 struct idp_elem {
28 char name[FBNAMSIZ];
29 idp_t idp;
30 struct rcu_head rcu;
31 } ____cacheline_aligned;
33 static struct critbit_tree idpmap;
34 static struct fblock **fblmap_head = NULL;
35 static spinlock_t fblmap_head_lock;
37 static atomic64_t idp_counter;
39 static struct kmem_cache *fblock_cache = NULL;
41 extern struct proc_dir_entry *lana_proc_dir;
42 static struct proc_dir_entry *fblocks_proc;
44 static inline idp_t provide_new_fblock_idp(void)
46 return (idp_t) atomic64_inc_return(&idp_counter);
49 static int register_to_fblock_namespace(char *name, idp_t val)
51 struct idp_elem *elem;
53 if (critbit_contains(&idpmap, name))
54 return -EEXIST;
55 elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
56 if (!elem)
57 return -ENOMEM;
58 strlcpy(elem->name, name, sizeof(elem->name));
59 elem->idp = val;
61 return critbit_insert(&idpmap, elem->name);
64 static void fblock_namespace_do_free_rcu(struct rcu_head *rp)
66 struct idp_elem *p = container_of(rp, struct idp_elem, rcu);
67 kfree(p);
70 static int unregister_from_fblock_namespace(char *name)
72 int ret;
73 struct idp_elem *elem;
75 elem = struct_of(critbit_get(&idpmap, name), struct idp_elem);
76 if (!elem)
77 return -ENOENT;
78 ret = critbit_delete(&idpmap, elem->name);
79 if (ret)
80 return ret;
81 call_rcu(&elem->rcu, fblock_namespace_do_free_rcu);
83 return 0;
86 /* Called within RCU read lock! */
87 idp_t __get_fblock_namespace_mapping(char *name)
89 struct idp_elem *elem = struct_of(__critbit_get(&idpmap, name),
90 struct idp_elem);
91 if (unlikely(!elem))
92 return IDP_UNKNOWN;
93 smp_rmb();
94 return elem->idp;
96 EXPORT_SYMBOL_GPL(__get_fblock_namespace_mapping);
98 idp_t get_fblock_namespace_mapping(char *name)
100 idp_t ret;
101 rcu_read_lock();
102 ret = __get_fblock_namespace_mapping(name);
103 rcu_read_unlock();
104 return ret;
106 EXPORT_SYMBOL_GPL(get_fblock_namespace_mapping);
108 /* Called within RCU read lock! */
109 int __change_fblock_namespace_mapping(char *name, idp_t new)
111 struct idp_elem *elem = struct_of(__critbit_get(&idpmap, name),
112 struct idp_elem);
113 if (unlikely(!elem))
114 return -ENOENT;
115 elem->idp = new;
116 smp_wmb();
117 return 0;
119 EXPORT_SYMBOL_GPL(__change_fblock_namespace_mapping);
121 int change_fblock_namespace_mapping(char *name, idp_t new)
123 int ret;
124 rcu_read_lock();
125 ret = __change_fblock_namespace_mapping(name, new);
126 rcu_read_unlock();
127 return ret;
129 EXPORT_SYMBOL_GPL(change_fblock_namespace_mapping);
131 /* Caller needs to do a put_fblock() after his work is done! */
132 /* Called within RCU read lock! */
133 struct fblock *__search_fblock(idp_t idp)
135 struct fblock *p0;
137 p0 = rcu_dereference_raw(fblmap_head[hash_idp(idp)]);
138 if (!p0)
139 return NULL;
140 while (p0) {
141 if (p0->idp == idp) {
142 get_fblock(p0);
143 return p0;
145 p0 = rcu_dereference_raw(p0->next);
148 return NULL;
150 EXPORT_SYMBOL_GPL(__search_fblock);
152 struct fblock *search_fblock(idp_t idp)
154 struct fblock *ret;
155 if (unlikely(idp == IDP_UNKNOWN))
156 return NULL;
157 rcu_read_lock();
158 ret = __search_fblock(idp);
159 rcu_read_unlock();
160 return ret;
162 EXPORT_SYMBOL_GPL(search_fblock);
164 /* Note: user needs to do a put_fblock */
165 struct fblock *__search_fblock_n(char *name)
167 idp_t id;
168 struct fblock *fb;
169 id = get_fblock_namespace_mapping(name);
170 if (unlikely(id == IDP_UNKNOWN))
171 return NULL;
172 fb = search_fblock(id);
173 if (!fb)
174 return NULL;
175 return fb;
177 EXPORT_SYMBOL_GPL(__search_fblock_n);
179 struct fblock *search_fblock_n(char *name)
181 struct fblock *ret;
182 if (unlikely(!name))
183 return NULL;
184 rcu_read_lock();
185 ret = __search_fblock_n(name);
186 rcu_read_unlock();
187 return ret;
189 EXPORT_SYMBOL_GPL(search_fblock_n);
191 /* opt_string must be of type "key=val" and 0-terminated */
192 int __fblock_set_option(struct fblock *fb, char *opt_string)
194 int ret = 0;
195 char *val = opt_string;
196 struct fblock_opt_msg msg;
197 /* Hack: we let the fb think that this belongs to his own chain to
198 * get the reference back to itself. */
199 struct fblock_notifier fbn;
201 memset(&fbn, 0, sizeof(fbn));
202 memset(&msg, 0, sizeof(msg));
204 msg.key = opt_string;
205 while (*val != '=' && *val != '\0')
206 val++;
207 if (*val == '\0')
208 return -EINVAL;
209 val++;
210 *(val - 1) = '\0';
211 msg.val = val;
212 fbn.self = fb;
214 get_fblock(fb);
215 ret = fb->ops->event_rx(&fbn.nb, FBLOCK_SET_OPT, &msg);
216 put_fblock(fb);
218 return ret;
220 EXPORT_SYMBOL_GPL(__fblock_set_option);
222 int fblock_set_option(struct fblock *fb, char *opt_string)
224 int ret;
225 if (unlikely(!opt_string || !fb))
226 return -EINVAL;
227 rcu_read_lock();
228 ret = __fblock_set_option(fb, opt_string);
229 rcu_read_unlock();
230 return ret;
232 EXPORT_SYMBOL_GPL(fblock_set_option);
235 * Migrate src to dst, both are of same type, working data is
236 * transferred to dst and droped from src. src gets dsts old data,
237 * so that on free, we do not need to explicitly ignore srcs
238 * private data and dsts remaining data.
240 int fblock_migrate(struct fblock *dst, struct fblock *src)
242 void *priv_old;
243 int ref_old;
244 struct fblock_notifier *not_old;
245 struct fblock_subscrib *sub_old;
247 get_fblock(dst);
248 get_fblock(src);
250 write_lock(&dst->lock);
251 write_lock(&src->lock);
253 dst->idp = src->idp;
254 strlcpy(dst->name, src->name, sizeof(dst->name));
256 rcu_assign_pointer(priv_old, dst->private_data);
257 rcu_assign_pointer(dst->private_data, src->private_data);
258 rcu_assign_pointer(src->private_data, priv_old);
260 /* Update all refs to self */
262 rcu_assign_pointer(not_old, dst->notifiers);
263 rcu_assign_pointer(dst->notifiers, src->notifiers);
264 rcu_assign_pointer(src->notifiers, not_old);
266 rcu_assign_pointer(sub_old, dst->others);
267 rcu_assign_pointer(dst->others, src->others);
268 rcu_assign_pointer(src->others, sub_old);
270 ref_old = atomic_read(&dst->refcnt);
271 atomic_set(&dst->refcnt, atomic_read(&src->refcnt));
272 atomic_set(&src->refcnt, ref_old);
274 write_unlock(&src->lock);
275 write_unlock(&dst->lock);
277 put_fblock(dst);
278 put_fblock(src);
280 return 0;
282 EXPORT_SYMBOL_GPL(fblock_migrate);
285 * fb1 on top of fb2 in the stack
287 int __fblock_bind(struct fblock *fb1, struct fblock *fb2)
289 int ret;
290 struct fblock_bind_msg msg;
291 /* Hack: we let the fb think that this belongs to his own chain to
292 * get the reference back to itself. */
293 struct fblock_notifier fbn;
295 memset(&fbn, 0, sizeof(fbn));
296 memset(&msg, 0, sizeof(msg));
298 get_fblock(fb1);
299 get_fblock(fb2);
301 msg.dir = TYPE_EGRESS;
302 msg.idp = fb2->idp;
303 fbn.self = fb1;
304 ret = fb1->ops->event_rx(&fbn.nb, FBLOCK_BIND_IDP, &msg);
305 if (ret != NOTIFY_OK) {
306 put_fblock(fb1);
307 put_fblock(fb2);
308 return -EBUSY;
311 msg.dir = TYPE_INGRESS;
312 msg.idp = fb1->idp;
313 fbn.self = fb2;
314 ret = fb2->ops->event_rx(&fbn.nb, FBLOCK_BIND_IDP, &msg);
315 if (ret != NOTIFY_OK) {
316 /* Release previous binding */
317 msg.dir = TYPE_EGRESS;
318 msg.idp = fb2->idp;
319 fbn.self = fb1;
320 ret = fb1->ops->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
321 if (ret != NOTIFY_OK)
322 panic("Cannot release previously bound fblock!\n");
323 put_fblock(fb1);
324 put_fblock(fb2);
325 return -EBUSY;
328 ret = subscribe_to_remote_fblock(fb1, fb2);
329 if (ret) {
330 __fblock_unbind(fb1, fb2);
331 return -ENOMEM;
334 ret = subscribe_to_remote_fblock(fb2, fb1);
335 if (ret) {
336 __fblock_unbind(fb1, fb2);
337 return -ENOMEM;
340 /* We don't give refcount back! */
341 return 0;
343 EXPORT_SYMBOL_GPL(__fblock_bind);
345 int fblock_bind(struct fblock *fb1, struct fblock *fb2)
347 int ret;
348 rcu_read_lock();
349 ret = __fblock_bind(fb1, fb2);
350 rcu_read_unlock();
351 return ret;
353 EXPORT_SYMBOL_GPL(fblock_bind);
356 * fb1 on top of fb2 in the stack
358 int __fblock_unbind(struct fblock *fb1, struct fblock *fb2)
360 int ret;
361 struct fblock_bind_msg msg;
362 /* Hack: we let the fb think that this belongs to his own chain to
363 * get the reference back to itself. */
364 struct fblock_notifier fbn;
366 /* We still have refcnt, we drop it on exit! */
368 memset(&fbn, 0, sizeof(fbn));
369 memset(&msg, 0, sizeof(msg));
371 msg.dir = TYPE_EGRESS;
372 msg.idp = fb2->idp;
373 fbn.self = fb1;
374 ret = fb1->ops->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
375 if (ret != NOTIFY_OK) {
376 /* We are not bound to fb2 */
377 return -EBUSY;
380 msg.dir = TYPE_INGRESS;
381 msg.idp = fb1->idp;
382 fbn.self = fb2;
383 ret = fb2->ops->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
384 if (ret != NOTIFY_OK) {
385 /* We are not bound to fb1, but fb1 was bound to us, so only
386 * release fb1 */
387 put_fblock(fb1);
388 return -EBUSY;
391 unsubscribe_from_remote_fblock(fb1, fb2);
392 unsubscribe_from_remote_fblock(fb2, fb1);
394 put_fblock(fb2);
395 put_fblock(fb1);
397 return 0;
399 EXPORT_SYMBOL_GPL(__fblock_unbind);
401 int fblock_unbind(struct fblock *fb1, struct fblock *fb2)
403 int ret;
404 rcu_read_lock();
405 ret = __fblock_unbind(fb1, fb2);
406 rcu_read_unlock();
407 return ret;
409 EXPORT_SYMBOL_GPL(fblock_unbind);
412 * register_fblock is called when the idp is preknown to the
413 * caller and has already been registered previously. The previous
414 * registration has then called unregister_fblock to remove the
415 * fblock but to keep the namespace and idp number.
417 int register_fblock(struct fblock *p, idp_t idp)
419 struct fblock *p0;
420 unsigned long flags;
422 spin_lock_irqsave(&fblmap_head_lock, flags);
423 p->idp = idp;
424 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
425 if (!p0)
426 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p);
427 else {
428 p->next = p0->next;
429 rcu_assign_pointer(p0->next, p);
431 spin_unlock_irqrestore(&fblmap_head_lock, flags);
432 return 0;
434 EXPORT_SYMBOL_GPL(register_fblock);
437 * register_fblock_namespace is called when a new functional block
438 * instance is registered to the system. Then, its name will be
439 * registered into the namespace and it receives a new idp number.
441 int register_fblock_namespace(struct fblock *p)
443 struct fblock *p0;
444 unsigned long flags;
446 spin_lock_irqsave(&fblmap_head_lock, flags);
447 p->idp = provide_new_fblock_idp();
448 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
449 if (!p0)
450 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p);
451 else {
452 p->next = p0->next;
453 rcu_assign_pointer(p0->next, p);
455 spin_unlock_irqrestore(&fblmap_head_lock, flags);
456 return register_to_fblock_namespace(p->name, p->idp);
458 EXPORT_SYMBOL_GPL(register_fblock_namespace);
460 static void free_fblock_rcu(struct rcu_head *rp)
462 struct fblock *p = container_of(rp, struct fblock, rcu);
463 put_fblock(p);
467 * unregister_fblock releases the functional block _only_ from the idp to
468 * fblock translation table, but not from the namespace. The idp can then
469 * later be reused, e.g. by another fblock.
471 int unregister_fblock(struct fblock *p)
473 int ret = -ENOENT;
474 struct fblock *p0;
475 unsigned long flags;
477 spin_lock_irqsave(&fblmap_head_lock, flags);
478 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
479 if (p0 == p)
480 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p->next);
481 else if (p0) {
482 struct fblock *p1;
483 while ((p1 = rcu_dereference_raw(p0->next))) {
484 if (p1 == p) {
485 rcu_assign_pointer(p0->next, p1->next);
486 ret = 0;
487 break;
489 p0 = p1;
492 spin_unlock_irqrestore(&fblmap_head_lock, flags);
493 call_rcu(&p->rcu, free_fblock_rcu);
494 return ret;
496 EXPORT_SYMBOL_GPL(unregister_fblock);
499 * Removes the functional block from the system along with its namespace
500 * mapping.
502 static void __unregister_fblock_namespace(struct fblock *p, int rcu)
504 struct fblock *p0;
505 unsigned long flags;
507 spin_lock_irqsave(&fblmap_head_lock, flags);
508 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
509 if (p0 == p)
510 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p->next);
511 else if (p0) {
512 struct fblock *p1;
513 while ((p1 = rcu_dereference_raw(p0->next))) {
514 if (p1 == p) {
515 rcu_assign_pointer(p0->next, p->next);
516 break;
518 p0 = p1;
521 spin_unlock_irqrestore(&fblmap_head_lock, flags);
522 unregister_from_fblock_namespace(p->name);
523 if (rcu)
524 call_rcu(&p->rcu, free_fblock_rcu);
527 void unregister_fblock_namespace(struct fblock *p)
529 __unregister_fblock_namespace(p, 1);
531 EXPORT_SYMBOL_GPL(unregister_fblock_namespace);
533 void unregister_fblock_namespace_no_rcu(struct fblock *p)
535 __unregister_fblock_namespace(p, 0);
537 EXPORT_SYMBOL_GPL(unregister_fblock_namespace_no_rcu);
539 /* If state changes on 'remote' fb, we ('us') want to be notified. */
540 int subscribe_to_remote_fblock(struct fblock *us, struct fblock *remote)
542 struct fblock_notifier *fn = kmalloc(sizeof(*fn), GFP_ATOMIC);
543 if (!fn)
544 return -ENOMEM;
545 /* hold ref */
546 get_fblock(us);
547 get_fblock(remote);
548 write_lock(&us->lock);
549 fn->self = us;
550 fn->remote = remote;
551 init_fblock_subscriber(us, &fn->nb);
552 fn->next = rcu_dereference_raw(us->notifiers);
553 rcu_assign_pointer(us->notifiers, fn);
554 write_unlock(&us->lock);
555 return fblock_register_foreign_subscriber(remote,
556 &rcu_dereference_raw(us->notifiers)->nb);
558 EXPORT_SYMBOL_GPL(subscribe_to_remote_fblock);
560 void unsubscribe_from_remote_fblock(struct fblock *us, struct fblock *remote)
562 int found = 0;
563 struct fblock_notifier *fn;
565 if (unlikely(!rcu_dereference_raw(us->notifiers)))
566 return;
567 write_lock(&us->lock);
568 fn = rcu_dereference_raw(us->notifiers);
569 if (fn->remote == remote)
570 rcu_assign_pointer(us->notifiers, us->notifiers->next);
571 else {
572 struct fblock_notifier *f1;
573 while ((f1 = fn->next)) {
574 if (f1->remote == remote) {
575 found = 1;
576 fn->next = f1->next;
577 fn = f1; /* free f1 */
578 break;
579 } else
580 fn = f1;
583 write_unlock(&us->lock);
584 if (found) {
585 fblock_unregister_foreign_subscriber(remote, &fn->nb);
586 kfree(fn);
588 /* drop ref */
589 put_fblock(us);
590 put_fblock(remote);
592 EXPORT_SYMBOL_GPL(unsubscribe_from_remote_fblock);
594 static void ctor_fblock(void *obj)
596 struct fblock *p = obj;
597 atomic_set(&p->refcnt, 1);
598 rwlock_init(&p->lock);
599 p->idp = IDP_UNKNOWN;
600 p->next = NULL;
601 p->private_data = NULL;
602 p->ops = NULL;
603 p->notifiers = NULL;
604 p->others = NULL;
607 struct fblock *alloc_fblock(gfp_t flags)
609 __module_get(THIS_MODULE);
610 return kmem_cache_alloc(fblock_cache, flags);
612 EXPORT_SYMBOL_GPL(alloc_fblock);
614 int init_fblock(struct fblock *fb, char *name, void *priv,
615 struct fblock_ops *ops)
617 write_lock(&fb->lock);
618 strlcpy(fb->name, name, sizeof(fb->name));
619 rcu_assign_pointer(fb->private_data, priv);
620 fb->ops = ops;
621 fb->others = kmalloc(sizeof(*(fb->others)), GFP_ATOMIC);
622 if (!fb->others)
623 return -ENOMEM;
624 ATOMIC_INIT_NOTIFIER_HEAD(&fb->others->subscribers);
625 write_unlock(&fb->lock);
626 return 0;
628 EXPORT_SYMBOL_GPL(init_fblock);
630 void kfree_fblock(struct fblock *p)
632 kmem_cache_free(fblock_cache, p);
633 module_put(THIS_MODULE);
635 EXPORT_SYMBOL_GPL(kfree_fblock);
637 void cleanup_fblock(struct fblock *fb)
639 notify_fblock_subscribers(fb, FBLOCK_DOWN, &fb->idp);
640 fb->factory->dtor(fb);
641 kfree(rcu_dereference_raw(fb->others));
643 EXPORT_SYMBOL_GPL(cleanup_fblock);
645 void cleanup_fblock_ctor(struct fblock *fb)
647 kfree(rcu_dereference_raw(fb->others));
649 EXPORT_SYMBOL_GPL(cleanup_fblock_ctor);
651 static int procfs_fblocks(char *page, char **start, off_t offset,
652 int count, int *eof, void *data)
654 int i;
655 off_t len = 0;
656 struct fblock *fb;
658 len += sprintf(page + len, "name type addr idp refcnt\n");
659 rcu_read_lock();
660 for (i = 0; i < HASHTSIZ; ++i) {
661 fb = rcu_dereference_raw(fblmap_head[i]);
662 while (fb) {
663 len += sprintf(page + len, "%s %s %p %u %d\n",
664 fb->name, fb->factory->type,
665 fb, fb->idp, atomic_read(&fb->refcnt));
666 fb = rcu_dereference_raw(fb->next);
669 rcu_read_unlock();
671 /* FIXME: fits in page? */
672 *eof = 1;
673 return len;
676 int init_fblock_tables(void)
678 int ret = 0;
680 get_critbit_cache();
681 critbit_init_tree(&idpmap);
683 fblmap_head_lock = __SPIN_LOCK_UNLOCKED(fblmap_head_lock);
684 fblmap_head = kzalloc(sizeof(*fblmap_head) * HASHTSIZ, GFP_KERNEL);
685 if (!fblmap_head)
686 goto err;
687 fblock_cache = kmem_cache_create("fblock", sizeof(struct fblock),
688 0, SLAB_HWCACHE_ALIGN, ctor_fblock);
689 if (!fblock_cache)
690 goto err2;
691 atomic64_set(&idp_counter, 0);
692 fblocks_proc = create_proc_read_entry("fblocks", 0400, lana_proc_dir,
693 procfs_fblocks, NULL);
694 if (!fblocks_proc)
695 goto err3;
696 return 0;
697 err3:
698 kmem_cache_destroy(fblock_cache);
699 err2:
700 kfree(fblmap_head);
701 err:
702 put_critbit_cache();
703 return ret;
705 EXPORT_SYMBOL_GPL(init_fblock_tables);
707 void cleanup_fblock_tables(void)
709 remove_proc_entry("fblocks", lana_proc_dir);
710 put_critbit_cache();
711 kfree(fblmap_head);
712 synchronize_rcu();
713 kmem_cache_destroy(fblock_cache);
715 EXPORT_SYMBOL_GPL(cleanup_fblock_tables);