[SUNGEM]: Make PM of PHYs more reliable (#2)
[linux-2.6] / net / sched / cls_route.c
1 /*
2  * net/sched/cls_route.c        ROUTE4 classifier.
3  *
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.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  */
11
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>
38
39 /*
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"
45  */
46
47 struct route4_fastmap
48 {
49         struct route4_filter    *filter;
50         u32                     id;
51         int                     iif;
52 };
53
54 struct route4_head
55 {
56         struct route4_fastmap   fastmap[16];
57         struct route4_bucket    *table[256+1];
58 };
59
60 struct route4_bucket
61 {
62         /* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */
63         struct route4_filter    *ht[16+16+1];
64 };
65
66 struct route4_filter
67 {
68         struct route4_filter    *next;
69         u32                     id;
70         int                     iif;
71
72         struct tcf_result       res;
73         struct tcf_exts         exts;
74         u32                     handle;
75         struct route4_bucket    *bkt;
76 };
77
78 #define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
79
80 static struct tcf_ext_map route_ext_map = {
81         .police = TCA_ROUTE4_POLICE,
82         .action = TCA_ROUTE4_ACT
83 };
84
85 static __inline__ int route4_fastmap_hash(u32 id, int iif)
86 {
87         return id&0xF;
88 }
89
90 static inline
91 void route4_reset_fastmap(struct net_device *dev, struct route4_head *head, u32 id)
92 {
93         spin_lock_bh(&dev->queue_lock);
94         memset(head->fastmap, 0, sizeof(head->fastmap));
95         spin_unlock_bh(&dev->queue_lock);
96 }
97
98 static void __inline__
99 route4_set_fastmap(struct route4_head *head, u32 id, int iif,
100                    struct route4_filter *f)
101 {
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;
106 }
107
108 static __inline__ int route4_hash_to(u32 id)
109 {
110         return id&0xFF;
111 }
112
113 static __inline__ int route4_hash_from(u32 id)
114 {
115         return (id>>16)&0xF;
116 }
117
118 static __inline__ int route4_hash_iif(int iif)
119 {
120         return 16 + ((iif>>16)&0xF);
121 }
122
123 static __inline__ int route4_hash_wild(void)
124 {
125         return 32;
126 }
127
128 #define ROUTE4_APPLY_RESULT()                                   \
129 {                                                               \
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;                               \
136                 }                                               \
137                 return r;                                       \
138         } else if (!dont_cache)                                 \
139                 route4_set_fastmap(head, id, iif, f);           \
140         return 0;                                               \
141 }
142
143 static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
144                            struct tcf_result *res)
145 {
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;
152
153         if ((dst = skb->dst) == NULL)
154                 goto failure;
155
156         id = dst->tclassid;
157         if (head == NULL)
158                 goto old_method;
159
160         iif = ((struct rtable*)dst)->fl.iif;
161
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;
168
169                 *res = f->res;
170                 return 0;
171         }
172
173         h = route4_hash_to(id);
174
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();
180
181                 for (f = b->ht[route4_hash_iif(iif)]; f; f = f->next)
182                         if (f->iif == iif)
183                                 ROUTE4_APPLY_RESULT();
184
185                 for (f = b->ht[route4_hash_wild()]; f; f = f->next)
186                         ROUTE4_APPLY_RESULT();
187
188         }
189         if (h < 256) {
190                 h = 256;
191                 id &= ~0xFFFF;
192                 goto restart;
193         }
194
195         if (!dont_cache)
196                 route4_set_fastmap(head, id, iif, ROUTE4_FAILURE);
197 failure:
198         return -1;
199
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;
206         }
207         return -1;
208 }
209
210 static inline u32 to_hash(u32 id)
211 {
212         u32 h = id&0xFF;
213         if (id&0x8000)
214                 h += 256;
215         return h;
216 }
217
218 static inline u32 from_hash(u32 id)
219 {
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;
227         }
228         return 16 + (id&0xF);
229 }
230
231 static unsigned long route4_get(struct tcf_proto *tp, u32 handle)
232 {
233         struct route4_head *head = (struct route4_head*)tp->root;
234         struct route4_bucket *b;
235         struct route4_filter *f;
236         unsigned h1, h2;
237
238         if (!head)
239                 return 0;
240
241         h1 = to_hash(handle);
242         if (h1 > 256)
243                 return 0;
244
245         h2 = from_hash(handle>>16);
246         if (h2 > 32)
247                 return 0;
248
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;
253         }
254         return 0;
255 }
256
257 static void route4_put(struct tcf_proto *tp, unsigned long f)
258 {
259 }
260
261 static int route4_init(struct tcf_proto *tp)
262 {
263         return 0;
264 }
265
266 static inline void
267 route4_delete_filter(struct tcf_proto *tp, struct route4_filter *f)
268 {
269         tcf_unbind_filter(tp, &f->res);
270         tcf_exts_destroy(tp, &f->exts);
271         kfree(f);
272 }
273
274 static void route4_destroy(struct tcf_proto *tp)
275 {
276         struct route4_head *head = xchg(&tp->root, NULL);
277         int h1, h2;
278
279         if (head == NULL)
280                 return;
281
282         for (h1=0; h1<=256; h1++) {
283                 struct route4_bucket *b;
284
285                 if ((b = head->table[h1]) != NULL) {
286                         for (h2=0; h2<=32; h2++) {
287                                 struct route4_filter *f;
288
289                                 while ((f = b->ht[h2]) != NULL) {
290                                         b->ht[h2] = f->next;
291                                         route4_delete_filter(tp, f);
292                                 }
293                         }
294                         kfree(b);
295                 }
296         }
297         kfree(head);
298 }
299
300 static int route4_delete(struct tcf_proto *tp, unsigned long arg)
301 {
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;
307
308         if (!head || !f)
309                 return -EINVAL;
310
311         h = f->handle;
312         b = f->bkt;
313
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);
319
320                         route4_reset_fastmap(tp->q->dev, head, f->id);
321                         route4_delete_filter(tp, f);
322
323                         /* Strip tree */
324
325                         for (i=0; i<=32; i++)
326                                 if (b->ht[i])
327                                         return 0;
328
329                         /* OK, session has no flows */
330                         tcf_tree_lock(tp);
331                         head->table[to_hash(h)] = NULL;
332                         tcf_tree_unlock(tp);
333
334                         kfree(b);
335                         return 0;
336                 }
337         }
338         return 0;
339 }
340
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)
344 {
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;
351
352         err = tcf_exts_validate(tp, tb, est, &e, &route_ext_map);
353         if (err < 0)
354                 return err;
355
356         err = -EINVAL;
357         if (tb[TCA_ROUTE4_CLASSID-1])
358                 if (RTA_PAYLOAD(tb[TCA_ROUTE4_CLASSID-1]) < sizeof(u32))
359                         goto errout;
360
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;
370         }
371
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;
390
391         if (handle && new) {
392                 nhandle |= handle & 0x7F00;
393                 if (nhandle != handle)
394                         goto errout;
395         }
396
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));
404
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;
414         }
415
416         tcf_tree_lock(tp);
417         if (tb[TCA_ROUTE4_TO-1])
418                 f->id = to;
419
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;
424
425         f->handle = nhandle;
426         f->bkt = b;
427         tcf_tree_unlock(tp);
428
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);
432         }
433
434         tcf_exts_change(tp, &f->exts, &e);
435
436         return 0;
437 errout:
438         tcf_exts_destroy(tp, &e);
439         return err;
440 }
441
442 static int route4_change(struct tcf_proto *tp, unsigned long base,
443                        u32 handle,
444                        struct rtattr **tca,
445                        unsigned long *arg)
446 {
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;
455
456         if (opt == NULL)
457                 return handle ? -EINVAL : 0;
458
459         if (rtattr_parse_nested(tb, TCA_ROUTE4_MAX, opt) < 0)
460                 return -EINVAL;
461
462         if ((f = (struct route4_filter*)*arg) != NULL) {
463                 if (f->handle != handle && handle)
464                         return -EINVAL;
465
466                 if (f->bkt)
467                         old_handle = f->handle;
468
469                 err = route4_set_parms(tp, base, f, handle, head, tb,
470                         tca[TCA_RATE-1], 0);
471                 if (err < 0)
472                         return err;
473
474                 goto reinsert;
475         }
476
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));
483
484                 tcf_tree_lock(tp);
485                 tp->root = head;
486                 tcf_tree_unlock(tp);
487         }
488
489         f = kmalloc(sizeof(struct route4_filter), GFP_KERNEL);
490         if (f == NULL)
491                 goto errout;
492         memset(f, 0, sizeof(*f));
493
494         err = route4_set_parms(tp, base, f, handle, head, tb,
495                 tca[TCA_RATE-1], 1);
496         if (err < 0)
497                 goto errout;
498
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;
504
505         f->next = f1;
506         tcf_tree_lock(tp);
507         *fp = f;
508
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;
517                                 }
518                         }
519                 }
520         }
521         tcf_tree_unlock(tp);
522
523         route4_reset_fastmap(tp->q->dev, head, f->id);
524         *arg = (unsigned long)f;
525         return 0;
526
527 errout:
528         kfree(f);
529         return err;
530 }
531
532 static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
533 {
534         struct route4_head *head = tp->root;
535         unsigned h, h1;
536
537         if (head == NULL)
538                 arg->stop = 1;
539
540         if (arg->stop)
541                 return;
542
543         for (h = 0; h <= 256; h++) {
544                 struct route4_bucket *b = head->table[h];
545
546                 if (b) {
547                         for (h1 = 0; h1 <= 32; h1++) {
548                                 struct route4_filter *f;
549
550                                 for (f = b->ht[h1]; f; f = f->next) {
551                                         if (arg->count < arg->skip) {
552                                                 arg->count++;
553                                                 continue;
554                                         }
555                                         if (arg->fn(tp, (unsigned long)f, arg) < 0) {
556                                                 arg->stop = 1;
557                                                 return;
558                                         }
559                                         arg->count++;
560                                 }
561                         }
562                 }
563         }
564 }
565
566 static int route4_dump(struct tcf_proto *tp, unsigned long fh,
567                        struct sk_buff *skb, struct tcmsg *t)
568 {
569         struct route4_filter *f = (struct route4_filter*)fh;
570         unsigned char    *b = skb->tail;
571         struct rtattr *rta;
572         u32 id;
573
574         if (f == NULL)
575                 return skb->len;
576
577         t->tcm_handle = f->handle;
578
579         rta = (struct rtattr*)b;
580         RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
581
582         if (!(f->handle&0x8000)) {
583                 id = f->id&0xFF;
584                 RTA_PUT(skb, TCA_ROUTE4_TO, sizeof(id), &id);
585         }
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);
592         }
593         if (f->res.classid)
594                 RTA_PUT(skb, TCA_ROUTE4_CLASSID, 4, &f->res.classid);
595
596         if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0)
597                 goto rtattr_failure;
598
599         rta->rta_len = skb->tail - b;
600
601         if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0)
602                 goto rtattr_failure;
603
604         return skb->len;
605
606 rtattr_failure:
607         skb_trim(skb, b - skb->data);
608         return -1;
609 }
610
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,
624 };
625
626 static int __init init_route4(void)
627 {
628         return register_tcf_proto_ops(&cls_route4_ops);
629 }
630
631 static void __exit exit_route4(void)
632 {
633         unregister_tcf_proto_ops(&cls_route4_ops);
634 }
635
636 module_init(init_route4)
637 module_exit(exit_route4)
638 MODULE_LICENSE("GPL");