intelfb: prepare for i9xx support.
[linux-2.6/linux-2.6-openrd.git] / net / sched / cls_route.c
blob520ff716dab2f0d744845747366f320dd83f9434
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 <linux/config.h>
14 #include <asm/uaccess.h>
15 #include <asm/system.h>
16 #include <linux/bitops.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/socket.h>
23 #include <linux/sockios.h>
24 #include <linux/in.h>
25 #include <linux/errno.h>
26 #include <linux/interrupt.h>
27 #include <linux/if_ether.h>
28 #include <linux/inet.h>
29 #include <linux/netdevice.h>
30 #include <linux/etherdevice.h>
31 #include <linux/notifier.h>
32 #include <net/ip.h>
33 #include <net/route.h>
34 #include <linux/skbuff.h>
35 #include <net/sock.h>
36 #include <net/act_api.h>
37 #include <net/pkt_cls.h>
40 1. For now we assume that route tags < 256.
41 It allows to use direct table lookups, instead of hash tables.
42 2. For now we assume that "from TAG" and "fromdev DEV" statements
43 are mutually exclusive.
44 3. "to TAG from ANY" has higher priority, than "to ANY from XXX"
47 struct route4_fastmap
49 struct route4_filter *filter;
50 u32 id;
51 int iif;
54 struct route4_head
56 struct route4_fastmap fastmap[16];
57 struct route4_bucket *table[256+1];
60 struct route4_bucket
62 /* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */
63 struct route4_filter *ht[16+16+1];
66 struct route4_filter
68 struct route4_filter *next;
69 u32 id;
70 int iif;
72 struct tcf_result res;
73 struct tcf_exts exts;
74 u32 handle;
75 struct route4_bucket *bkt;
78 #define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
80 static struct tcf_ext_map route_ext_map = {
81 .police = TCA_ROUTE4_POLICE,
82 .action = TCA_ROUTE4_ACT
85 static __inline__ int route4_fastmap_hash(u32 id, int iif)
87 return id&0xF;
90 static inline
91 void route4_reset_fastmap(struct net_device *dev, struct route4_head *head, u32 id)
93 spin_lock_bh(&dev->queue_lock);
94 memset(head->fastmap, 0, sizeof(head->fastmap));
95 spin_unlock_bh(&dev->queue_lock);
98 static void __inline__
99 route4_set_fastmap(struct route4_head *head, u32 id, int iif,
100 struct route4_filter *f)
102 int h = route4_fastmap_hash(id, iif);
103 head->fastmap[h].id = id;
104 head->fastmap[h].iif = iif;
105 head->fastmap[h].filter = f;
108 static __inline__ int route4_hash_to(u32 id)
110 return id&0xFF;
113 static __inline__ int route4_hash_from(u32 id)
115 return (id>>16)&0xF;
118 static __inline__ int route4_hash_iif(int iif)
120 return 16 + ((iif>>16)&0xF);
123 static __inline__ int route4_hash_wild(void)
125 return 32;
128 #define ROUTE4_APPLY_RESULT() \
130 *res = f->res; \
131 if (tcf_exts_is_available(&f->exts)) { \
132 int r = tcf_exts_exec(skb, &f->exts, res); \
133 if (r < 0) { \
134 dont_cache = 1; \
135 continue; \
137 return r; \
138 } else if (!dont_cache) \
139 route4_set_fastmap(head, id, iif, f); \
140 return 0; \
143 static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
144 struct tcf_result *res)
146 struct route4_head *head = (struct route4_head*)tp->root;
147 struct dst_entry *dst;
148 struct route4_bucket *b;
149 struct route4_filter *f;
150 u32 id, h;
151 int iif, dont_cache = 0;
153 if ((dst = skb->dst) == NULL)
154 goto failure;
156 id = dst->tclassid;
157 if (head == NULL)
158 goto old_method;
160 iif = ((struct rtable*)dst)->fl.iif;
162 h = route4_fastmap_hash(id, iif);
163 if (id == head->fastmap[h].id &&
164 iif == head->fastmap[h].iif &&
165 (f = head->fastmap[h].filter) != NULL) {
166 if (f == ROUTE4_FAILURE)
167 goto failure;
169 *res = f->res;
170 return 0;
173 h = route4_hash_to(id);
175 restart:
176 if ((b = head->table[h]) != NULL) {
177 for (f = b->ht[route4_hash_from(id)]; f; f = f->next)
178 if (f->id == id)
179 ROUTE4_APPLY_RESULT();
181 for (f = b->ht[route4_hash_iif(iif)]; f; f = f->next)
182 if (f->iif == iif)
183 ROUTE4_APPLY_RESULT();
185 for (f = b->ht[route4_hash_wild()]; f; f = f->next)
186 ROUTE4_APPLY_RESULT();
189 if (h < 256) {
190 h = 256;
191 id &= ~0xFFFF;
192 goto restart;
195 if (!dont_cache)
196 route4_set_fastmap(head, id, iif, ROUTE4_FAILURE);
197 failure:
198 return -1;
200 old_method:
201 if (id && (TC_H_MAJ(id) == 0 ||
202 !(TC_H_MAJ(id^tp->q->handle)))) {
203 res->classid = id;
204 res->class = 0;
205 return 0;
207 return -1;
210 static inline u32 to_hash(u32 id)
212 u32 h = id&0xFF;
213 if (id&0x8000)
214 h += 256;
215 return h;
218 static inline u32 from_hash(u32 id)
220 id &= 0xFFFF;
221 if (id == 0xFFFF)
222 return 32;
223 if (!(id & 0x8000)) {
224 if (id > 255)
225 return 256;
226 return id&0xF;
228 return 16 + (id&0xF);
231 static unsigned long route4_get(struct tcf_proto *tp, u32 handle)
233 struct route4_head *head = (struct route4_head*)tp->root;
234 struct route4_bucket *b;
235 struct route4_filter *f;
236 unsigned h1, h2;
238 if (!head)
239 return 0;
241 h1 = to_hash(handle);
242 if (h1 > 256)
243 return 0;
245 h2 = from_hash(handle>>16);
246 if (h2 > 32)
247 return 0;
249 if ((b = head->table[h1]) != NULL) {
250 for (f = b->ht[h2]; f; f = f->next)
251 if (f->handle == handle)
252 return (unsigned long)f;
254 return 0;
257 static void route4_put(struct tcf_proto *tp, unsigned long f)
261 static int route4_init(struct tcf_proto *tp)
263 return 0;
266 static inline void
267 route4_delete_filter(struct tcf_proto *tp, struct route4_filter *f)
269 tcf_unbind_filter(tp, &f->res);
270 tcf_exts_destroy(tp, &f->exts);
271 kfree(f);
274 static void route4_destroy(struct tcf_proto *tp)
276 struct route4_head *head = xchg(&tp->root, NULL);
277 int h1, h2;
279 if (head == NULL)
280 return;
282 for (h1=0; h1<=256; h1++) {
283 struct route4_bucket *b;
285 if ((b = head->table[h1]) != NULL) {
286 for (h2=0; h2<=32; h2++) {
287 struct route4_filter *f;
289 while ((f = b->ht[h2]) != NULL) {
290 b->ht[h2] = f->next;
291 route4_delete_filter(tp, f);
294 kfree(b);
297 kfree(head);
300 static int route4_delete(struct tcf_proto *tp, unsigned long arg)
302 struct route4_head *head = (struct route4_head*)tp->root;
303 struct route4_filter **fp, *f = (struct route4_filter*)arg;
304 unsigned h = 0;
305 struct route4_bucket *b;
306 int i;
308 if (!head || !f)
309 return -EINVAL;
311 h = f->handle;
312 b = f->bkt;
314 for (fp = &b->ht[from_hash(h>>16)]; *fp; fp = &(*fp)->next) {
315 if (*fp == f) {
316 tcf_tree_lock(tp);
317 *fp = f->next;
318 tcf_tree_unlock(tp);
320 route4_reset_fastmap(tp->q->dev, head, f->id);
321 route4_delete_filter(tp, f);
323 /* Strip tree */
325 for (i=0; i<=32; i++)
326 if (b->ht[i])
327 return 0;
329 /* OK, session has no flows */
330 tcf_tree_lock(tp);
331 head->table[to_hash(h)] = NULL;
332 tcf_tree_unlock(tp);
334 kfree(b);
335 return 0;
338 return 0;
341 static int route4_set_parms(struct tcf_proto *tp, unsigned long base,
342 struct route4_filter *f, u32 handle, struct route4_head *head,
343 struct rtattr **tb, struct rtattr *est, int new)
345 int err;
346 u32 id = 0, to = 0, nhandle = 0x8000;
347 struct route4_filter *fp;
348 unsigned int h1;
349 struct route4_bucket *b;
350 struct tcf_exts e;
352 err = tcf_exts_validate(tp, tb, est, &e, &route_ext_map);
353 if (err < 0)
354 return err;
356 err = -EINVAL;
357 if (tb[TCA_ROUTE4_CLASSID-1])
358 if (RTA_PAYLOAD(tb[TCA_ROUTE4_CLASSID-1]) < sizeof(u32))
359 goto errout;
361 if (tb[TCA_ROUTE4_TO-1]) {
362 if (new && handle & 0x8000)
363 goto errout;
364 if (RTA_PAYLOAD(tb[TCA_ROUTE4_TO-1]) < sizeof(u32))
365 goto errout;
366 to = *(u32*)RTA_DATA(tb[TCA_ROUTE4_TO-1]);
367 if (to > 0xFF)
368 goto errout;
369 nhandle = to;
372 if (tb[TCA_ROUTE4_FROM-1]) {
373 if (tb[TCA_ROUTE4_IIF-1])
374 goto errout;
375 if (RTA_PAYLOAD(tb[TCA_ROUTE4_FROM-1]) < sizeof(u32))
376 goto errout;
377 id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_FROM-1]);
378 if (id > 0xFF)
379 goto errout;
380 nhandle |= id << 16;
381 } else if (tb[TCA_ROUTE4_IIF-1]) {
382 if (RTA_PAYLOAD(tb[TCA_ROUTE4_IIF-1]) < sizeof(u32))
383 goto errout;
384 id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_IIF-1]);
385 if (id > 0x7FFF)
386 goto errout;
387 nhandle |= (id | 0x8000) << 16;
388 } else
389 nhandle |= 0xFFFF << 16;
391 if (handle && new) {
392 nhandle |= handle & 0x7F00;
393 if (nhandle != handle)
394 goto errout;
397 h1 = to_hash(nhandle);
398 if ((b = head->table[h1]) == NULL) {
399 err = -ENOBUFS;
400 b = kmalloc(sizeof(struct route4_bucket), GFP_KERNEL);
401 if (b == NULL)
402 goto errout;
403 memset(b, 0, sizeof(*b));
405 tcf_tree_lock(tp);
406 head->table[h1] = b;
407 tcf_tree_unlock(tp);
408 } else {
409 unsigned int h2 = from_hash(nhandle >> 16);
410 err = -EEXIST;
411 for (fp = b->ht[h2]; fp; fp = fp->next)
412 if (fp->handle == f->handle)
413 goto errout;
416 tcf_tree_lock(tp);
417 if (tb[TCA_ROUTE4_TO-1])
418 f->id = to;
420 if (tb[TCA_ROUTE4_FROM-1])
421 f->id = to | id<<16;
422 else if (tb[TCA_ROUTE4_IIF-1])
423 f->iif = id;
425 f->handle = nhandle;
426 f->bkt = b;
427 tcf_tree_unlock(tp);
429 if (tb[TCA_ROUTE4_CLASSID-1]) {
430 f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]);
431 tcf_bind_filter(tp, &f->res, base);
434 tcf_exts_change(tp, &f->exts, &e);
436 return 0;
437 errout:
438 tcf_exts_destroy(tp, &e);
439 return err;
442 static int route4_change(struct tcf_proto *tp, unsigned long base,
443 u32 handle,
444 struct rtattr **tca,
445 unsigned long *arg)
447 struct route4_head *head = tp->root;
448 struct route4_filter *f, *f1, **fp;
449 struct route4_bucket *b;
450 struct rtattr *opt = tca[TCA_OPTIONS-1];
451 struct rtattr *tb[TCA_ROUTE4_MAX];
452 unsigned int h, th;
453 u32 old_handle = 0;
454 int err;
456 if (opt == NULL)
457 return handle ? -EINVAL : 0;
459 if (rtattr_parse_nested(tb, TCA_ROUTE4_MAX, opt) < 0)
460 return -EINVAL;
462 if ((f = (struct route4_filter*)*arg) != NULL) {
463 if (f->handle != handle && handle)
464 return -EINVAL;
466 if (f->bkt)
467 old_handle = f->handle;
469 err = route4_set_parms(tp, base, f, handle, head, tb,
470 tca[TCA_RATE-1], 0);
471 if (err < 0)
472 return err;
474 goto reinsert;
477 err = -ENOBUFS;
478 if (head == NULL) {
479 head = kmalloc(sizeof(struct route4_head), GFP_KERNEL);
480 if (head == NULL)
481 goto errout;
482 memset(head, 0, sizeof(struct route4_head));
484 tcf_tree_lock(tp);
485 tp->root = head;
486 tcf_tree_unlock(tp);
489 f = kmalloc(sizeof(struct route4_filter), GFP_KERNEL);
490 if (f == NULL)
491 goto errout;
492 memset(f, 0, sizeof(*f));
494 err = route4_set_parms(tp, base, f, handle, head, tb,
495 tca[TCA_RATE-1], 1);
496 if (err < 0)
497 goto errout;
499 reinsert:
500 h = from_hash(f->handle >> 16);
501 for (fp = &f->bkt->ht[h]; (f1=*fp) != NULL; fp = &f1->next)
502 if (f->handle < f1->handle)
503 break;
505 f->next = f1;
506 tcf_tree_lock(tp);
507 *fp = f;
509 if (old_handle && f->handle != old_handle) {
510 th = to_hash(old_handle);
511 h = from_hash(old_handle >> 16);
512 if ((b = head->table[th]) != NULL) {
513 for (fp = &b->ht[h]; *fp; fp = &(*fp)->next) {
514 if (*fp == f) {
515 *fp = f->next;
516 break;
521 tcf_tree_unlock(tp);
523 route4_reset_fastmap(tp->q->dev, head, f->id);
524 *arg = (unsigned long)f;
525 return 0;
527 errout:
528 kfree(f);
529 return err;
532 static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
534 struct route4_head *head = tp->root;
535 unsigned h, h1;
537 if (head == NULL)
538 arg->stop = 1;
540 if (arg->stop)
541 return;
543 for (h = 0; h <= 256; h++) {
544 struct route4_bucket *b = head->table[h];
546 if (b) {
547 for (h1 = 0; h1 <= 32; h1++) {
548 struct route4_filter *f;
550 for (f = b->ht[h1]; f; f = f->next) {
551 if (arg->count < arg->skip) {
552 arg->count++;
553 continue;
555 if (arg->fn(tp, (unsigned long)f, arg) < 0) {
556 arg->stop = 1;
557 return;
559 arg->count++;
566 static int route4_dump(struct tcf_proto *tp, unsigned long fh,
567 struct sk_buff *skb, struct tcmsg *t)
569 struct route4_filter *f = (struct route4_filter*)fh;
570 unsigned char *b = skb->tail;
571 struct rtattr *rta;
572 u32 id;
574 if (f == NULL)
575 return skb->len;
577 t->tcm_handle = f->handle;
579 rta = (struct rtattr*)b;
580 RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
582 if (!(f->handle&0x8000)) {
583 id = f->id&0xFF;
584 RTA_PUT(skb, TCA_ROUTE4_TO, sizeof(id), &id);
586 if (f->handle&0x80000000) {
587 if ((f->handle>>16) != 0xFFFF)
588 RTA_PUT(skb, TCA_ROUTE4_IIF, sizeof(f->iif), &f->iif);
589 } else {
590 id = f->id>>16;
591 RTA_PUT(skb, TCA_ROUTE4_FROM, sizeof(id), &id);
593 if (f->res.classid)
594 RTA_PUT(skb, TCA_ROUTE4_CLASSID, 4, &f->res.classid);
596 if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0)
597 goto rtattr_failure;
599 rta->rta_len = skb->tail - b;
601 if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0)
602 goto rtattr_failure;
604 return skb->len;
606 rtattr_failure:
607 skb_trim(skb, b - skb->data);
608 return -1;
611 static struct tcf_proto_ops cls_route4_ops = {
612 .next = NULL,
613 .kind = "route",
614 .classify = route4_classify,
615 .init = route4_init,
616 .destroy = route4_destroy,
617 .get = route4_get,
618 .put = route4_put,
619 .change = route4_change,
620 .delete = route4_delete,
621 .walk = route4_walk,
622 .dump = route4_dump,
623 .owner = THIS_MODULE,
626 static int __init init_route4(void)
628 return register_tcf_proto_ops(&cls_route4_ops);
631 static void __exit exit_route4(void)
633 unregister_tcf_proto_ops(&cls_route4_ops);
636 module_init(init_route4)
637 module_exit(exit_route4)
638 MODULE_LICENSE("GPL");