inlining of __search_fblock
[ana-net.git] / src / xt_fblock.c
blob5cd98a18d9d72a7a3b05ed5096f4f3db25a3e101
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>
21 #include <linux/radix-tree.h>
23 #include "xt_fblock.h"
24 #include "xt_idp.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 RADIX_TREE(fblmap, GFP_ATOMIC);
35 static atomic64_t idp_counter;
36 static struct kmem_cache *fblock_cache = NULL;
38 extern struct proc_dir_entry *lana_proc_dir;
39 static struct proc_dir_entry *fblocks_proc;
41 static inline idp_t provide_new_fblock_idp(void)
43 return (idp_t) atomic64_inc_return(&idp_counter);
46 static int register_to_fblock_namespace(char *name, idp_t val)
48 struct idp_elem *elem;
49 if (critbit_contains(&idpmap, name))
50 return -EEXIST;
51 elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
52 if (!elem)
53 return -ENOMEM;
54 strlcpy(elem->name, name, sizeof(elem->name));
55 elem->idp = val;
56 return critbit_insert(&idpmap, elem->name);
59 static void fblock_namespace_do_free_rcu(struct rcu_head *rp)
61 struct idp_elem *p = container_of(rp, struct idp_elem, rcu);
62 kfree(p);
65 static int unregister_from_fblock_namespace(char *name)
67 int ret;
68 struct idp_elem *elem;
69 elem = struct_of(critbit_get(&idpmap, name), struct idp_elem);
70 if (!elem)
71 return -ENOENT;
72 ret = critbit_delete(&idpmap, elem->name);
73 if (ret)
74 return ret;
75 call_rcu(&elem->rcu, fblock_namespace_do_free_rcu);
76 return 0;
79 /* Called within RCU read lock! */
80 idp_t __get_fblock_namespace_mapping(char *name)
82 struct idp_elem *elem = struct_of(__critbit_get(&idpmap, name),
83 struct idp_elem);
84 if (unlikely(!elem))
85 return IDP_UNKNOWN;
86 smp_rmb();
87 return elem->idp;
89 EXPORT_SYMBOL_GPL(__get_fblock_namespace_mapping);
91 idp_t get_fblock_namespace_mapping(char *name)
93 idp_t ret;
94 rcu_read_lock();
95 ret = __get_fblock_namespace_mapping(name);
96 rcu_read_unlock();
97 return ret;
99 EXPORT_SYMBOL_GPL(get_fblock_namespace_mapping);
101 /* Called within RCU read lock! */
102 int __change_fblock_namespace_mapping(char *name, idp_t new)
104 struct idp_elem *elem = struct_of(__critbit_get(&idpmap, name),
105 struct idp_elem);
106 if (unlikely(!elem))
107 return -ENOENT;
108 elem->idp = new;
109 smp_wmb();
110 return 0;
112 EXPORT_SYMBOL_GPL(__change_fblock_namespace_mapping);
114 int change_fblock_namespace_mapping(char *name, idp_t new)
116 int ret;
117 rcu_read_lock();
118 ret = __change_fblock_namespace_mapping(name, new);
119 rcu_read_unlock();
120 return ret;
122 EXPORT_SYMBOL_GPL(change_fblock_namespace_mapping);
124 struct fblock *search_fblock(idp_t idp)
126 struct fblock *ret;
127 if (unlikely(idp == IDP_UNKNOWN))
128 return NULL;
129 rcu_read_lock();
130 ret = __search_fblock(idp);
131 rcu_read_unlock();
132 return ret;
134 EXPORT_SYMBOL_GPL(search_fblock);
136 /* Note: user needs to do a put_fblock */
137 struct fblock *__search_fblock_n(char *name)
139 idp_t id;
140 struct fblock *fb;
141 id = get_fblock_namespace_mapping(name);
142 if (unlikely(id == IDP_UNKNOWN))
143 return NULL;
144 fb = search_fblock(id);
145 if (!fb)
146 return NULL;
147 return fb;
149 EXPORT_SYMBOL_GPL(__search_fblock_n);
151 struct fblock *search_fblock_n(char *name)
153 struct fblock *ret;
154 if (unlikely(!name))
155 return NULL;
156 rcu_read_lock();
157 ret = __search_fblock_n(name);
158 rcu_read_unlock();
159 return ret;
161 EXPORT_SYMBOL_GPL(search_fblock_n);
163 /* opt_string must be of type "key=val" and 0-terminated */
164 int __fblock_set_option(struct fblock *fb, char *opt_string)
166 int ret = 0;
167 char *val = opt_string;
168 struct fblock_opt_msg msg;
169 /* Hack: we let the fb think that this belongs to his own chain to
170 * get the reference back to itself. */
171 struct fblock_notifier fbn;
173 memset(&fbn, 0, sizeof(fbn));
174 memset(&msg, 0, sizeof(msg));
176 msg.key = opt_string;
177 while (*val != '=' && *val != '\0')
178 val++;
179 if (*val == '\0')
180 return -EINVAL;
181 val++;
182 *(val - 1) = '\0';
183 msg.val = val;
184 fbn.self = fb;
186 get_fblock(fb);
187 ret = fb->event_rx(&fbn.nb, FBLOCK_SET_OPT, &msg);
188 put_fblock(fb);
190 return ret;
192 EXPORT_SYMBOL_GPL(__fblock_set_option);
194 int fblock_set_option(struct fblock *fb, char *opt_string)
196 int ret;
197 if (unlikely(!opt_string || !fb))
198 return -EINVAL;
199 rcu_read_lock();
200 ret = __fblock_set_option(fb, opt_string);
201 rcu_read_unlock();
202 return ret;
204 EXPORT_SYMBOL_GPL(fblock_set_option);
206 /* Must already hold write_lock */
207 static void fblock_update_selfref(struct fblock_notifier *head,
208 struct fblock *self)
210 while (rcu_dereference_raw(head) != NULL) {
211 rcu_assign_pointer(head->self, self);
212 rcu_assign_pointer(head, head->next);
217 * Migrate src to dst, both are of same type, working data is
218 * transferred to dst and droped from src. src gets dsts old data,
219 * so that on free, we do not need to explicitly ignore srcs
220 * private data and dsts remaining data.
222 void fblock_migrate_p(struct fblock *dst, struct fblock *src)
224 void *priv_old;
226 get_fblock(dst);
227 get_fblock(src);
229 rcu_assign_pointer(priv_old, dst->private_data);
230 rcu_assign_pointer(dst->private_data, src->private_data);
231 rcu_assign_pointer(src->private_data, priv_old);
233 put_fblock(dst);
234 put_fblock(src);
236 EXPORT_SYMBOL_GPL(fblock_migrate_p);
238 void fblock_migrate_r(struct fblock *dst, struct fblock *src)
240 int ref_old;
241 struct fblock_notifier *not_old;
242 struct fblock_subscrib *sub_old;
244 get_fblock(dst);
245 get_fblock(src);
247 write_lock(&dst->lock);
248 write_lock(&src->lock);
250 dst->idp = src->idp;
251 strlcpy(dst->name, src->name, sizeof(dst->name));
253 rcu_assign_pointer(not_old, dst->notifiers);
254 rcu_assign_pointer(dst->notifiers, src->notifiers);
255 rcu_assign_pointer(src->notifiers, not_old);
257 fblock_update_selfref(dst->notifiers, dst);
258 fblock_update_selfref(src->notifiers, src);
260 rcu_assign_pointer(sub_old, dst->others);
261 rcu_assign_pointer(dst->others, src->others);
262 rcu_assign_pointer(src->others, sub_old);
264 ref_old = atomic_read(&dst->refcnt);
265 atomic_set(&dst->refcnt, atomic_read(&src->refcnt));
266 atomic_set(&src->refcnt, ref_old);
268 write_unlock(&src->lock);
269 write_unlock(&dst->lock);
271 put_fblock(dst);
272 put_fblock(src);
274 EXPORT_SYMBOL_GPL(fblock_migrate_r);
277 * fb1 on top of fb2 in the stack
279 int __fblock_bind(struct fblock *fb1, struct fblock *fb2)
281 int ret;
282 struct fblock_bind_msg msg;
283 /* Hack: we let the fb think that this belongs to his own chain to
284 * get the reference back to itself. */
285 struct fblock_notifier fbn;
287 memset(&fbn, 0, sizeof(fbn));
288 memset(&msg, 0, sizeof(msg));
290 get_fblock(fb1);
291 get_fblock(fb2);
293 msg.dir = TYPE_EGRESS;
294 msg.idp = fb2->idp;
295 fbn.self = fb1;
296 ret = fb1->event_rx(&fbn.nb, FBLOCK_BIND_IDP, &msg);
297 if (ret != NOTIFY_OK) {
298 put_fblock(fb1);
299 put_fblock(fb2);
300 return -EBUSY;
303 msg.dir = TYPE_INGRESS;
304 msg.idp = fb1->idp;
305 fbn.self = fb2;
306 ret = fb2->event_rx(&fbn.nb, FBLOCK_BIND_IDP, &msg);
307 if (ret != NOTIFY_OK) {
308 /* Release previous binding */
309 msg.dir = TYPE_EGRESS;
310 msg.idp = fb2->idp;
311 fbn.self = fb1;
312 ret = fb1->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
313 if (ret != NOTIFY_OK)
314 panic("Cannot release previously bound fblock!\n");
315 put_fblock(fb1);
316 put_fblock(fb2);
317 return -EBUSY;
320 ret = subscribe_to_remote_fblock(fb1, fb2);
321 if (ret) {
322 __fblock_unbind(fb1, fb2);
323 return -ENOMEM;
326 ret = subscribe_to_remote_fblock(fb2, fb1);
327 if (ret) {
328 __fblock_unbind(fb1, fb2);
329 return -ENOMEM;
332 /* We don't give refcount back! */
333 return 0;
335 EXPORT_SYMBOL_GPL(__fblock_bind);
337 int fblock_bind(struct fblock *fb1, struct fblock *fb2)
339 int ret;
340 rcu_read_lock();
341 ret = __fblock_bind(fb1, fb2);
342 rcu_read_unlock();
343 return ret;
345 EXPORT_SYMBOL_GPL(fblock_bind);
348 * fb1 on top of fb2 in the stack
350 int __fblock_unbind(struct fblock *fb1, struct fblock *fb2)
352 int ret;
353 struct fblock_bind_msg msg;
354 /* Hack: we let the fb think that this belongs to his own chain to
355 * get the reference back to itself. */
356 struct fblock_notifier fbn;
358 /* We still have refcnt, we drop it on exit! */
360 memset(&fbn, 0, sizeof(fbn));
361 memset(&msg, 0, sizeof(msg));
363 msg.dir = TYPE_EGRESS;
364 msg.idp = fb2->idp;
365 fbn.self = fb1;
366 ret = fb1->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
367 if (ret != NOTIFY_OK) {
368 /* We are not bound to fb2 */
369 return -EBUSY;
372 msg.dir = TYPE_INGRESS;
373 msg.idp = fb1->idp;
374 fbn.self = fb2;
375 ret = fb2->event_rx(&fbn.nb, FBLOCK_UNBIND_IDP, &msg);
376 if (ret != NOTIFY_OK) {
377 /* We are not bound to fb1, but fb1 was bound to us, so only
378 * release fb1 */
379 put_fblock(fb1);
380 return -EBUSY;
383 unsubscribe_from_remote_fblock(fb1, fb2);
384 unsubscribe_from_remote_fblock(fb2, fb1);
386 put_fblock(fb2);
387 put_fblock(fb1);
389 return 0;
391 EXPORT_SYMBOL_GPL(__fblock_unbind);
393 int fblock_unbind(struct fblock *fb1, struct fblock *fb2)
395 int ret;
396 rcu_read_lock();
397 ret = __fblock_unbind(fb1, fb2);
398 rcu_read_unlock();
399 return ret;
401 EXPORT_SYMBOL_GPL(fblock_unbind);
404 * register_fblock is called when the idp is preknown to the
405 * caller and has already been registered previously. The previous
406 * registration has then called unregister_fblock to remove the
407 * fblock but to keep the namespace and idp number.
409 int register_fblock(struct fblock *p, idp_t idp)
411 p->idp = idp;
412 return radix_tree_insert(&fblmap, idp, p);
414 EXPORT_SYMBOL_GPL(register_fblock);
417 * register_fblock_namespace is called when a new functional block
418 * instance is registered to the system. Then, its name will be
419 * registered into the namespace and it receives a new idp number.
421 int register_fblock_namespace(struct fblock *p)
423 int ret;
424 p->idp = provide_new_fblock_idp();
425 ret = radix_tree_insert(&fblmap, p->idp, p);
426 if (ret < 0)
427 return ret;
428 return register_to_fblock_namespace(p->name, p->idp);
430 EXPORT_SYMBOL_GPL(register_fblock_namespace);
432 void free_fblock_rcu(struct rcu_head *rp)
434 struct fblock *p = container_of(rp, struct fblock, rcu);
435 cleanup_fblock(p);
436 kfree_fblock(p);
438 EXPORT_SYMBOL_GPL(free_fblock_rcu);
441 * unregister_fblock releases the functional block _only_ from the idp to
442 * fblock translation table, but not from the namespace. The idp can then
443 * later be reused, e.g. by another fblock.
445 void unregister_fblock(struct fblock *p)
447 radix_tree_delete(&fblmap, p->idp);
448 put_fblock(p);
450 EXPORT_SYMBOL_GPL(unregister_fblock);
453 * Removes the functional block from the system along with its namespace
454 * mapping.
456 static void __unregister_fblock_namespace(struct fblock *p, int rcu)
458 radix_tree_delete(&fblmap, p->idp);
459 unregister_from_fblock_namespace(p->name);
460 if (rcu)
461 put_fblock(p);
464 void unregister_fblock_namespace(struct fblock *p)
466 __unregister_fblock_namespace(p, 1);
468 EXPORT_SYMBOL_GPL(unregister_fblock_namespace);
470 void unregister_fblock_namespace_no_rcu(struct fblock *p)
472 __unregister_fblock_namespace(p, 0);
474 EXPORT_SYMBOL_GPL(unregister_fblock_namespace_no_rcu);
476 /* If state changes on 'remote' fb, we ('us') want to be notified. */
477 int subscribe_to_remote_fblock(struct fblock *us, struct fblock *remote)
479 struct fblock_notifier *fn = kmalloc(sizeof(*fn), GFP_ATOMIC);
480 if (!fn)
481 return -ENOMEM;
482 /* hold ref */
483 get_fblock(us);
484 get_fblock(remote);
486 write_lock(&us->lock);
488 fn->self = us;
489 fn->remote = remote->idp;
490 init_fblock_subscriber(us, &fn->nb);
491 fn->next = rcu_dereference_raw(us->notifiers);
492 rcu_assign_pointer(us->notifiers, fn);
494 write_unlock(&us->lock);
496 return fblock_register_foreign_subscriber(remote,
497 &rcu_dereference_raw(us->notifiers)->nb);
499 EXPORT_SYMBOL_GPL(subscribe_to_remote_fblock);
501 void unsubscribe_from_remote_fblock(struct fblock *us, struct fblock *remote)
503 int found = 0;
504 struct fblock_notifier *fn;
506 if (unlikely(!rcu_dereference_raw(us->notifiers)))
507 return;
508 write_lock(&us->lock);
509 fn = rcu_dereference_raw(us->notifiers);
510 if (fn->remote == remote->idp)
511 rcu_assign_pointer(us->notifiers, us->notifiers->next);
512 else {
513 struct fblock_notifier *f1;
514 while ((f1 = fn->next)) {
515 if (f1->remote == remote->idp) {
516 found = 1;
517 fn->next = f1->next;
518 fn = f1; /* free f1 */
519 break;
520 } else
521 fn = f1;
524 write_unlock(&us->lock);
525 if (found) {
526 fblock_unregister_foreign_subscriber(remote, &fn->nb);
527 kfree(fn);
530 /* drop ref */
531 put_fblock(us);
532 put_fblock(remote);
534 EXPORT_SYMBOL_GPL(unsubscribe_from_remote_fblock);
536 static void ctor_fblock(void *obj)
538 struct fblock *p = obj;
539 memset(p, 0, sizeof(*p));
540 rwlock_init(&p->lock);
541 p->idp = IDP_UNKNOWN;
544 struct fblock *alloc_fblock(gfp_t flags)
546 struct fblock *fb;
547 #ifndef __USE_KMALLOC
548 fb = kmem_cache_alloc(fblock_cache, flags);
549 if (likely(fb))
550 __module_get(THIS_MODULE);
551 #else
552 fb = kmalloc(sizeof(*fb), flags);
553 if (fb) {
554 ctor_fblock(fb);
555 __module_get(THIS_MODULE);
557 #endif
558 return fb;
560 EXPORT_SYMBOL_GPL(alloc_fblock);
562 int init_fblock(struct fblock *fb, char *name, void __percpu *priv)
564 write_lock(&fb->lock);
565 strlcpy(fb->name, name, sizeof(fb->name));
566 rcu_assign_pointer(fb->private_data, priv);
567 fb->others = kmalloc(sizeof(*(fb->others)), GFP_ATOMIC);
568 if (!fb->others)
569 return -ENOMEM;
570 ATOMIC_INIT_NOTIFIER_HEAD(&fb->others->subscribers);
571 write_unlock(&fb->lock);
572 atomic_set(&fb->refcnt, 1);
573 return 0;
575 EXPORT_SYMBOL_GPL(init_fblock);
577 void kfree_fblock(struct fblock *p)
579 #ifndef __USE_KMALLOC
580 kmem_cache_free(fblock_cache, p);
581 #else
582 kfree(p);
583 #endif
584 module_put(THIS_MODULE);
586 EXPORT_SYMBOL_GPL(kfree_fblock);
588 void cleanup_fblock(struct fblock *fb)
590 notify_fblock_subscribers(fb, FBLOCK_DOWN, &fb->idp);
591 fb->factory->dtor(fb);
592 kfree(rcu_dereference_raw(fb->others));
594 EXPORT_SYMBOL_GPL(cleanup_fblock);
596 void cleanup_fblock_ctor(struct fblock *fb)
598 kfree(rcu_dereference_raw(fb->others));
600 EXPORT_SYMBOL_GPL(cleanup_fblock_ctor);
602 static int procfs_fblocks(char *page, char **start, off_t offset,
603 int count, int *eof, void *data)
605 int i, has_sub;
606 off_t len = 0;
607 struct fblock *fb;
608 struct fblock_notifier *fn;
609 long long max = atomic64_read(&idp_counter);
611 len += sprintf(page + len, "name type addr idp refcnt next subscr\n");
612 rcu_read_lock();
613 for (i = 0; i <= max; ++i) {
614 fb = radix_tree_lookup(&fblmap, i);
615 if (!fb)
616 continue;
617 while (fb) {
618 has_sub = 0;
619 len += sprintf(page + len, "%s %s %p %u %d %p [",
620 fb->name, fb->factory->type,
621 fb, fb->idp,
622 atomic_read(&fb->refcnt),
623 rcu_dereference_raw(fb->next));
624 fn = rcu_dereference_raw(fb->notifiers);
625 while (fn) {
626 len += sprintf(page + len, "%u ", fn->remote);
627 rcu_assign_pointer(fn, fn->next);
628 has_sub = 1;
630 len += sprintf(page + len - has_sub, "]\n");
631 fb = rcu_dereference_raw(fb->next);
634 rcu_read_unlock();
636 /* FIXME: fits in page? */
637 *eof = 1;
638 return len;
641 int init_fblock_tables(void)
643 int ret = 0;
645 get_critbit_cache();
646 critbit_init_tree(&idpmap);
647 fblock_cache = kmem_cache_create("fblock", sizeof(struct fblock),
648 0, SLAB_HWCACHE_ALIGN |
649 SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT,
650 ctor_fblock);
651 if (!fblock_cache)
652 goto err;
653 atomic64_set(&idp_counter, 0);
654 fblocks_proc = create_proc_read_entry("fblocks", 0400, lana_proc_dir,
655 procfs_fblocks, NULL);
656 if (!fblocks_proc)
657 goto err2;
658 return 0;
659 err2:
660 kmem_cache_destroy(fblock_cache);
661 err:
662 put_critbit_cache();
663 return ret;
665 EXPORT_SYMBOL_GPL(init_fblock_tables);
667 void cleanup_fblock_tables(void)
669 remove_proc_entry("fblocks", lana_proc_dir);
670 put_critbit_cache();
671 rcu_barrier();
672 kmem_cache_destroy(fblock_cache);
674 EXPORT_SYMBOL_GPL(cleanup_fblock_tables);