2 * Lightweight Autonomic Network Architecture
4 * LANA Berkeley Packet Filter (BPF) module using the BPF JIT compiler.
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/spinlock.h>
14 #include <linux/notifier.h>
15 #include <linux/rcupdate.h>
16 #include <linux/seqlock.h>
17 #include <linux/spinlock.h>
18 #include <linux/slab.h>
19 #include <linux/percpu.h>
20 #include <linux/prefetch.h>
21 #include <linux/filter.h>
22 #include <linux/proc_fs.h>
23 #include <linux/seq_file.h>
24 #include <linux/uaccess.h>
26 #include "xt_fblock.h"
27 #include "xt_builder.h"
30 #include "xt_engine.h"
31 #include "xt_builder.h"
35 struct sk_filter
*filter
;
39 static int fb_bpf_init_filter(struct fb_bpf_priv __percpu
*fb_priv_cpu
,
40 struct sock_fprog
*fprog
, unsigned int cpu
)
43 struct sk_filter
*sf
, *sfold
;
47 if (fprog
->filter
== NULL
)
50 fsize
= sizeof(struct sock_filter
) * fprog
->len
;
52 sf
= kmalloc_node(fsize
+ sizeof(*sf
), GFP_KERNEL
, cpu_to_node(cpu
));
56 memcpy(sf
->insns
, fprog
->filter
, fsize
);
57 atomic_set(&sf
->refcnt
, 1);
59 sf
->bpf_func
= sk_run_filter
;
61 err
= sk_chk_filter(sf
->insns
, sf
->len
);
69 spin_lock_irqsave(&fb_priv_cpu
->flock
, flags
);
70 sfold
= fb_priv_cpu
->filter
;
71 fb_priv_cpu
->filter
= sf
;
72 spin_unlock_irqrestore(&fb_priv_cpu
->flock
, flags
);
82 static int fb_bpf_init_filter_cpus(struct fblock
*fb
, struct sock_fprog
*fprog
)
86 struct fb_bpf_priv __percpu
*fb_priv
;
92 fb_priv
= (struct fb_bpf_priv __percpu
*) rcu_dereference_raw(fb
->private_data
);
96 for_each_online_cpu(cpu
) {
97 struct fb_bpf_priv
*fb_priv_cpu
;
98 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
99 err
= fb_bpf_init_filter(fb_priv_cpu
, fprog
, cpu
);
101 printk(KERN_ERR
"[%s::%s] fb_bpf_init_filter error: %d\n",
102 fb
->name
, fb
->factory
->type
, err
);
111 static void fb_bpf_cleanup_filter(struct fb_bpf_priv __percpu
*fb_priv_cpu
)
114 struct sk_filter
*sfold
;
116 spin_lock_irqsave(&fb_priv_cpu
->flock
, flags
);
117 sfold
= fb_priv_cpu
->filter
;
118 fb_priv_cpu
->filter
= NULL
;
119 spin_unlock_irqrestore(&fb_priv_cpu
->flock
, flags
);
127 static void fb_bpf_cleanup_filter_cpus(struct fblock
*fb
)
130 struct fb_bpf_priv __percpu
*fb_priv
;
136 fb_priv
= (struct fb_bpf_priv __percpu
*) rcu_dereference_raw(fb
->private_data
);
140 for_each_online_cpu(cpu
) {
141 struct fb_bpf_priv
*fb_priv_cpu
;
142 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
143 fb_bpf_cleanup_filter(fb_priv_cpu
);
148 static int fb_bpf_netrx(const struct fblock
* const fb
,
149 struct sk_buff
* const skb
,
150 enum path_type
* const dir
)
153 unsigned int pkt_len
;
155 struct fb_bpf_priv __percpu
*fb_priv_cpu
;
157 fb_priv_cpu
= this_cpu_ptr(rcu_dereference_raw(fb
->private_data
));
159 spin_lock_irqsave(&fb_priv_cpu
->flock
, flags
);
160 if (fb_priv_cpu
->filter
) {
161 pkt_len
= SK_RUN_FILTER(fb_priv_cpu
->filter
, skb
);
162 /* No snap, either drop or pass */
163 if (pkt_len
< skb
->len
) {
164 spin_unlock_irqrestore(&fb_priv_cpu
->flock
, flags
);
169 write_next_idp_to_skb(skb
, fb
->idp
, fb_priv_cpu
->port
[*dir
]);
170 if (fb_priv_cpu
->port
[*dir
] == IDP_UNKNOWN
)
172 spin_unlock_irqrestore(&fb_priv_cpu
->flock
, flags
);
181 static int fb_bpf_event(struct notifier_block
*self
, unsigned long cmd
,
187 struct fb_bpf_priv __percpu
*fb_priv
;
190 fb
= rcu_dereference_raw(container_of(self
, struct fblock_notifier
, nb
)->self
);
191 fb_priv
= (struct fb_bpf_priv __percpu
*) rcu_dereference_raw(fb
->private_data
);
195 case FBLOCK_BIND_IDP
: {
197 struct fblock_bind_msg
*msg
= args
;
199 for_each_online_cpu(cpu
) {
200 struct fb_bpf_priv
*fb_priv_cpu
;
201 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
202 spin_lock(&fb_priv_cpu
->flock
);
203 if (fb_priv_cpu
->port
[msg
->dir
] == IDP_UNKNOWN
) {
204 fb_priv_cpu
->port
[msg
->dir
] = msg
->idp
;
208 spin_unlock(&fb_priv_cpu
->flock
);
211 spin_unlock(&fb_priv_cpu
->flock
);
215 printk(KERN_INFO
"[%s::%s] port %s bound to IDP%u\n",
216 fb
->name
, fb
->factory
->type
,
217 path_names
[msg
->dir
], msg
->idp
);
219 case FBLOCK_UNBIND_IDP
: {
221 struct fblock_bind_msg
*msg
= args
;
223 for_each_online_cpu(cpu
) {
224 struct fb_bpf_priv
*fb_priv_cpu
;
225 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
226 spin_lock(&fb_priv_cpu
->flock
);
227 if (fb_priv_cpu
->port
[msg
->dir
] == msg
->idp
) {
228 fb_priv_cpu
->port
[msg
->dir
] = IDP_UNKNOWN
;
232 spin_unlock(&fb_priv_cpu
->flock
);
235 spin_unlock(&fb_priv_cpu
->flock
);
239 printk(KERN_INFO
"[%s::%s] port %s unbound\n",
240 fb
->name
, fb
->factory
->type
,
241 path_names
[msg
->dir
]);
250 static int fb_bpf_proc_show_filter(struct seq_file
*seq
, void *v
)
253 struct fblock
*fb
= v
;
254 struct fb_bpf_priv __percpu
*fb_priv
;
255 struct fb_bpf_priv
*fb_priv_cpu
;
256 struct sk_filter
*sf
;
259 fb_priv
= this_cpu_ptr(rcu_dereference_raw(fb
->private_data
));
263 fb_priv_cpu
= per_cpu_ptr(fb_priv
, smp_processor_id());
264 spin_lock_irqsave(&fb_priv_cpu
->flock
, flags
);
266 sf
= fb_priv_cpu
->filter
;
269 if (sf
->bpf_func
== sk_run_filter
)
270 seq_puts(seq
, "bpf jit: 0\n");
272 seq_puts(seq
, "bpf jit: 1\n");
273 seq_puts(seq
, "code:\n");
274 for (i
= 0; i
< sf
->len
; ++i
) {
276 memset(sline
, 0, sizeof(sline
));
277 snprintf(sline
, sizeof(sline
),
283 sline
[sizeof(sline
) - 1] = 0;
284 seq_puts(seq
, sline
);
288 spin_unlock_irqrestore(&fb_priv_cpu
->flock
, flags
);
294 static int fb_bpf_proc_open(struct inode
*inode
, struct file
*file
)
296 return single_open(file
, fb_bpf_proc_show_filter
, PDE(inode
)->data
);
299 static ssize_t
fb_bpf_proc_write(struct file
*file
, const char __user
* user_buffer
,
300 size_t count
, loff_t
* offset
)
302 /* TODO: Parse struct sock_fprog and init filter */
306 static const struct file_operations fb_bpf_proc_fops
= {
307 .owner
= THIS_MODULE
,
308 .open
= fb_bpf_proc_open
,
311 .write
= fb_bpf_proc_write
,
312 .release
= single_release
,
315 static struct fblock
*fb_bpf_ctor(char *name
)
320 struct fb_bpf_priv __percpu
*fb_priv
;
321 struct proc_dir_entry
*fb_proc
;
323 fb
= alloc_fblock(GFP_ATOMIC
);
327 fb_priv
= alloc_percpu(struct fb_bpf_priv
);
332 for_each_online_cpu(cpu
) {
333 struct fb_bpf_priv
*fb_priv_cpu
;
334 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
335 spin_lock_init(&fb_priv_cpu
->flock
);
336 fb_priv_cpu
->port
[0] = IDP_UNKNOWN
;
337 fb_priv_cpu
->port
[1] = IDP_UNKNOWN
;
338 fb_priv_cpu
->filter
= NULL
;
342 ret
= init_fblock(fb
, name
, fb_priv
);
346 fb
->netfb_rx
= fb_bpf_netrx
;
347 fb
->event_rx
= fb_bpf_event
;
349 fb_proc
= proc_create_data(fb
->name
, 0444, fblock_proc_dir
,
350 &fb_bpf_proc_fops
, fb
);
354 ret
= register_fblock_namespace(fb
);
358 __module_get(THIS_MODULE
);
362 remove_proc_entry(fb
->name
, fblock_proc_dir
);
364 cleanup_fblock_ctor(fb
);
366 free_percpu(fb_priv
);
372 static void fb_bpf_dtor(struct fblock
*fb
)
374 free_percpu(rcu_dereference_raw(fb
->private_data
));
375 remove_proc_entry(fb
->name
, fblock_proc_dir
);
376 module_put(THIS_MODULE
);
379 static struct fblock_factory fb_bpf_factory
= {
384 .owner
= THIS_MODULE
,
387 static int __init
init_fb_bpf_module(void)
389 return register_fblock_type(&fb_bpf_factory
);
392 static void __exit
cleanup_fb_bpf_module(void)
394 unregister_fblock_type(&fb_bpf_factory
);
397 module_init(init_fb_bpf_module
);
398 module_exit(cleanup_fb_bpf_module
);
400 MODULE_LICENSE("GPL");
401 MODULE_AUTHOR("Daniel Borkmann <dborkma@tik.ee.ethz.ch>");
402 MODULE_DESCRIPTION("LANA Berkeley Packet Filter module");