2 * Lightweight Autonomic Network Architecture
4 * Packet counter module.
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/percpu.h>
18 #include <linux/prefetch.h>
19 #include <linux/u64_stats_sync.h>
20 #include <linux/proc_fs.h>
21 #include <linux/seq_file.h>
23 #include "xt_fblock.h"
24 #include "xt_builder.h"
27 #include "xt_engine.h"
28 #include "xt_builder.h"
30 struct fb_counter_priv
{
35 struct u64_stats_sync syncp
;
38 static int fb_counter_netrx(const struct fblock
* const fb
,
39 struct sk_buff
* const skb
,
40 enum path_type
* const dir
)
44 struct fb_counter_priv __percpu
*fb_priv_cpu
;
46 fb_priv_cpu
= this_cpu_ptr(rcu_dereference_raw(fb
->private_data
));
49 seq
= read_seqbegin(&fb_priv_cpu
->lock
);
50 write_next_idp_to_skb(skb
, fb
->idp
, fb_priv_cpu
->port
[*dir
]);
51 if (fb_priv_cpu
->port
[*dir
] == IDP_UNKNOWN
)
53 } while (read_seqretry(&fb_priv_cpu
->lock
, seq
));
55 u64_stats_update_begin(&fb_priv_cpu
->syncp
);
56 fb_priv_cpu
->packets
++;
57 fb_priv_cpu
->bytes
+= skb
->len
;
58 u64_stats_update_end(&fb_priv_cpu
->syncp
);
67 static int fb_counter_event(struct notifier_block
*self
, unsigned long cmd
,
73 struct fb_counter_priv __percpu
*fb_priv
;
76 fb
= rcu_dereference_raw(container_of(self
, struct fblock_notifier
, nb
)->self
);
77 fb_priv
= (struct fb_counter_priv __percpu
*) rcu_dereference_raw(fb
->private_data
);
81 case FBLOCK_BIND_IDP
: {
83 struct fblock_bind_msg
*msg
= args
;
85 for_each_online_cpu(cpu
) {
86 struct fb_counter_priv
*fb_priv_cpu
;
87 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
88 if (fb_priv_cpu
->port
[msg
->dir
] == IDP_UNKNOWN
) {
89 write_seqlock(&fb_priv_cpu
->lock
);
90 fb_priv_cpu
->port
[msg
->dir
] = msg
->idp
;
91 write_sequnlock(&fb_priv_cpu
->lock
);
100 printk(KERN_INFO
"[%s::%s] port %s bound to IDP%u\n",
101 fb
->name
, fb
->factory
->type
,
102 path_names
[msg
->dir
], msg
->idp
);
104 case FBLOCK_UNBIND_IDP
: {
106 struct fblock_bind_msg
*msg
= args
;
108 for_each_online_cpu(cpu
) {
109 struct fb_counter_priv
*fb_priv_cpu
;
110 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
111 if (fb_priv_cpu
->port
[msg
->dir
] == msg
->idp
) {
112 write_seqlock(&fb_priv_cpu
->lock
);
113 fb_priv_cpu
->port
[msg
->dir
] = IDP_UNKNOWN
;
114 write_sequnlock(&fb_priv_cpu
->lock
);
123 printk(KERN_INFO
"[%s::%s] port %s unbound\n",
124 fb
->name
, fb
->factory
->type
,
125 path_names
[msg
->dir
]);
127 case FBLOCK_SET_OPT
: {
128 struct fblock_opt_msg
*msg
= args
;
129 printk("Set option %s to %s!\n", msg
->key
, msg
->val
);
138 static int fb_counter_proc_show(struct seq_file
*m
, void *v
)
140 u64 pkts_sum
= 0, bytes_sum
= 0;
143 struct fblock
*fb
= (struct fblock
*) m
->private;
144 struct fb_counter_priv __percpu
*fb_priv
;
147 fb_priv
= (struct fb_counter_priv __percpu
*) rcu_dereference_raw(fb
->private_data
);
151 for_each_online_cpu(cpu
) {
153 struct fb_counter_priv
*fb_priv_cpu
;
154 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
156 start
= u64_stats_fetch_begin(&fb_priv_cpu
->syncp
);
157 pkts_sum
+= fb_priv_cpu
->packets
;
158 bytes_sum
+= fb_priv_cpu
->bytes
;
159 } while (u64_stats_fetch_retry(&fb_priv_cpu
->syncp
, start
));
163 memset(sline
, 0, sizeof(sline
));
164 snprintf(sline
, sizeof(sline
), "%llu %llu\n", pkts_sum
, bytes_sum
);
170 static int fb_counter_proc_open(struct inode
*inode
, struct file
*file
)
172 return single_open(file
, fb_counter_proc_show
, PDE(inode
)->data
);
175 static const struct file_operations fb_counter_proc_fops
= {
176 .owner
= THIS_MODULE
,
177 .open
= fb_counter_proc_open
,
180 .release
= single_release
,
183 static struct fblock
*fb_counter_ctor(char *name
)
188 struct fb_counter_priv __percpu
*fb_priv
;
189 struct proc_dir_entry
*fb_proc
;
191 fb
= alloc_fblock(GFP_ATOMIC
);
195 fb_priv
= alloc_percpu(struct fb_counter_priv
);
200 for_each_online_cpu(cpu
) {
201 struct fb_counter_priv
*fb_priv_cpu
;
202 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
203 seqlock_init(&fb_priv_cpu
->lock
);
204 fb_priv_cpu
->port
[0] = IDP_UNKNOWN
;
205 fb_priv_cpu
->port
[1] = IDP_UNKNOWN
;
206 fb_priv_cpu
->packets
= 0;
207 fb_priv_cpu
->bytes
= 0;
211 ret
= init_fblock(fb
, name
, fb_priv
);
214 fb
->netfb_rx
= fb_counter_netrx
;
215 fb
->event_rx
= fb_counter_event
;
217 fb_proc
= proc_create_data(fb
->name
, 0444, fblock_proc_dir
,
218 &fb_counter_proc_fops
,
223 ret
= register_fblock_namespace(fb
);
227 __module_get(THIS_MODULE
);
230 remove_proc_entry(fb
->name
, fblock_proc_dir
);
232 cleanup_fblock_ctor(fb
);
234 free_percpu(fb_priv
);
240 static void fb_counter_dtor(struct fblock
*fb
)
242 free_percpu(rcu_dereference_raw(fb
->private_data
));
243 remove_proc_entry(fb
->name
, fblock_proc_dir
);
244 module_put(THIS_MODULE
);
247 static struct fblock_factory fb_counter_factory
= {
250 .ctor
= fb_counter_ctor
,
251 .dtor
= fb_counter_dtor
,
252 .owner
= THIS_MODULE
,
255 static int __init
init_fb_counter_module(void)
257 return register_fblock_type(&fb_counter_factory
);
260 static void __exit
cleanup_fb_counter_module(void)
263 unregister_fblock_type(&fb_counter_factory
);
266 module_init(init_fb_counter_module
);
267 module_exit(cleanup_fb_counter_module
);
269 MODULE_LICENSE("GPL");
270 MODULE_AUTHOR("Daniel Borkmann <dborkma@tik.ee.ethz.ch>");
271 MODULE_DESCRIPTION("LANA packet counter module");