[PATCH] count_vm_events() fix
[linux-2.6/mini2440.git] / net / sched / cls_route.c
blobc2e71900f7bdd2f64ed400860623004342e12fd5
1 /*
2 * net/sched/cls_route.c ROUTE4 classifier.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 #include <linux/module.h>
13 #include <asm/uaccess.h>
14 #include <asm/system.h>
15 #include <linux/bitops.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/sched.h>
19 #include <linux/string.h>
20 #include <linux/mm.h>
21 #include <linux/socket.h>
22 #include <linux/sockios.h>
23 #include <linux/in.h>
24 #include <linux/errno.h>
25 #include <linux/interrupt.h>
26 #include <linux/if_ether.h>
27 #include <linux/inet.h>
28 #include <linux/netdevice.h>
29 #include <linux/etherdevice.h>
30 #include <linux/notifier.h>
31 #include <net/ip.h>
32 #include <net/route.h>
33 #include <linux/skbuff.h>
34 #include <net/sock.h>
35 #include <net/act_api.h>
36 #include <net/pkt_cls.h>
39 1. For now we assume that route tags < 256.
40 It allows to use direct table lookups, instead of hash tables.
41 2. For now we assume that "from TAG" and "fromdev DEV" statements
42 are mutually exclusive.
43 3. "to TAG from ANY" has higher priority, than "to ANY from XXX"
46 struct route4_fastmap
48 struct route4_filter *filter;
49 u32 id;
50 int iif;
53 struct route4_head
55 struct route4_fastmap fastmap[16];
56 struct route4_bucket *table[256+1];
59 struct route4_bucket
61 /* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */
62 struct route4_filter *ht[16+16+1];
65 struct route4_filter
67 struct route4_filter *next;
68 u32 id;
69 int iif;
71 struct tcf_result res;
72 struct tcf_exts exts;
73 u32 handle;
74 struct route4_bucket *bkt;
77 #define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
79 static struct tcf_ext_map route_ext_map = {
80 .police = TCA_ROUTE4_POLICE,
81 .action = TCA_ROUTE4_ACT
84 static __inline__ int route4_fastmap_hash(u32 id, int iif)
86 return id&0xF;
89 static inline
90 void route4_reset_fastmap(struct net_device *dev, struct route4_head *head, u32 id)
92 spin_lock_bh(&dev->queue_lock);
93 memset(head->fastmap, 0, sizeof(head->fastmap));
94 spin_unlock_bh(&dev->queue_lock);
97 static void __inline__
98 route4_set_fastmap(struct route4_head *head, u32 id, int iif,
99 struct route4_filter *f)
101 int h = route4_fastmap_hash(id, iif);
102 head->fastmap[h].id = id;
103 head->fastmap[h].iif = iif;
104 head->fastmap[h].filter = f;
107 static __inline__ int route4_hash_to(u32 id)
109 return id&0xFF;
112 static __inline__ int route4_hash_from(u32 id)
114 return (id>>16)&0xF;
117 static __inline__ int route4_hash_iif(int iif)
119 return 16 + ((iif>>16)&0xF);
122 static __inline__ int route4_hash_wild(void)
124 return 32;
127 #define ROUTE4_APPLY_RESULT() \
129 *res = f->res; \
130 if (tcf_exts_is_available(&f->exts)) { \
131 int r = tcf_exts_exec(skb, &f->exts, res); \
132 if (r < 0) { \
133 dont_cache = 1; \
134 continue; \
136 return r; \
137 } else if (!dont_cache) \
138 route4_set_fastmap(head, id, iif, f); \
139 return 0; \
142 static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
143 struct tcf_result *res)
145 struct route4_head *head = (struct route4_head*)tp->root;
146 struct dst_entry *dst;
147 struct route4_bucket *b;
148 struct route4_filter *f;
149 u32 id, h;
150 int iif, dont_cache = 0;
152 if ((dst = skb->dst) == NULL)
153 goto failure;
155 id = dst->tclassid;
156 if (head == NULL)
157 goto old_method;
159 iif = ((struct rtable*)dst)->fl.iif;
161 h = route4_fastmap_hash(id, iif);
162 if (id == head->fastmap[h].id &&
163 iif == head->fastmap[h].iif &&
164 (f = head->fastmap[h].filter) != NULL) {
165 if (f == ROUTE4_FAILURE)
166 goto failure;
168 *res = f->res;
169 return 0;
172 h = route4_hash_to(id);
174 restart:
175 if ((b = head->table[h]) != NULL) {
176 for (f = b->ht[route4_hash_from(id)]; f; f = f->next)
177 if (f->id == id)
178 ROUTE4_APPLY_RESULT();
180 for (f = b->ht[route4_hash_iif(iif)]; f; f = f->next)
181 if (f->iif == iif)
182 ROUTE4_APPLY_RESULT();
184 for (f = b->ht[route4_hash_wild()]; f; f = f->next)
185 ROUTE4_APPLY_RESULT();
188 if (h < 256) {
189 h = 256;
190 id &= ~0xFFFF;
191 goto restart;
194 if (!dont_cache)
195 route4_set_fastmap(head, id, iif, ROUTE4_FAILURE);
196 failure:
197 return -1;
199 old_method:
200 if (id && (TC_H_MAJ(id) == 0 ||
201 !(TC_H_MAJ(id^tp->q->handle)))) {
202 res->classid = id;
203 res->class = 0;
204 return 0;
206 return -1;
209 static inline u32 to_hash(u32 id)
211 u32 h = id&0xFF;
212 if (id&0x8000)
213 h += 256;
214 return h;
217 static inline u32 from_hash(u32 id)
219 id &= 0xFFFF;
220 if (id == 0xFFFF)
221 return 32;
222 if (!(id & 0x8000)) {
223 if (id > 255)
224 return 256;
225 return id&0xF;
227 return 16 + (id&0xF);
230 static unsigned long route4_get(struct tcf_proto *tp, u32 handle)
232 struct route4_head *head = (struct route4_head*)tp->root;
233 struct route4_bucket *b;
234 struct route4_filter *f;
235 unsigned h1, h2;
237 if (!head)
238 return 0;
240 h1 = to_hash(handle);
241 if (h1 > 256)
242 return 0;
244 h2 = from_hash(handle>>16);
245 if (h2 > 32)
246 return 0;
248 if ((b = head->table[h1]) != NULL) {
249 for (f = b->ht[h2]; f; f = f->next)
250 if (f->handle == handle)
251 return (unsigned long)f;
253 return 0;
256 static void route4_put(struct tcf_proto *tp, unsigned long f)
260 static int route4_init(struct tcf_proto *tp)
262 return 0;
265 static inline void
266 route4_delete_filter(struct tcf_proto *tp, struct route4_filter *f)
268 tcf_unbind_filter(tp, &f->res);
269 tcf_exts_destroy(tp, &f->exts);
270 kfree(f);
273 static void route4_destroy(struct tcf_proto *tp)
275 struct route4_head *head = xchg(&tp->root, NULL);
276 int h1, h2;
278 if (head == NULL)
279 return;
281 for (h1=0; h1<=256; h1++) {
282 struct route4_bucket *b;
284 if ((b = head->table[h1]) != NULL) {
285 for (h2=0; h2<=32; h2++) {
286 struct route4_filter *f;
288 while ((f = b->ht[h2]) != NULL) {
289 b->ht[h2] = f->next;
290 route4_delete_filter(tp, f);
293 kfree(b);
296 kfree(head);
299 static int route4_delete(struct tcf_proto *tp, unsigned long arg)
301 struct route4_head *head = (struct route4_head*)tp->root;
302 struct route4_filter **fp, *f = (struct route4_filter*)arg;
303 unsigned h = 0;
304 struct route4_bucket *b;
305 int i;
307 if (!head || !f)
308 return -EINVAL;
310 h = f->handle;
311 b = f->bkt;
313 for (fp = &b->ht[from_hash(h>>16)]; *fp; fp = &(*fp)->next) {
314 if (*fp == f) {
315 tcf_tree_lock(tp);
316 *fp = f->next;
317 tcf_tree_unlock(tp);
319 route4_reset_fastmap(tp->q->dev, head, f->id);
320 route4_delete_filter(tp, f);
322 /* Strip tree */
324 for (i=0; i<=32; i++)
325 if (b->ht[i])
326 return 0;
328 /* OK, session has no flows */
329 tcf_tree_lock(tp);
330 head->table[to_hash(h)] = NULL;
331 tcf_tree_unlock(tp);
333 kfree(b);
334 return 0;
337 return 0;
340 static int route4_set_parms(struct tcf_proto *tp, unsigned long base,
341 struct route4_filter *f, u32 handle, struct route4_head *head,
342 struct rtattr **tb, struct rtattr *est, int new)
344 int err;
345 u32 id = 0, to = 0, nhandle = 0x8000;
346 struct route4_filter *fp;
347 unsigned int h1;
348 struct route4_bucket *b;
349 struct tcf_exts e;
351 err = tcf_exts_validate(tp, tb, est, &e, &route_ext_map);
352 if (err < 0)
353 return err;
355 err = -EINVAL;
356 if (tb[TCA_ROUTE4_CLASSID-1])
357 if (RTA_PAYLOAD(tb[TCA_ROUTE4_CLASSID-1]) < sizeof(u32))
358 goto errout;
360 if (tb[TCA_ROUTE4_TO-1]) {
361 if (new && handle & 0x8000)
362 goto errout;
363 if (RTA_PAYLOAD(tb[TCA_ROUTE4_TO-1]) < sizeof(u32))
364 goto errout;
365 to = *(u32*)RTA_DATA(tb[TCA_ROUTE4_TO-1]);
366 if (to > 0xFF)
367 goto errout;
368 nhandle = to;
371 if (tb[TCA_ROUTE4_FROM-1]) {
372 if (tb[TCA_ROUTE4_IIF-1])
373 goto errout;
374 if (RTA_PAYLOAD(tb[TCA_ROUTE4_FROM-1]) < sizeof(u32))
375 goto errout;
376 id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_FROM-1]);
377 if (id > 0xFF)
378 goto errout;
379 nhandle |= id << 16;
380 } else if (tb[TCA_ROUTE4_IIF-1]) {
381 if (RTA_PAYLOAD(tb[TCA_ROUTE4_IIF-1]) < sizeof(u32))
382 goto errout;
383 id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_IIF-1]);
384 if (id > 0x7FFF)
385 goto errout;
386 nhandle |= (id | 0x8000) << 16;
387 } else
388 nhandle |= 0xFFFF << 16;
390 if (handle && new) {
391 nhandle |= handle & 0x7F00;
392 if (nhandle != handle)
393 goto errout;
396 h1 = to_hash(nhandle);
397 if ((b = head->table[h1]) == NULL) {
398 err = -ENOBUFS;
399 b = kmalloc(sizeof(struct route4_bucket), GFP_KERNEL);
400 if (b == NULL)
401 goto errout;
402 memset(b, 0, sizeof(*b));
404 tcf_tree_lock(tp);
405 head->table[h1] = b;
406 tcf_tree_unlock(tp);
407 } else {
408 unsigned int h2 = from_hash(nhandle >> 16);
409 err = -EEXIST;
410 for (fp = b->ht[h2]; fp; fp = fp->next)
411 if (fp->handle == f->handle)
412 goto errout;
415 tcf_tree_lock(tp);
416 if (tb[TCA_ROUTE4_TO-1])
417 f->id = to;
419 if (tb[TCA_ROUTE4_FROM-1])
420 f->id = to | id<<16;
421 else if (tb[TCA_ROUTE4_IIF-1])
422 f->iif = id;
424 f->handle = nhandle;
425 f->bkt = b;
426 tcf_tree_unlock(tp);
428 if (tb[TCA_ROUTE4_CLASSID-1]) {
429 f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]);
430 tcf_bind_filter(tp, &f->res, base);
433 tcf_exts_change(tp, &f->exts, &e);
435 return 0;
436 errout:
437 tcf_exts_destroy(tp, &e);
438 return err;
441 static int route4_change(struct tcf_proto *tp, unsigned long base,
442 u32 handle,
443 struct rtattr **tca,
444 unsigned long *arg)
446 struct route4_head *head = tp->root;
447 struct route4_filter *f, *f1, **fp;
448 struct route4_bucket *b;
449 struct rtattr *opt = tca[TCA_OPTIONS-1];
450 struct rtattr *tb[TCA_ROUTE4_MAX];
451 unsigned int h, th;
452 u32 old_handle = 0;
453 int err;
455 if (opt == NULL)
456 return handle ? -EINVAL : 0;
458 if (rtattr_parse_nested(tb, TCA_ROUTE4_MAX, opt) < 0)
459 return -EINVAL;
461 if ((f = (struct route4_filter*)*arg) != NULL) {
462 if (f->handle != handle && handle)
463 return -EINVAL;
465 if (f->bkt)
466 old_handle = f->handle;
468 err = route4_set_parms(tp, base, f, handle, head, tb,
469 tca[TCA_RATE-1], 0);
470 if (err < 0)
471 return err;
473 goto reinsert;
476 err = -ENOBUFS;
477 if (head == NULL) {
478 head = kmalloc(sizeof(struct route4_head), GFP_KERNEL);
479 if (head == NULL)
480 goto errout;
481 memset(head, 0, sizeof(struct route4_head));
483 tcf_tree_lock(tp);
484 tp->root = head;
485 tcf_tree_unlock(tp);
488 f = kmalloc(sizeof(struct route4_filter), GFP_KERNEL);
489 if (f == NULL)
490 goto errout;
491 memset(f, 0, sizeof(*f));
493 err = route4_set_parms(tp, base, f, handle, head, tb,
494 tca[TCA_RATE-1], 1);
495 if (err < 0)
496 goto errout;
498 reinsert:
499 h = from_hash(f->handle >> 16);
500 for (fp = &f->bkt->ht[h]; (f1=*fp) != NULL; fp = &f1->next)
501 if (f->handle < f1->handle)
502 break;
504 f->next = f1;
505 tcf_tree_lock(tp);
506 *fp = f;
508 if (old_handle && f->handle != old_handle) {
509 th = to_hash(old_handle);
510 h = from_hash(old_handle >> 16);
511 if ((b = head->table[th]) != NULL) {
512 for (fp = &b->ht[h]; *fp; fp = &(*fp)->next) {
513 if (*fp == f) {
514 *fp = f->next;
515 break;
520 tcf_tree_unlock(tp);
522 route4_reset_fastmap(tp->q->dev, head, f->id);
523 *arg = (unsigned long)f;
524 return 0;
526 errout:
527 kfree(f);
528 return err;
531 static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
533 struct route4_head *head = tp->root;
534 unsigned h, h1;
536 if (head == NULL)
537 arg->stop = 1;
539 if (arg->stop)
540 return;
542 for (h = 0; h <= 256; h++) {
543 struct route4_bucket *b = head->table[h];
545 if (b) {
546 for (h1 = 0; h1 <= 32; h1++) {
547 struct route4_filter *f;
549 for (f = b->ht[h1]; f; f = f->next) {
550 if (arg->count < arg->skip) {
551 arg->count++;
552 continue;
554 if (arg->fn(tp, (unsigned long)f, arg) < 0) {
555 arg->stop = 1;
556 return;
558 arg->count++;
565 static int route4_dump(struct tcf_proto *tp, unsigned long fh,
566 struct sk_buff *skb, struct tcmsg *t)
568 struct route4_filter *f = (struct route4_filter*)fh;
569 unsigned char *b = skb->tail;
570 struct rtattr *rta;
571 u32 id;
573 if (f == NULL)
574 return skb->len;
576 t->tcm_handle = f->handle;
578 rta = (struct rtattr*)b;
579 RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
581 if (!(f->handle&0x8000)) {
582 id = f->id&0xFF;
583 RTA_PUT(skb, TCA_ROUTE4_TO, sizeof(id), &id);
585 if (f->handle&0x80000000) {
586 if ((f->handle>>16) != 0xFFFF)
587 RTA_PUT(skb, TCA_ROUTE4_IIF, sizeof(f->iif), &f->iif);
588 } else {
589 id = f->id>>16;
590 RTA_PUT(skb, TCA_ROUTE4_FROM, sizeof(id), &id);
592 if (f->res.classid)
593 RTA_PUT(skb, TCA_ROUTE4_CLASSID, 4, &f->res.classid);
595 if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0)
596 goto rtattr_failure;
598 rta->rta_len = skb->tail - b;
600 if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0)
601 goto rtattr_failure;
603 return skb->len;
605 rtattr_failure:
606 skb_trim(skb, b - skb->data);
607 return -1;
610 static struct tcf_proto_ops cls_route4_ops = {
611 .next = NULL,
612 .kind = "route",
613 .classify = route4_classify,
614 .init = route4_init,
615 .destroy = route4_destroy,
616 .get = route4_get,
617 .put = route4_put,
618 .change = route4_change,
619 .delete = route4_delete,
620 .walk = route4_walk,
621 .dump = route4_dump,
622 .owner = THIS_MODULE,
625 static int __init init_route4(void)
627 return register_tcf_proto_ops(&cls_route4_ops);
630 static void __exit exit_route4(void)
632 unregister_tcf_proto_ops(&cls_route4_ops);
635 module_init(init_route4)
636 module_exit(exit_route4)
637 MODULE_LICENSE("GPL");