removed likely
[ana-net.git] / src / xt_fblock.c
blob521f35af3253f33855310a6aa4c7e510c73e9724
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;
52 if (critbit_contains(&idpmap, name))
53 return -EEXIST;
54 elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
55 if (!elem)
56 return -ENOMEM;
57 strlcpy(elem->name, name, sizeof(elem->name));
58 elem->idp = val;
59 return critbit_insert(&idpmap, elem->name);
62 static void fblock_namespace_do_free_rcu(struct rcu_head *rp)
64 struct idp_elem *p = container_of(rp, struct idp_elem, rcu);
65 kfree(p);
68 static int unregister_from_fblock_namespace(char *name)
70 int ret;
71 struct idp_elem *elem;
72 elem = struct_of(critbit_get(&idpmap, name), struct idp_elem);
73 if (!elem)
74 return -ENOENT;
75 ret = critbit_delete(&idpmap, elem->name);
76 if (ret)
77 return ret;
78 call_rcu(&elem->rcu, fblock_namespace_do_free_rcu);
79 return 0;
82 /* Called within RCU read lock! */
83 idp_t __get_fblock_namespace_mapping(char *name)
85 struct idp_elem *elem = struct_of(__critbit_get(&idpmap, name),
86 struct idp_elem);
87 if (unlikely(!elem))
88 return IDP_UNKNOWN;
89 smp_rmb();
90 return elem->idp;
92 EXPORT_SYMBOL_GPL(__get_fblock_namespace_mapping);
94 idp_t get_fblock_namespace_mapping(char *name)
96 idp_t ret;
97 rcu_read_lock();
98 ret = __get_fblock_namespace_mapping(name);
99 rcu_read_unlock();
100 return ret;
102 EXPORT_SYMBOL_GPL(get_fblock_namespace_mapping);
104 /* Called within RCU read lock! */
105 int __change_fblock_namespace_mapping(char *name, idp_t new)
107 struct idp_elem *elem = struct_of(__critbit_get(&idpmap, name),
108 struct idp_elem);
109 if (unlikely(!elem))
110 return -ENOENT;
111 elem->idp = new;
112 smp_wmb();
113 return 0;
115 EXPORT_SYMBOL_GPL(__change_fblock_namespace_mapping);
117 int change_fblock_namespace_mapping(char *name, idp_t new)
119 int ret;
120 rcu_read_lock();
121 ret = __change_fblock_namespace_mapping(name, new);
122 rcu_read_unlock();
123 return ret;
125 EXPORT_SYMBOL_GPL(change_fblock_namespace_mapping);
127 /* Caller needs to do a put_fblock() after his work is done! */
128 /* Called within RCU read lock! */
129 struct fblock *__search_fblock(idp_t idp)
131 struct fblock *p0;
132 p0 = rcu_dereference_raw(fblmap_head[hash_idp(idp)]);
133 while (p0) {
134 if (p0->idp == idp) {
135 get_fblock(p0);
136 return p0;
138 p0 = rcu_dereference_raw(p0->next);
140 return NULL;
142 EXPORT_SYMBOL_GPL(__search_fblock);
144 struct fblock *search_fblock(idp_t idp)
146 struct fblock *ret;
147 if (unlikely(idp == IDP_UNKNOWN))
148 return NULL;
149 rcu_read_lock();
150 ret = __search_fblock(idp);
151 rcu_read_unlock();
152 return ret;
154 EXPORT_SYMBOL_GPL(search_fblock);
156 /* Note: user needs to do a put_fblock */
157 struct fblock *__search_fblock_n(char *name)
159 idp_t id;
160 struct fblock *fb;
161 id = get_fblock_namespace_mapping(name);
162 if (unlikely(id == IDP_UNKNOWN))
163 return NULL;
164 fb = search_fblock(id);
165 if (!fb)
166 return NULL;
167 return fb;
169 EXPORT_SYMBOL_GPL(__search_fblock_n);
171 struct fblock *search_fblock_n(char *name)
173 struct fblock *ret;
174 if (unlikely(!name))
175 return NULL;
176 rcu_read_lock();
177 ret = __search_fblock_n(name);
178 rcu_read_unlock();
179 return ret;
181 EXPORT_SYMBOL_GPL(search_fblock_n);
183 /* opt_string must be of type "key=val" and 0-terminated */
184 int __fblock_set_option(struct fblock *fb, char *opt_string)
186 int ret = 0;
187 char *val = opt_string;
188 struct fblock_opt_msg msg;
189 /* Hack: we let the fb think that this belongs to his own chain to
190 * get the reference back to itself. */
191 struct fblock_notifier fbn;
193 memset(&fbn, 0, sizeof(fbn));
194 memset(&msg, 0, sizeof(msg));
196 msg.key = opt_string;
197 while (*val != '=' && *val != '\0')
198 val++;
199 if (*val == '\0')
200 return -EINVAL;
201 val++;
202 *(val - 1) = '\0';
203 msg.val = val;
204 fbn.self = fb;
206 get_fblock(fb);
207 ret = fb->ops->event_rx(&fbn.nb, FBLOCK_SET_OPT, &msg);
208 put_fblock(fb);
210 return ret;
212 EXPORT_SYMBOL_GPL(__fblock_set_option);
214 int fblock_set_option(struct fblock *fb, char *opt_string)
216 int ret;
217 if (unlikely(!opt_string || !fb))
218 return -EINVAL;
219 rcu_read_lock();
220 ret = __fblock_set_option(fb, opt_string);
221 rcu_read_unlock();
222 return ret;
224 EXPORT_SYMBOL_GPL(fblock_set_option);
226 /* Must already hold write_lock */
227 static void fblock_update_selfref(struct fblock_notifier *head,
228 struct fblock *self)
230 while (rcu_dereference_raw(head) != NULL) {
231 rcu_assign_pointer(head->self, self);
232 rcu_assign_pointer(head, head->next);
237 * Migrate src to dst, both are of same type, working data is
238 * transferred to dst and droped from src. src gets dsts old data,
239 * so that on free, we do not need to explicitly ignore srcs
240 * private data and dsts remaining data.
242 void fblock_migrate_p(struct fblock *dst, struct fblock *src)
244 void *priv_old;
246 get_fblock(dst);
247 get_fblock(src);
249 rcu_assign_pointer(priv_old, dst->private_data);
250 rcu_assign_pointer(dst->private_data, src->private_data);
251 rcu_assign_pointer(src->private_data, priv_old);
253 put_fblock(dst);
254 put_fblock(src);
256 EXPORT_SYMBOL_GPL(fblock_migrate_p);
258 void fblock_migrate_r(struct fblock *dst, struct fblock *src)
260 int ref_old;
261 struct fblock_notifier *not_old;
262 struct fblock_subscrib *sub_old;
264 get_fblock(dst);
265 get_fblock(src);
267 write_lock(&dst->lock);
268 write_lock(&src->lock);
270 dst->idp = src->idp;
271 strlcpy(dst->name, src->name, sizeof(dst->name));
273 rcu_assign_pointer(not_old, dst->notifiers);
274 rcu_assign_pointer(dst->notifiers, src->notifiers);
275 rcu_assign_pointer(src->notifiers, not_old);
277 fblock_update_selfref(dst->notifiers, dst);
278 fblock_update_selfref(src->notifiers, src);
280 rcu_assign_pointer(sub_old, dst->others);
281 rcu_assign_pointer(dst->others, src->others);
282 rcu_assign_pointer(src->others, sub_old);
284 ref_old = atomic_read(&dst->refcnt);
285 atomic_set(&dst->refcnt, atomic_read(&src->refcnt));
286 atomic_set(&src->refcnt, ref_old);
288 write_unlock(&src->lock);
289 write_unlock(&dst->lock);
291 put_fblock(dst);
292 put_fblock(src);
294 EXPORT_SYMBOL_GPL(fblock_migrate_r);
297 * fb1 on top of fb2 in the stack
299 int __fblock_bind(struct fblock *fb1, struct fblock *fb2)
301 int ret;
302 struct fblock_bind_msg msg;
303 /* Hack: we let the fb think that this belongs to his own chain to
304 * get the reference back to itself. */
305 struct fblock_notifier fbn;
307 memset(&fbn, 0, sizeof(fbn));
308 memset(&msg, 0, sizeof(msg));
310 get_fblock(fb1);
311 get_fblock(fb2);
313 msg.dir = TYPE_EGRESS;
314 msg.idp = fb2->idp;
315 fbn.self = fb1;
316 ret = fb1->ops->event_rx(&fbn.nb, FBLOCK_BIND_IDP, &msg);
317 if (ret != NOTIFY_OK) {
318 put_fblock(fb1);
319 put_fblock(fb2);
320 return -EBUSY;
323 msg.dir = TYPE_INGRESS;
324 msg.idp = fb1->idp;
325 fbn.self = fb2;
326 ret = fb2->ops->event_rx(&fbn.nb, FBLOCK_BIND_IDP, &msg);
327 if (ret != NOTIFY_OK) {
328 /* Release previous binding */
329 msg.dir = TYPE_EGRESS;
330 msg.idp = fb2->idp;
331 fbn.self = fb1;
332 ret = fb1->ops->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
333 if (ret != NOTIFY_OK)
334 panic("Cannot release previously bound fblock!\n");
335 put_fblock(fb1);
336 put_fblock(fb2);
337 return -EBUSY;
340 ret = subscribe_to_remote_fblock(fb1, fb2);
341 if (ret) {
342 __fblock_unbind(fb1, fb2);
343 return -ENOMEM;
346 ret = subscribe_to_remote_fblock(fb2, fb1);
347 if (ret) {
348 __fblock_unbind(fb1, fb2);
349 return -ENOMEM;
352 /* We don't give refcount back! */
353 return 0;
355 EXPORT_SYMBOL_GPL(__fblock_bind);
357 int fblock_bind(struct fblock *fb1, struct fblock *fb2)
359 int ret;
360 rcu_read_lock();
361 ret = __fblock_bind(fb1, fb2);
362 rcu_read_unlock();
363 return ret;
365 EXPORT_SYMBOL_GPL(fblock_bind);
368 * fb1 on top of fb2 in the stack
370 int __fblock_unbind(struct fblock *fb1, struct fblock *fb2)
372 int ret;
373 struct fblock_bind_msg msg;
374 /* Hack: we let the fb think that this belongs to his own chain to
375 * get the reference back to itself. */
376 struct fblock_notifier fbn;
378 /* We still have refcnt, we drop it on exit! */
380 memset(&fbn, 0, sizeof(fbn));
381 memset(&msg, 0, sizeof(msg));
383 msg.dir = TYPE_EGRESS;
384 msg.idp = fb2->idp;
385 fbn.self = fb1;
386 ret = fb1->ops->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
387 if (ret != NOTIFY_OK) {
388 /* We are not bound to fb2 */
389 return -EBUSY;
392 msg.dir = TYPE_INGRESS;
393 msg.idp = fb1->idp;
394 fbn.self = fb2;
395 ret = fb2->ops->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
396 if (ret != NOTIFY_OK) {
397 /* We are not bound to fb1, but fb1 was bound to us, so only
398 * release fb1 */
399 put_fblock(fb1);
400 return -EBUSY;
403 unsubscribe_from_remote_fblock(fb1, fb2);
404 unsubscribe_from_remote_fblock(fb2, fb1);
406 put_fblock(fb2);
407 put_fblock(fb1);
409 return 0;
411 EXPORT_SYMBOL_GPL(__fblock_unbind);
413 int fblock_unbind(struct fblock *fb1, struct fblock *fb2)
415 int ret;
416 rcu_read_lock();
417 ret = __fblock_unbind(fb1, fb2);
418 rcu_read_unlock();
419 return ret;
421 EXPORT_SYMBOL_GPL(fblock_unbind);
424 * register_fblock is called when the idp is preknown to the
425 * caller and has already been registered previously. The previous
426 * registration has then called unregister_fblock to remove the
427 * fblock but to keep the namespace and idp number.
429 int register_fblock(struct fblock *p, idp_t idp)
431 struct fblock *p0;
432 unsigned long flags;
434 spin_lock_irqsave(&fblmap_head_lock, flags);
435 p->idp = idp;
436 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
437 if (!p0)
438 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p);
439 else {
440 p->next = p0->next;
441 rcu_assign_pointer(p0->next, p);
443 spin_unlock_irqrestore(&fblmap_head_lock, flags);
444 return 0;
446 EXPORT_SYMBOL_GPL(register_fblock);
449 * register_fblock_namespace is called when a new functional block
450 * instance is registered to the system. Then, its name will be
451 * registered into the namespace and it receives a new idp number.
453 int register_fblock_namespace(struct fblock *p)
455 struct fblock *p0;
456 unsigned long flags;
458 spin_lock_irqsave(&fblmap_head_lock, flags);
459 p->idp = provide_new_fblock_idp();
460 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
461 if (!p0)
462 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p);
463 else {
464 p->next = p0->next;
465 rcu_assign_pointer(p0->next, p);
467 spin_unlock_irqrestore(&fblmap_head_lock, flags);
468 return register_to_fblock_namespace(p->name, p->idp);
470 EXPORT_SYMBOL_GPL(register_fblock_namespace);
472 void free_fblock_rcu(struct rcu_head *rp)
474 struct fblock *p = container_of(rp, struct fblock, rcu);
475 cleanup_fblock(p);
476 kfree_fblock(p);
478 EXPORT_SYMBOL_GPL(free_fblock_rcu);
481 * unregister_fblock releases the functional block _only_ from the idp to
482 * fblock translation table, but not from the namespace. The idp can then
483 * later be reused, e.g. by another fblock.
485 void unregister_fblock(struct fblock *p)
487 struct fblock *p0;
488 unsigned long flags;
490 spin_lock_irqsave(&fblmap_head_lock, flags);
491 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
492 if (p0 == p)
493 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p->next);
494 else if (p0) {
495 struct fblock *p1;
496 while ((p1 = rcu_dereference_raw(p0->next))) {
497 if (p1 == p) {
498 rcu_assign_pointer(p0->next, p1->next);
499 break;
501 p0 = p1;
504 spin_unlock_irqrestore(&fblmap_head_lock, flags);
505 put_fblock(p);
507 EXPORT_SYMBOL_GPL(unregister_fblock);
510 * Removes the functional block from the system along with its namespace
511 * mapping.
513 static void __unregister_fblock_namespace(struct fblock *p, int rcu)
515 struct fblock *p0;
516 unsigned long flags;
518 spin_lock_irqsave(&fblmap_head_lock, flags);
519 p0 = rcu_dereference_raw(fblmap_head[hash_idp(p->idp)]);
520 if (p0 == p)
521 rcu_assign_pointer(fblmap_head[hash_idp(p->idp)], p->next);
522 else if (p0) {
523 struct fblock *p1;
524 while ((p1 = rcu_dereference_raw(p0->next))) {
525 if (p1 == p) {
526 rcu_assign_pointer(p0->next, p->next);
527 break;
529 p0 = p1;
532 spin_unlock_irqrestore(&fblmap_head_lock, flags);
533 unregister_from_fblock_namespace(p->name);
534 if (rcu)
535 put_fblock(p);
538 void unregister_fblock_namespace(struct fblock *p)
540 __unregister_fblock_namespace(p, 1);
542 EXPORT_SYMBOL_GPL(unregister_fblock_namespace);
544 void unregister_fblock_namespace_no_rcu(struct fblock *p)
546 __unregister_fblock_namespace(p, 0);
548 EXPORT_SYMBOL_GPL(unregister_fblock_namespace_no_rcu);
550 /* If state changes on 'remote' fb, we ('us') want to be notified. */
551 int subscribe_to_remote_fblock(struct fblock *us, struct fblock *remote)
553 struct fblock_notifier *fn = kmalloc(sizeof(*fn), GFP_ATOMIC);
554 if (!fn)
555 return -ENOMEM;
556 /* hold ref */
557 get_fblock(us);
558 get_fblock(remote);
560 write_lock(&us->lock);
562 fn->self = us;
563 fn->remote = remote->idp;
564 init_fblock_subscriber(us, &fn->nb);
565 fn->next = rcu_dereference_raw(us->notifiers);
566 rcu_assign_pointer(us->notifiers, fn);
568 write_unlock(&us->lock);
570 return fblock_register_foreign_subscriber(remote,
571 &rcu_dereference_raw(us->notifiers)->nb);
573 EXPORT_SYMBOL_GPL(subscribe_to_remote_fblock);
575 void unsubscribe_from_remote_fblock(struct fblock *us, struct fblock *remote)
577 int found = 0;
578 struct fblock_notifier *fn;
580 if (unlikely(!rcu_dereference_raw(us->notifiers)))
581 return;
582 write_lock(&us->lock);
583 fn = rcu_dereference_raw(us->notifiers);
584 if (fn->remote == remote->idp)
585 rcu_assign_pointer(us->notifiers, us->notifiers->next);
586 else {
587 struct fblock_notifier *f1;
588 while ((f1 = fn->next)) {
589 if (f1->remote == remote->idp) {
590 found = 1;
591 fn->next = f1->next;
592 fn = f1; /* free f1 */
593 break;
594 } else
595 fn = f1;
598 write_unlock(&us->lock);
599 if (found) {
600 fblock_unregister_foreign_subscriber(remote, &fn->nb);
601 kfree(fn);
604 /* drop ref */
605 put_fblock(us);
606 put_fblock(remote);
608 EXPORT_SYMBOL_GPL(unsubscribe_from_remote_fblock);
610 static void ctor_fblock(void *obj)
612 struct fblock *p = obj;
613 memset(p, 0, sizeof(*p));
614 rwlock_init(&p->lock);
615 p->idp = IDP_UNKNOWN;
618 struct fblock *alloc_fblock(gfp_t flags)
620 struct fblock *fb;
621 #ifndef __USE_KMALLOC
622 fb = kmem_cache_alloc(fblock_cache, flags);
623 if (likely(fb))
624 __module_get(THIS_MODULE);
625 #else
626 fb = kmalloc(sizeof(*fb), flags);
627 if (fb) {
628 ctor_fblock(fb);
629 __module_get(THIS_MODULE);
631 #endif
632 return fb;
634 EXPORT_SYMBOL_GPL(alloc_fblock);
636 int init_fblock(struct fblock *fb, char *name, void __percpu *priv,
637 struct fblock_ops *ops)
639 write_lock(&fb->lock);
640 strlcpy(fb->name, name, sizeof(fb->name));
641 rcu_assign_pointer(fb->private_data, priv);
642 fb->ops = ops;
643 fb->others = kmalloc(sizeof(*(fb->others)), GFP_ATOMIC);
644 if (!fb->others)
645 return -ENOMEM;
646 ATOMIC_INIT_NOTIFIER_HEAD(&fb->others->subscribers);
647 write_unlock(&fb->lock);
648 atomic_set(&fb->refcnt, 1);
649 return 0;
651 EXPORT_SYMBOL_GPL(init_fblock);
653 void kfree_fblock(struct fblock *p)
655 #ifndef __USE_KMALLOC
656 kmem_cache_free(fblock_cache, p);
657 #else
658 kfree(p);
659 #endif
660 module_put(THIS_MODULE);
662 EXPORT_SYMBOL_GPL(kfree_fblock);
664 void cleanup_fblock(struct fblock *fb)
666 notify_fblock_subscribers(fb, FBLOCK_DOWN, &fb->idp);
667 fb->factory->dtor(fb);
668 kfree(rcu_dereference_raw(fb->others));
670 EXPORT_SYMBOL_GPL(cleanup_fblock);
672 void cleanup_fblock_ctor(struct fblock *fb)
674 kfree(rcu_dereference_raw(fb->others));
676 EXPORT_SYMBOL_GPL(cleanup_fblock_ctor);
678 static int procfs_fblocks(char *page, char **start, off_t offset,
679 int count, int *eof, void *data)
681 int i, has_sub;
682 off_t len = 0;
683 struct fblock *fb;
684 struct fblock_notifier *fn;
686 len += sprintf(page + len, "name type addr idp refcnt next subscr\n");
687 rcu_read_lock();
688 for (i = 0; i < HASHTSIZ; ++i) {
689 fb = rcu_dereference_raw(fblmap_head[i]);
690 while (fb) {
691 has_sub = 0;
692 len += sprintf(page + len, "%s %s %p %u %d %p [",
693 fb->name, fb->factory->type,
694 fb, fb->idp,
695 atomic_read(&fb->refcnt),
696 rcu_dereference_raw(fb->next));
697 fn = rcu_dereference_raw(fb->notifiers);
698 while (fn) {
699 len += sprintf(page + len, "%u ", fn->remote);
700 rcu_assign_pointer(fn, fn->next);
701 has_sub = 1;
703 len += sprintf(page + len - has_sub, "]\n");
704 fb = rcu_dereference_raw(fb->next);
707 rcu_read_unlock();
709 /* FIXME: fits in page? */
710 *eof = 1;
711 return len;
714 int init_fblock_tables(void)
716 int ret = 0;
718 get_critbit_cache();
719 critbit_init_tree(&idpmap);
721 fblmap_head_lock = __SPIN_LOCK_UNLOCKED(fblmap_head_lock);
722 fblmap_head = kzalloc(sizeof(*fblmap_head) * HASHTSIZ, GFP_KERNEL);
723 if (!fblmap_head)
724 goto err;
725 fblock_cache = kmem_cache_create("fblock", sizeof(struct fblock),
726 0, SLAB_HWCACHE_ALIGN |
727 SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT,
728 ctor_fblock);
729 if (!fblock_cache)
730 goto err2;
731 atomic64_set(&idp_counter, 0);
732 fblocks_proc = create_proc_read_entry("fblocks", 0400, lana_proc_dir,
733 procfs_fblocks, NULL);
734 if (!fblocks_proc)
735 goto err3;
736 return 0;
737 err3:
738 kmem_cache_destroy(fblock_cache);
739 err2:
740 kfree(fblmap_head);
741 err:
742 put_critbit_cache();
743 return ret;
745 EXPORT_SYMBOL_GPL(init_fblock_tables);
747 void cleanup_fblock_tables(void)
749 remove_proc_entry("fblocks", lana_proc_dir);
750 put_critbit_cache();
751 kfree(fblmap_head);
752 rcu_barrier();
753 kmem_cache_destroy(fblock_cache);
755 EXPORT_SYMBOL_GPL(cleanup_fblock_tables);