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>
22 #include "xt_fblock.h"
25 #include "xt_critbit.h"
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
))
54 elem
= kzalloc(sizeof(*elem
), GFP_ATOMIC
);
57 strlcpy(elem
->name
, name
, sizeof(elem
->name
));
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
);
68 static int unregister_from_fblock_namespace(char *name
)
71 struct idp_elem
*elem
;
72 elem
= struct_of(critbit_get(&idpmap
, name
), struct idp_elem
);
75 ret
= critbit_delete(&idpmap
, elem
->name
);
78 call_rcu(&elem
->rcu
, fblock_namespace_do_free_rcu
);
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
),
92 EXPORT_SYMBOL_GPL(__get_fblock_namespace_mapping
);
94 idp_t
get_fblock_namespace_mapping(char *name
)
98 ret
= __get_fblock_namespace_mapping(name
);
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
),
115 EXPORT_SYMBOL_GPL(__change_fblock_namespace_mapping
);
117 int change_fblock_namespace_mapping(char *name
, idp_t
new)
121 ret
= __change_fblock_namespace_mapping(name
, new);
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
)
132 p0
= rcu_dereference_raw(fblmap_head
[hash_idp(idp
)]);
134 if (p0
->idp
== idp
) {
138 p0
= rcu_dereference_raw(p0
->next
);
142 EXPORT_SYMBOL_GPL(__search_fblock
);
144 struct fblock
*search_fblock(idp_t idp
)
147 if (unlikely(idp
== IDP_UNKNOWN
))
150 ret
= __search_fblock(idp
);
154 EXPORT_SYMBOL_GPL(search_fblock
);
156 /* Note: user needs to do a put_fblock */
157 struct fblock
*__search_fblock_n(char *name
)
161 id
= get_fblock_namespace_mapping(name
);
162 if (unlikely(id
== IDP_UNKNOWN
))
164 fb
= search_fblock(id
);
169 EXPORT_SYMBOL_GPL(__search_fblock_n
);
171 struct fblock
*search_fblock_n(char *name
)
177 ret
= __search_fblock_n(name
);
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
)
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')
207 ret
= fb
->ops
->event_rx(&fbn
.nb
, FBLOCK_SET_OPT
, &msg
);
212 EXPORT_SYMBOL_GPL(__fblock_set_option
);
214 int fblock_set_option(struct fblock
*fb
, char *opt_string
)
217 if (unlikely(!opt_string
|| !fb
))
220 ret
= __fblock_set_option(fb
, opt_string
);
224 EXPORT_SYMBOL_GPL(fblock_set_option
);
226 /* Must already hold write_lock */
227 static void fblock_update_selfref(struct fblock_notifier
*head
,
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
)
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
);
256 EXPORT_SYMBOL_GPL(fblock_migrate_p
);
258 void fblock_migrate_r(struct fblock
*dst
, struct fblock
*src
)
261 struct fblock_notifier
*not_old
;
262 struct fblock_subscrib
*sub_old
;
267 write_lock(&dst
->lock
);
268 write_lock(&src
->lock
);
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
);
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
)
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
));
313 msg
.dir
= TYPE_EGRESS
;
316 ret
= fb1
->ops
->event_rx(&fbn
.nb
, FBLOCK_BIND_IDP
, &msg
);
317 if (ret
!= NOTIFY_OK
) {
323 msg
.dir
= TYPE_INGRESS
;
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
;
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");
340 ret
= subscribe_to_remote_fblock(fb1
, fb2
);
342 __fblock_unbind(fb1
, fb2
);
346 ret
= subscribe_to_remote_fblock(fb2
, fb1
);
348 __fblock_unbind(fb1
, fb2
);
352 /* We don't give refcount back! */
355 EXPORT_SYMBOL_GPL(__fblock_bind
);
357 int fblock_bind(struct fblock
*fb1
, struct fblock
*fb2
)
361 ret
= __fblock_bind(fb1
, fb2
);
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
)
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
;
386 ret
= fb1
->ops
->event_rx(&fbn
.nb
, FBLOCK_UNBIND_IDP
, &msg
);
387 if (ret
!= NOTIFY_OK
) {
388 /* We are not bound to fb2 */
392 msg
.dir
= TYPE_INGRESS
;
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
403 unsubscribe_from_remote_fblock(fb1
, fb2
);
404 unsubscribe_from_remote_fblock(fb2
, fb1
);
411 EXPORT_SYMBOL_GPL(__fblock_unbind
);
413 int fblock_unbind(struct fblock
*fb1
, struct fblock
*fb2
)
417 ret
= __fblock_unbind(fb1
, fb2
);
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
)
434 spin_lock_irqsave(&fblmap_head_lock
, flags
);
436 p0
= rcu_dereference_raw(fblmap_head
[hash_idp(p
->idp
)]);
438 rcu_assign_pointer(fblmap_head
[hash_idp(p
->idp
)], p
);
441 rcu_assign_pointer(p0
->next
, p
);
443 spin_unlock_irqrestore(&fblmap_head_lock
, flags
);
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
)
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
)]);
462 rcu_assign_pointer(fblmap_head
[hash_idp(p
->idp
)], p
);
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
);
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
)
490 spin_lock_irqsave(&fblmap_head_lock
, flags
);
491 p0
= rcu_dereference_raw(fblmap_head
[hash_idp(p
->idp
)]);
493 rcu_assign_pointer(fblmap_head
[hash_idp(p
->idp
)], p
->next
);
496 while ((p1
= rcu_dereference_raw(p0
->next
))) {
498 rcu_assign_pointer(p0
->next
, p1
->next
);
504 spin_unlock_irqrestore(&fblmap_head_lock
, flags
);
507 EXPORT_SYMBOL_GPL(unregister_fblock
);
510 * Removes the functional block from the system along with its namespace
513 static void __unregister_fblock_namespace(struct fblock
*p
, int rcu
)
518 spin_lock_irqsave(&fblmap_head_lock
, flags
);
519 p0
= rcu_dereference_raw(fblmap_head
[hash_idp(p
->idp
)]);
521 rcu_assign_pointer(fblmap_head
[hash_idp(p
->idp
)], p
->next
);
524 while ((p1
= rcu_dereference_raw(p0
->next
))) {
526 rcu_assign_pointer(p0
->next
, p
->next
);
532 spin_unlock_irqrestore(&fblmap_head_lock
, flags
);
533 unregister_from_fblock_namespace(p
->name
);
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
);
560 write_lock(&us
->lock
);
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
)
578 struct fblock_notifier
*fn
;
580 if (unlikely(!rcu_dereference_raw(us
->notifiers
)))
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
);
587 struct fblock_notifier
*f1
;
588 while ((f1
= fn
->next
)) {
589 if (f1
->remote
== remote
->idp
) {
592 fn
= f1
; /* free f1 */
598 write_unlock(&us
->lock
);
600 fblock_unregister_foreign_subscriber(remote
, &fn
->nb
);
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
)
621 #ifndef __USE_KMALLOC
622 fb
= kmem_cache_alloc(fblock_cache
, flags
);
624 __module_get(THIS_MODULE
);
626 fb
= kmalloc(sizeof(*fb
), flags
);
629 __module_get(THIS_MODULE
);
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
);
643 fb
->others
= kmalloc(sizeof(*(fb
->others
)), GFP_ATOMIC
);
646 ATOMIC_INIT_NOTIFIER_HEAD(&fb
->others
->subscribers
);
647 write_unlock(&fb
->lock
);
648 atomic_set(&fb
->refcnt
, 1);
651 EXPORT_SYMBOL_GPL(init_fblock
);
653 void kfree_fblock(struct fblock
*p
)
655 #ifndef __USE_KMALLOC
656 kmem_cache_free(fblock_cache
, p
);
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
)
684 struct fblock_notifier
*fn
;
686 len
+= sprintf(page
+ len
, "name type addr idp refcnt next subscr\n");
688 for (i
= 0; i
< HASHTSIZ
; ++i
) {
689 fb
= rcu_dereference_raw(fblmap_head
[i
]);
692 len
+= sprintf(page
+ len
, "%s %s %p %u %d %p [",
693 fb
->name
, fb
->factory
->type
,
695 atomic_read(&fb
->refcnt
),
696 rcu_dereference_raw(fb
->next
));
697 fn
= rcu_dereference_raw(fb
->notifiers
);
699 len
+= sprintf(page
+ len
, "%u ", fn
->remote
);
700 rcu_assign_pointer(fn
, fn
->next
);
703 len
+= sprintf(page
+ len
- has_sub
, "]\n");
704 fb
= rcu_dereference_raw(fb
->next
);
709 /* FIXME: fits in page? */
714 int init_fblock_tables(void)
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
);
725 fblock_cache
= kmem_cache_create("fblock", sizeof(struct fblock
),
726 0, SLAB_HWCACHE_ALIGN
|
727 SLAB_MEM_SPREAD
| SLAB_RECLAIM_ACCOUNT
,
731 atomic64_set(&idp_counter
, 0);
732 fblocks_proc
= create_proc_read_entry("fblocks", 0400, lana_proc_dir
,
733 procfs_fblocks
, NULL
);
738 kmem_cache_destroy(fblock_cache
);
745 EXPORT_SYMBOL_GPL(init_fblock_tables
);
747 void cleanup_fblock_tables(void)
749 remove_proc_entry("fblocks", lana_proc_dir
);
753 kmem_cache_destroy(fblock_cache
);
755 EXPORT_SYMBOL_GPL(cleanup_fblock_tables
);