test on fb_eth
[ana-net.git] / src / xt_sched.c
blob0904dfa7e171723e340b2cdbc3ddaf0eba4626dc
1 /*
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
7 * their disciplines.
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)
14 * Subject to the GPL.
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>
23 #include "xt_sched.h"
25 #define MAX_SCHED 32
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))
37 return -ENOENT;
38 dis = rcu_dereference_raw(pdt[pc]);
39 if (!dis->ops->discipline_init)
40 return 0;
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)) {
49 kfree_skb(skb);
50 return -EIO;
52 dis = rcu_dereference_raw(pdt[pc]);
53 if (unlikely(!dis || !dis->ops->discipline_sched)) {
54 kfree_skb(skb);
55 return -EIO;
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))
65 return;
66 dis = rcu_dereference_raw(pdt[pc]);
67 if (!dis->ops->discipline_cleanup)
68 return;
69 dis->ops->discipline_cleanup();
71 EXPORT_SYMBOL_GPL(ppesched_cleanup);
73 int ppesched_discipline_register(struct ppesched_discipline *pd)
75 int i;
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)) {
80 pc = i;
81 barrier();
82 __module_get(pd->owner);
84 return 0;
87 return -ENOMEM;
89 EXPORT_SYMBOL_GPL(ppesched_discipline_register);
91 void ppesched_discipline_unregister(struct ppesched_discipline *pd)
93 int i;
94 for (i = 0; i < MAX_SCHED; ++i) {
95 if (rcu_dereference_raw(pdt[i]) == pd) {
96 rcu_assign_pointer(pdt[i], NULL);
97 if (i == pc) {
98 pc = -1;
99 barrier();
100 module_put(pd->owner);
102 break;
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)
111 int i;
112 off_t len = 0;
114 len += sprintf(page + len, "running: %s\n",
115 pc != -1 ?
116 rcu_dereference_raw(pdt[pc])->name :
117 "none");
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);
126 *eof = 1;
127 return len;
130 static int ppesched_procfs_write(struct file *file, const char __user *buffer,
131 unsigned long count, void *data)
133 int ret = count, res;
134 size_t len;
135 char *discipline;
137 if (count > 64)
138 return -EINVAL;
139 len = count;
140 discipline = kmalloc(len, GFP_KERNEL);
141 if (!discipline)
142 return -ENOMEM;
143 memset(discipline, 0, len);
144 if (copy_from_user(discipline, buffer, len)) {
145 ret = -EFAULT;
146 goto out;
148 discipline[len - 1] = 0;
149 res = simple_strtol(discipline, NULL, 10);
150 if (res >= MAX_SCHED || res < -1) {
151 ret = -EINVAL;
152 goto out;
154 if (res >= 0) {
155 if (!rcu_dereference_raw(pdt[res])) {
156 ret = -EINVAL;
157 goto out;
160 if (pc != -1)
161 module_put(rcu_dereference_raw(pdt[pc])->owner);
162 pc = res;
163 barrier();
164 if (pc != -1)
165 __module_get(rcu_dereference_raw(pdt[pc])->owner);
166 ret = len;
167 out:
168 kfree(discipline);
169 return ret;
172 int init_ppesched_system(void)
174 int i;
175 for (i = 0; i < MAX_SCHED; ++i)
176 pdt[i] = NULL;
177 ppesched_proc = create_proc_entry("ppesched", 0600, lana_proc_dir);
178 if (!ppesched_proc)
179 return -ENOMEM;
180 ppesched_proc->read_proc = ppesched_procfs_read;
181 ppesched_proc->write_proc = ppesched_procfs_write;
182 ppesched_proc->data = NULL;
183 return 0;
185 EXPORT_SYMBOL_GPL(init_ppesched_system);
187 void cleanup_ppesched_system(void)
189 remove_proc_entry("ppesched", lana_proc_dir);
191 EXPORT_SYMBOL_GPL(cleanup_ppesched_system);