2 * Lightweight Autonomic Network Architecture
4 * Ingress and egress flow ppe-scheduler. Flows that traverse the network
5 * stack, e.g. ranging from PHY to the socket handler, are kept CPU-affine
6 * for the communication. This scheduler framework offers modules to register
9 * Change scheduling policies with, i.e. echo "1" > /proc/net/lana/ppesched
10 * where "n" is the id of the discipline.
12 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
13 * Swiss federal institute of technology (ETH Zurich)
17 #include <linux/kernel.h>
18 #include <linux/skbuff.h>
19 #include <linux/proc_fs.h>
20 #include <linux/rcupdate.h>
21 #include <linux/module.h>
27 static volatile int pc
= -1;
28 static struct ppesched_discipline
*pdt
[MAX_SCHED
];
30 extern struct proc_dir_entry
*lana_proc_dir
;
31 static struct proc_dir_entry
*ppesched_proc
;
33 int ppesched_init(void)
35 struct ppesched_discipline
*dis
;
36 if (unlikely(pc
== -1))
38 dis
= rcu_dereference_raw(pdt
[pc
]);
39 if (!dis
->ops
->discipline_init
)
41 return dis
->ops
->discipline_init();
43 EXPORT_SYMBOL_GPL(ppesched_init
);
45 int ppesched_sched(struct sk_buff
*skb
, enum path_type dir
)
47 struct ppesched_discipline
*dis
;
48 if (unlikely(pc
== -1)) {
52 dis
= rcu_dereference_raw(pdt
[pc
]);
53 if (unlikely(!dis
|| !dis
->ops
->discipline_sched
)) {
57 return dis
->ops
->discipline_sched(skb
, dir
);
59 EXPORT_SYMBOL_GPL(ppesched_sched
);
61 void ppesched_cleanup(void)
63 struct ppesched_discipline
*dis
;
64 if (unlikely(pc
== -1))
66 dis
= rcu_dereference_raw(pdt
[pc
]);
67 if (!dis
->ops
->discipline_cleanup
)
69 dis
->ops
->discipline_cleanup();
71 EXPORT_SYMBOL_GPL(ppesched_cleanup
);
73 int ppesched_discipline_register(struct ppesched_discipline
*pd
)
76 for (i
= 0; i
< MAX_SCHED
; ++i
) {
77 if (!rcu_dereference_raw(pdt
[i
])) {
78 rcu_assign_pointer(pdt
[i
], pd
);
79 if (unlikely(pc
== -1)) {
82 __module_get(pd
->owner
);
89 EXPORT_SYMBOL_GPL(ppesched_discipline_register
);
91 void ppesched_discipline_unregister(struct ppesched_discipline
*pd
)
94 for (i
= 0; i
< MAX_SCHED
; ++i
) {
95 if (rcu_dereference_raw(pdt
[i
]) == pd
) {
96 rcu_assign_pointer(pdt
[i
], NULL
);
100 module_put(pd
->owner
);
106 EXPORT_SYMBOL_GPL(ppesched_discipline_unregister
);
108 static int ppesched_procfs_read(char *page
, char **start
, off_t offset
,
109 int count
, int *eof
, void *data
)
114 len
+= sprintf(page
+ len
, "running: %s\n",
116 rcu_dereference_raw(pdt
[pc
])->name
:
118 len
+= sprintf(page
+ len
, "name addr id\n");
119 for (i
= 0; i
< MAX_SCHED
; ++i
) {
120 if (rcu_dereference_raw(pdt
[i
]))
121 len
+= sprintf(page
+ len
, "%s %p %d\n",
122 rcu_dereference_raw(pdt
[i
])->name
,
123 rcu_dereference_raw(pdt
[i
]), i
);
130 static int ppesched_procfs_write(struct file
*file
, const char __user
*buffer
,
131 unsigned long count
, void *data
)
133 int ret
= count
, res
;
140 discipline
= kmalloc(len
, GFP_KERNEL
);
143 memset(discipline
, 0, len
);
144 if (copy_from_user(discipline
, buffer
, len
)) {
148 discipline
[len
- 1] = 0;
149 res
= simple_strtol(discipline
, NULL
, 10);
150 if (res
>= MAX_SCHED
|| res
< -1) {
155 if (!rcu_dereference_raw(pdt
[res
])) {
161 module_put(rcu_dereference_raw(pdt
[pc
])->owner
);
165 __module_get(rcu_dereference_raw(pdt
[pc
])->owner
);
172 int init_ppesched_system(void)
175 for (i
= 0; i
< MAX_SCHED
; ++i
)
177 ppesched_proc
= create_proc_entry("ppesched", 0600, lana_proc_dir
);
180 ppesched_proc
->read_proc
= ppesched_procfs_read
;
181 ppesched_proc
->write_proc
= ppesched_procfs_write
;
184 EXPORT_SYMBOL_GPL(init_ppesched_system
);
186 void cleanup_ppesched_system(void)
188 remove_proc_entry("ppesched", lana_proc_dir
);
190 EXPORT_SYMBOL_GPL(cleanup_ppesched_system
);