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)
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"
25 #include "xt_critbit.h"
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
))
51 elem
= kzalloc(sizeof(*elem
), GFP_ATOMIC
);
54 strlcpy(elem
->name
, name
, sizeof(elem
->name
));
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
);
65 static int unregister_from_fblock_namespace(char *name
)
68 struct idp_elem
*elem
;
69 elem
= struct_of(critbit_get(&idpmap
, name
), struct idp_elem
);
72 ret
= critbit_delete(&idpmap
, elem
->name
);
75 call_rcu(&elem
->rcu
, fblock_namespace_do_free_rcu
);
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
),
89 EXPORT_SYMBOL_GPL(__get_fblock_namespace_mapping
);
91 idp_t
get_fblock_namespace_mapping(char *name
)
95 ret
= __get_fblock_namespace_mapping(name
);
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
),
112 EXPORT_SYMBOL_GPL(__change_fblock_namespace_mapping
);
114 int change_fblock_namespace_mapping(char *name
, idp_t
new)
118 ret
= __change_fblock_namespace_mapping(name
, new);
122 EXPORT_SYMBOL_GPL(change_fblock_namespace_mapping
);
124 struct fblock
*search_fblock(idp_t idp
)
127 if (unlikely(idp
== IDP_UNKNOWN
))
130 ret
= __search_fblock(idp
);
134 EXPORT_SYMBOL_GPL(search_fblock
);
136 /* Note: user needs to do a put_fblock */
137 struct fblock
*search_fblock_n(char *name
)
144 id
= __get_fblock_namespace_mapping(name
);
145 ret
= __search_fblock(id
);
149 EXPORT_SYMBOL_GPL(search_fblock_n
);
151 /* opt_string must be of type "key=val" and 0-terminated */
152 int __fblock_set_option(struct fblock
*fb
, char *opt_string
)
155 char *val
= opt_string
;
156 struct fblock_opt_msg msg
;
157 /* Hack: we let the fb think that this belongs to his own chain to
158 * get the reference back to itself. */
159 struct fblock_notifier fbn
;
161 memset(&fbn
, 0, sizeof(fbn
));
162 memset(&msg
, 0, sizeof(msg
));
164 msg
.key
= opt_string
;
165 while (*val
!= '=' && *val
!= '\0')
175 ret
= fb
->event_rx(&fbn
.nb
, FBLOCK_SET_OPT
, &msg
);
180 EXPORT_SYMBOL_GPL(__fblock_set_option
);
182 int fblock_set_option(struct fblock
*fb
, char *opt_string
)
185 if (unlikely(!opt_string
|| !fb
))
188 ret
= __fblock_set_option(fb
, opt_string
);
192 EXPORT_SYMBOL_GPL(fblock_set_option
);
194 /* Must already hold spin_lock */
195 static void fblock_update_selfref(struct fblock_notifier
*head
,
198 while (rcu_dereference_raw(head
) != NULL
) {
199 rcu_assign_pointer(head
->self
, self
);
200 rcu_assign_pointer(head
, head
->next
);
205 * Migrate src to dst, both are of same type, working data is
206 * transferred to dst and droped from src. src gets dsts old data,
207 * so that on free, we do not need to explicitly ignore srcs
208 * private data and dsts remaining data.
210 void fblock_migrate_p(struct fblock
*dst
, struct fblock
*src
)
217 rcu_assign_pointer(priv_old
, dst
->private_data
);
218 rcu_assign_pointer(dst
->private_data
, src
->private_data
);
219 rcu_assign_pointer(src
->private_data
, priv_old
);
224 EXPORT_SYMBOL_GPL(fblock_migrate_p
);
226 void fblock_migrate_r(struct fblock
*dst
, struct fblock
*src
)
228 struct fblock_notifier
*not_old
;
229 struct fblock_subscrib
*sub_old
;
234 spin_lock(&dst
->lock
);
235 spin_lock(&src
->lock
);
238 strlcpy(dst
->name
, src
->name
, sizeof(dst
->name
));
240 rcu_assign_pointer(not_old
, dst
->notifiers
);
241 rcu_assign_pointer(dst
->notifiers
, src
->notifiers
);
242 rcu_assign_pointer(src
->notifiers
, not_old
);
244 fblock_update_selfref(dst
->notifiers
, dst
);
245 fblock_update_selfref(src
->notifiers
, src
);
247 rcu_assign_pointer(sub_old
, dst
->others
);
248 rcu_assign_pointer(dst
->others
, src
->others
);
249 rcu_assign_pointer(src
->others
, sub_old
);
251 atomic_xchg(&dst
->refcnt
, atomic_xchg(&src
->refcnt
,
252 atomic_read(&dst
->refcnt
)));
254 spin_unlock(&src
->lock
);
255 spin_unlock(&dst
->lock
);
260 EXPORT_SYMBOL_GPL(fblock_migrate_r
);
263 * fb1 on top of fb2 in the stack
265 int __fblock_bind(struct fblock
*fb1
, struct fblock
*fb2
)
268 struct fblock_bind_msg msg
;
269 /* Hack: we let the fb think that this belongs to his own chain to
270 * get the reference back to itself. */
271 struct fblock_notifier fbn
;
273 memset(&fbn
, 0, sizeof(fbn
));
274 memset(&msg
, 0, sizeof(msg
));
279 msg
.dir
= TYPE_EGRESS
;
282 ret
= fb1
->event_rx(&fbn
.nb
, FBLOCK_BIND_IDP
, &msg
);
283 if (ret
!= NOTIFY_OK
) {
289 msg
.dir
= TYPE_INGRESS
;
292 ret
= fb2
->event_rx(&fbn
.nb
, FBLOCK_BIND_IDP
, &msg
);
293 if (ret
!= NOTIFY_OK
) {
294 /* Release previous binding */
295 msg
.dir
= TYPE_EGRESS
;
298 ret
= fb1
->event_rx(&fbn
.nb
, FBLOCK_UNBIND_IDP
, &msg
);
299 if (ret
!= NOTIFY_OK
)
300 panic("Cannot release previously bound fblock!\n");
306 ret
= subscribe_to_remote_fblock(fb1
, fb2
);
308 __fblock_unbind(fb1
, fb2
);
312 ret
= subscribe_to_remote_fblock(fb2
, fb1
);
314 __fblock_unbind(fb1
, fb2
);
318 /* We don't give refcount back! */
321 EXPORT_SYMBOL_GPL(__fblock_bind
);
323 int fblock_bind(struct fblock
*fb1
, struct fblock
*fb2
)
327 ret
= __fblock_bind(fb1
, fb2
);
331 EXPORT_SYMBOL_GPL(fblock_bind
);
334 * fb1 on top of fb2 in the stack
336 int __fblock_unbind(struct fblock
*fb1
, struct fblock
*fb2
)
339 struct fblock_bind_msg msg
;
340 /* Hack: we let the fb think that this belongs to his own chain to
341 * get the reference back to itself. */
342 struct fblock_notifier fbn
;
344 /* We still have refcnt, we drop it on exit! */
346 memset(&fbn
, 0, sizeof(fbn
));
347 memset(&msg
, 0, sizeof(msg
));
349 msg
.dir
= TYPE_EGRESS
;
352 ret
= fb1
->event_rx(&fbn
.nb
, FBLOCK_UNBIND_IDP
, &msg
);
353 if (ret
!= NOTIFY_OK
) {
354 /* We are not bound to fb2 */
358 msg
.dir
= TYPE_INGRESS
;
361 ret
= fb2
->event_rx(&fbn
.nb
, FBLOCK_UNBIND_IDP
, &msg
);
362 if (ret
!= NOTIFY_OK
) {
363 /* We are not bound to fb1, but fb1 was bound to us, so only
369 unsubscribe_from_remote_fblock(fb1
, fb2
);
370 unsubscribe_from_remote_fblock(fb2
, fb1
);
377 EXPORT_SYMBOL_GPL(__fblock_unbind
);
379 int fblock_unbind(struct fblock
*fb1
, struct fblock
*fb2
)
383 ret
= __fblock_unbind(fb1
, fb2
);
387 EXPORT_SYMBOL_GPL(fblock_unbind
);
390 * register_fblock is called when the idp is preknown to the
391 * caller and has already been registered previously. The previous
392 * registration has then called unregister_fblock to remove the
393 * fblock but to keep the namespace and idp number.
395 int register_fblock(struct fblock
*p
, idp_t idp
)
398 return radix_tree_insert(&fblmap
, idp
, p
);
400 EXPORT_SYMBOL_GPL(register_fblock
);
403 * register_fblock_namespace is called when a new functional block
404 * instance is registered to the system. Then, its name will be
405 * registered into the namespace and it receives a new idp number.
407 int register_fblock_namespace(struct fblock
*p
)
410 p
->idp
= provide_new_fblock_idp();
411 ret
= radix_tree_insert(&fblmap
, p
->idp
, p
);
414 return register_to_fblock_namespace(p
->name
, p
->idp
);
416 EXPORT_SYMBOL_GPL(register_fblock_namespace
);
418 void free_fblock_rcu(struct rcu_head
*rp
)
420 struct fblock
*p
= container_of(rp
, struct fblock
, rcu
);
424 EXPORT_SYMBOL_GPL(free_fblock_rcu
);
427 * unregister_fblock releases the functional block _only_ from the idp to
428 * fblock translation table, but not from the namespace. The idp can then
429 * later be reused, e.g. by another fblock.
431 void unregister_fblock(struct fblock
*p
)
433 radix_tree_delete(&fblmap
, p
->idp
);
436 EXPORT_SYMBOL_GPL(unregister_fblock
);
439 * Removes the functional block from the system along with its namespace
442 static void __unregister_fblock_namespace(struct fblock
*p
, int rcu
)
444 radix_tree_delete(&fblmap
, p
->idp
);
445 unregister_from_fblock_namespace(p
->name
);
450 void unregister_fblock_namespace(struct fblock
*p
)
452 __unregister_fblock_namespace(p
, 1);
454 EXPORT_SYMBOL_GPL(unregister_fblock_namespace
);
456 void unregister_fblock_namespace_no_rcu(struct fblock
*p
)
458 __unregister_fblock_namespace(p
, 0);
460 EXPORT_SYMBOL_GPL(unregister_fblock_namespace_no_rcu
);
462 /* If state changes on 'remote' fb, we ('us') want to be notified. */
463 int subscribe_to_remote_fblock(struct fblock
*us
, struct fblock
*remote
)
465 struct fblock_notifier
*fn
= kmalloc(sizeof(*fn
), GFP_ATOMIC
);
472 spin_lock(&us
->lock
);
474 fn
->remote
= remote
->idp
;
475 init_fblock_subscriber(us
, &fn
->nb
);
476 fn
->next
= rcu_dereference_raw(us
->notifiers
);
477 rcu_assign_pointer(us
->notifiers
, fn
);
478 spin_unlock(&us
->lock
);
480 return fblock_register_foreign_subscriber(remote
,
481 &rcu_dereference_raw(us
->notifiers
)->nb
);
483 EXPORT_SYMBOL_GPL(subscribe_to_remote_fblock
);
485 void unsubscribe_from_remote_fblock(struct fblock
*us
, struct fblock
*remote
)
488 struct fblock_notifier
*fn
;
490 if (unlikely(!rcu_dereference_raw(us
->notifiers
)))
492 spin_lock(&us
->lock
);
493 fn
= rcu_dereference_raw(us
->notifiers
);
494 if (fn
->remote
== remote
->idp
)
495 rcu_assign_pointer(us
->notifiers
, us
->notifiers
->next
);
497 struct fblock_notifier
*f1
;
498 while ((f1
= fn
->next
)) {
499 if (f1
->remote
== remote
->idp
) {
502 fn
= f1
; /* free f1 */
508 spin_unlock(&us
->lock
);
510 fblock_unregister_foreign_subscriber(remote
, &fn
->nb
);
518 EXPORT_SYMBOL_GPL(unsubscribe_from_remote_fblock
);
520 static void ctor_fblock(void *obj
)
522 struct fblock
*p
= obj
;
523 memset(p
, 0, sizeof(*p
));
524 spin_lock_init(&p
->lock
);
525 p
->idp
= IDP_UNKNOWN
;
528 struct fblock
*alloc_fblock(gfp_t flags
)
531 #ifndef __USE_KMALLOC
532 fb
= kmem_cache_alloc(fblock_cache
, flags
);
534 __module_get(THIS_MODULE
);
536 fb
= kmalloc(sizeof(*fb
), flags
);
539 __module_get(THIS_MODULE
);
544 EXPORT_SYMBOL_GPL(alloc_fblock
);
546 int init_fblock(struct fblock
*fb
, char *name
, void __percpu
*priv
)
548 spin_lock(&fb
->lock
);
549 strlcpy(fb
->name
, name
, sizeof(fb
->name
));
550 rcu_assign_pointer(fb
->private_data
, priv
);
551 fb
->others
= kmalloc(sizeof(*(fb
->others
)), GFP_ATOMIC
);
554 ATOMIC_INIT_NOTIFIER_HEAD(&fb
->others
->subscribers
);
555 spin_unlock(&fb
->lock
);
556 atomic_set(&fb
->refcnt
, 1);
559 EXPORT_SYMBOL_GPL(init_fblock
);
561 void kfree_fblock(struct fblock
*p
)
563 #ifndef __USE_KMALLOC
564 kmem_cache_free(fblock_cache
, p
);
568 module_put(THIS_MODULE
);
570 EXPORT_SYMBOL_GPL(kfree_fblock
);
572 void cleanup_fblock(struct fblock
*fb
)
574 notify_fblock_subscribers(fb
, FBLOCK_DOWN
, &fb
->idp
);
575 fb
->factory
->dtor(fb
);
576 kfree(rcu_dereference_raw(fb
->others
));
578 EXPORT_SYMBOL_GPL(cleanup_fblock
);
580 void cleanup_fblock_ctor(struct fblock
*fb
)
582 kfree(rcu_dereference_raw(fb
->others
));
584 EXPORT_SYMBOL_GPL(cleanup_fblock_ctor
);
586 static int procfs_fblocks(char *page
, char **start
, off_t offset
,
587 int count
, int *eof
, void *data
)
592 struct fblock_notifier
*fn
;
593 long long max
= atomic64_read(&idp_counter
);
595 len
+= sprintf(page
+ len
, "name type addr idp refcnt next subscr\n");
597 for (i
= 0; i
<= max
; ++i
) {
598 fb
= radix_tree_lookup(&fblmap
, i
);
603 len
+= sprintf(page
+ len
, "%s %s %p %u %d %p [",
604 fb
->name
, fb
->factory
->type
,
606 atomic_read(&fb
->refcnt
),
607 rcu_dereference_raw(fb
->next
));
608 fn
= rcu_dereference_raw(fb
->notifiers
);
610 len
+= sprintf(page
+ len
, "%u ", fn
->remote
);
611 rcu_assign_pointer(fn
, fn
->next
);
614 len
+= sprintf(page
+ len
- has_sub
, "]\n");
615 fb
= rcu_dereference_raw(fb
->next
);
620 /* FIXME: fits in page? */
625 int init_fblock_tables(void)
630 critbit_init_tree(&idpmap
);
631 fblock_cache
= kmem_cache_create("fblock", sizeof(struct fblock
),
632 0, SLAB_HWCACHE_ALIGN
|
633 SLAB_MEM_SPREAD
| SLAB_RECLAIM_ACCOUNT
,
637 atomic64_set(&idp_counter
, 0);
638 fblocks_proc
= create_proc_read_entry("fblocks", 0400, lana_proc_dir
,
639 procfs_fblocks
, NULL
);
644 kmem_cache_destroy(fblock_cache
);
649 EXPORT_SYMBOL_GPL(init_fblock_tables
);
651 void cleanup_fblock_tables(void)
653 remove_proc_entry("fblocks", lana_proc_dir
);
656 kmem_cache_destroy(fblock_cache
);
658 EXPORT_SYMBOL_GPL(cleanup_fblock_tables
);