OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [net/] [sched/] [cls_tcindex.c] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * net/sched/cls_tcindex.c      Packet classifier for skb->tc_index
3
 *
4
 * Written 1998,1999 by Werner Almesberger, EPFL ICA
5
 */
6
 
7
#include <linux/module.h>
8
#include <linux/types.h>
9
#include <linux/kernel.h>
10
#include <linux/skbuff.h>
11
#include <linux/errno.h>
12
#include <net/act_api.h>
13
#include <net/netlink.h>
14
#include <net/pkt_cls.h>
15
 
16
 
17
/*
18
 * Not quite sure if we need all the xchgs Alexey uses when accessing things.
19
 * Can always add them later ... :)
20
 */
21
 
22
/*
23
 * Passing parameters to the root seems to be done more awkwardly than really
24
 * necessary. At least, u32 doesn't seem to use such dirty hacks. To be
25
 * verified. FIXME.
26
 */
27
 
28
#define PERFECT_HASH_THRESHOLD  64      /* use perfect hash if not bigger */
29
#define DEFAULT_HASH_SIZE       64      /* optimized for diffserv */
30
 
31
 
32
#if 1 /* control */
33
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
34
#else
35
#define DPRINTK(format,args...)
36
#endif
37
 
38
#if 0 /* data */
39
#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
40
#else
41
#define D2PRINTK(format,args...)
42
#endif
43
 
44
 
45
#define PRIV(tp)        ((struct tcindex_data *) (tp)->root)
46
 
47
 
48
struct tcindex_filter_result {
49
        struct tcf_exts         exts;
50
        struct tcf_result       res;
51
};
52
 
53
struct tcindex_filter {
54
        u16 key;
55
        struct tcindex_filter_result result;
56
        struct tcindex_filter *next;
57
};
58
 
59
 
60
struct tcindex_data {
61
        struct tcindex_filter_result *perfect; /* perfect hash; NULL if none */
62
        struct tcindex_filter **h; /* imperfect hash; only used if !perfect;
63
                                      NULL if unused */
64
        u16 mask;               /* AND key with mask */
65
        int shift;              /* shift ANDed key to the right */
66
        int hash;               /* hash table size; 0 if undefined */
67
        int alloc_hash;         /* allocated size */
68
        int fall_through;       /* 0: only classify if explicit match */
69
};
70
 
71
static struct tcf_ext_map tcindex_ext_map = {
72
        .police = TCA_TCINDEX_POLICE,
73
        .action = TCA_TCINDEX_ACT
74
};
75
 
76
static inline int
77
tcindex_filter_is_set(struct tcindex_filter_result *r)
78
{
79
        return tcf_exts_is_predicative(&r->exts) || r->res.classid;
80
}
81
 
82
static struct tcindex_filter_result *
83
tcindex_lookup(struct tcindex_data *p, u16 key)
84
{
85
        struct tcindex_filter *f;
86
 
87
        if (p->perfect)
88
                return tcindex_filter_is_set(p->perfect + key) ?
89
                        p->perfect + key : NULL;
90
        else if (p->h) {
91
                for (f = p->h[key % p->hash]; f; f = f->next)
92
                        if (f->key == key)
93
                                return &f->result;
94
        }
95
 
96
        return NULL;
97
}
98
 
99
 
100
static int tcindex_classify(struct sk_buff *skb, struct tcf_proto *tp,
101
                            struct tcf_result *res)
102
{
103
        struct tcindex_data *p = PRIV(tp);
104
        struct tcindex_filter_result *f;
105
        int key = (skb->tc_index & p->mask) >> p->shift;
106
 
107
        D2PRINTK("tcindex_classify(skb %p,tp %p,res %p),p %p\n",skb,tp,res,p);
108
 
109
        f = tcindex_lookup(p, key);
110
        if (!f) {
111
                if (!p->fall_through)
112
                        return -1;
113
                res->classid = TC_H_MAKE(TC_H_MAJ(tp->q->handle), key);
114
                res->class = 0;
115
                D2PRINTK("alg 0x%x\n",res->classid);
116
                return 0;
117
        }
118
        *res = f->res;
119
        D2PRINTK("map 0x%x\n",res->classid);
120
 
121
        return tcf_exts_exec(skb, &f->exts, res);
122
}
123
 
124
 
125
static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle)
126
{
127
        struct tcindex_data *p = PRIV(tp);
128
        struct tcindex_filter_result *r;
129
 
130
        DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle);
131
        if (p->perfect && handle >= p->alloc_hash)
132
                return 0;
133
        r = tcindex_lookup(p, handle);
134
        return r && tcindex_filter_is_set(r) ? (unsigned long) r : 0UL;
135
}
136
 
137
 
138
static void tcindex_put(struct tcf_proto *tp, unsigned long f)
139
{
140
        DPRINTK("tcindex_put(tp %p,f 0x%lx)\n",tp,f);
141
}
142
 
143
 
144
static int tcindex_init(struct tcf_proto *tp)
145
{
146
        struct tcindex_data *p;
147
 
148
        DPRINTK("tcindex_init(tp %p)\n",tp);
149
        p = kzalloc(sizeof(struct tcindex_data),GFP_KERNEL);
150
        if (!p)
151
                return -ENOMEM;
152
 
153
        p->mask = 0xffff;
154
        p->hash = DEFAULT_HASH_SIZE;
155
        p->fall_through = 1;
156
 
157
        tp->root = p;
158
        return 0;
159
}
160
 
161
 
162
static int
163
__tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock)
164
{
165
        struct tcindex_data *p = PRIV(tp);
166
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
167
        struct tcindex_filter *f = NULL;
168
 
169
        DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f);
170
        if (p->perfect) {
171
                if (!r->res.class)
172
                        return -ENOENT;
173
        } else {
174
                int i;
175
                struct tcindex_filter **walk = NULL;
176
 
177
                for (i = 0; i < p->hash; i++)
178
                        for (walk = p->h+i; *walk; walk = &(*walk)->next)
179
                                if (&(*walk)->result == r)
180
                                        goto found;
181
                return -ENOENT;
182
 
183
found:
184
                f = *walk;
185
                if (lock)
186
                        tcf_tree_lock(tp);
187
                *walk = f->next;
188
                if (lock)
189
                        tcf_tree_unlock(tp);
190
        }
191
        tcf_unbind_filter(tp, &r->res);
192
        tcf_exts_destroy(tp, &r->exts);
193
        kfree(f);
194
        return 0;
195
}
196
 
197
static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
198
{
199
        return __tcindex_delete(tp, arg, 1);
200
}
201
 
202
static inline int
203
valid_perfect_hash(struct tcindex_data *p)
204
{
205
        return  p->hash > (p->mask >> p->shift);
206
}
207
 
208
static int
209
tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle,
210
                  struct tcindex_data *p, struct tcindex_filter_result *r,
211
                  struct rtattr **tb, struct rtattr *est)
212
{
213
        int err, balloc = 0;
214
        struct tcindex_filter_result new_filter_result, *old_r = r;
215
        struct tcindex_filter_result cr;
216
        struct tcindex_data cp;
217
        struct tcindex_filter *f = NULL; /* make gcc behave */
218
        struct tcf_exts e;
219
 
220
        err = tcf_exts_validate(tp, tb, est, &e, &tcindex_ext_map);
221
        if (err < 0)
222
                return err;
223
 
224
        memcpy(&cp, p, sizeof(cp));
225
        memset(&new_filter_result, 0, sizeof(new_filter_result));
226
 
227
        if (old_r)
228
                memcpy(&cr, r, sizeof(cr));
229
        else
230
                memset(&cr, 0, sizeof(cr));
231
 
232
        err = -EINVAL;
233
        if (tb[TCA_TCINDEX_HASH-1]) {
234
                if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH-1]) < sizeof(u32))
235
                        goto errout;
236
                cp.hash = *(u32 *) RTA_DATA(tb[TCA_TCINDEX_HASH-1]);
237
        }
238
 
239
        if (tb[TCA_TCINDEX_MASK-1]) {
240
                if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK-1]) < sizeof(u16))
241
                        goto errout;
242
                cp.mask = *(u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]);
243
        }
244
 
245
        if (tb[TCA_TCINDEX_SHIFT-1]) {
246
                if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(int))
247
                        goto errout;
248
                cp.shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]);
249
        }
250
 
251
        err = -EBUSY;
252
        /* Hash already allocated, make sure that we still meet the
253
         * requirements for the allocated hash.
254
         */
255
        if (cp.perfect) {
256
                if (!valid_perfect_hash(&cp) ||
257
                    cp.hash > cp.alloc_hash)
258
                        goto errout;
259
        } else if (cp.h && cp.hash != cp.alloc_hash)
260
                goto errout;
261
 
262
        err = -EINVAL;
263
        if (tb[TCA_TCINDEX_FALL_THROUGH-1]) {
264
                if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(u32))
265
                        goto errout;
266
                cp.fall_through =
267
                        *(u32 *) RTA_DATA(tb[TCA_TCINDEX_FALL_THROUGH-1]);
268
        }
269
 
270
        if (!cp.hash) {
271
                /* Hash not specified, use perfect hash if the upper limit
272
                 * of the hashing index is below the threshold.
273
                 */
274
                if ((cp.mask >> cp.shift) < PERFECT_HASH_THRESHOLD)
275
                        cp.hash = (cp.mask >> cp.shift)+1;
276
                else
277
                        cp.hash = DEFAULT_HASH_SIZE;
278
        }
279
 
280
        if (!cp.perfect && !cp.h)
281
                cp.alloc_hash = cp.hash;
282
 
283
        /* Note: this could be as restrictive as if (handle & ~(mask >> shift))
284
         * but then, we'd fail handles that may become valid after some future
285
         * mask change. While this is extremely unlikely to ever matter,
286
         * the check below is safer (and also more backwards-compatible).
287
         */
288
        if (cp.perfect || valid_perfect_hash(&cp))
289
                if (handle >= cp.alloc_hash)
290
                        goto errout;
291
 
292
 
293
        err = -ENOMEM;
294
        if (!cp.perfect && !cp.h) {
295
                if (valid_perfect_hash(&cp)) {
296
                        cp.perfect = kcalloc(cp.hash, sizeof(*r), GFP_KERNEL);
297
                        if (!cp.perfect)
298
                                goto errout;
299
                        balloc = 1;
300
                } else {
301
                        cp.h = kcalloc(cp.hash, sizeof(f), GFP_KERNEL);
302
                        if (!cp.h)
303
                                goto errout;
304
                        balloc = 2;
305
                }
306
        }
307
 
308
        if (cp.perfect)
309
                r = cp.perfect + handle;
310
        else
311
                r = tcindex_lookup(&cp, handle) ? : &new_filter_result;
312
 
313
        if (r == &new_filter_result) {
314
                f = kzalloc(sizeof(*f), GFP_KERNEL);
315
                if (!f)
316
                        goto errout_alloc;
317
        }
318
 
319
        if (tb[TCA_TCINDEX_CLASSID-1]) {
320
                cr.res.classid = *(u32 *) RTA_DATA(tb[TCA_TCINDEX_CLASSID-1]);
321
                tcf_bind_filter(tp, &cr.res, base);
322
        }
323
 
324
        tcf_exts_change(tp, &cr.exts, &e);
325
 
326
        tcf_tree_lock(tp);
327
        if (old_r && old_r != r)
328
                memset(old_r, 0, sizeof(*old_r));
329
 
330
        memcpy(p, &cp, sizeof(cp));
331
        memcpy(r, &cr, sizeof(cr));
332
 
333
        if (r == &new_filter_result) {
334
                struct tcindex_filter **fp;
335
 
336
                f->key = handle;
337
                f->result = new_filter_result;
338
                f->next = NULL;
339
                for (fp = p->h+(handle % p->hash); *fp; fp = &(*fp)->next)
340
                        /* nothing */;
341
                *fp = f;
342
        }
343
        tcf_tree_unlock(tp);
344
 
345
        return 0;
346
 
347
errout_alloc:
348
        if (balloc == 1)
349
                kfree(cp.perfect);
350
        else if (balloc == 2)
351
                kfree(cp.h);
352
errout:
353
        tcf_exts_destroy(tp, &e);
354
        return err;
355
}
356
 
357
static int
358
tcindex_change(struct tcf_proto *tp, unsigned long base, u32 handle,
359
               struct rtattr **tca, unsigned long *arg)
360
{
361
        struct rtattr *opt = tca[TCA_OPTIONS-1];
362
        struct rtattr *tb[TCA_TCINDEX_MAX];
363
        struct tcindex_data *p = PRIV(tp);
364
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg;
365
 
366
        DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
367
            "p %p,r %p,*arg 0x%lx\n",
368
            tp, handle, tca, arg, opt, p, r, arg ? *arg : 0L);
369
 
370
        if (!opt)
371
                return 0;
372
 
373
        if (rtattr_parse_nested(tb, TCA_TCINDEX_MAX, opt) < 0)
374
                return -EINVAL;
375
 
376
        return tcindex_set_parms(tp, base, handle, p, r, tb, tca[TCA_RATE-1]);
377
}
378
 
379
 
380
static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
381
{
382
        struct tcindex_data *p = PRIV(tp);
383
        struct tcindex_filter *f,*next;
384
        int i;
385
 
386
        DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p);
387
        if (p->perfect) {
388
                for (i = 0; i < p->hash; i++) {
389
                        if (!p->perfect[i].res.class)
390
                                continue;
391
                        if (walker->count >= walker->skip) {
392
                                if (walker->fn(tp,
393
                                    (unsigned long) (p->perfect+i), walker)
394
                                     < 0) {
395
                                        walker->stop = 1;
396
                                        return;
397
                                }
398
                        }
399
                        walker->count++;
400
                }
401
        }
402
        if (!p->h)
403
                return;
404
        for (i = 0; i < p->hash; i++) {
405
                for (f = p->h[i]; f; f = next) {
406
                        next = f->next;
407
                        if (walker->count >= walker->skip) {
408
                                if (walker->fn(tp,(unsigned long) &f->result,
409
                                    walker) < 0) {
410
                                        walker->stop = 1;
411
                                        return;
412
                                }
413
                        }
414
                        walker->count++;
415
                }
416
        }
417
}
418
 
419
 
420
static int tcindex_destroy_element(struct tcf_proto *tp,
421
    unsigned long arg, struct tcf_walker *walker)
422
{
423
        return __tcindex_delete(tp, arg, 0);
424
}
425
 
426
 
427
static void tcindex_destroy(struct tcf_proto *tp)
428
{
429
        struct tcindex_data *p = PRIV(tp);
430
        struct tcf_walker walker;
431
 
432
        DPRINTK("tcindex_destroy(tp %p),p %p\n",tp,p);
433
        walker.count = 0;
434
        walker.skip = 0;
435
        walker.fn = &tcindex_destroy_element;
436
        tcindex_walk(tp,&walker);
437
        kfree(p->perfect);
438
        kfree(p->h);
439
        kfree(p);
440
        tp->root = NULL;
441
}
442
 
443
 
444
static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
445
    struct sk_buff *skb, struct tcmsg *t)
446
{
447
        struct tcindex_data *p = PRIV(tp);
448
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh;
449
        unsigned char *b = skb_tail_pointer(skb);
450
        struct rtattr *rta;
451
 
452
        DPRINTK("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %p\n",
453
            tp,fh,skb,t,p,r,b);
454
        DPRINTK("p->perfect %p p->h %p\n",p->perfect,p->h);
455
        rta = (struct rtattr *) b;
456
        RTA_PUT(skb,TCA_OPTIONS,0,NULL);
457
        if (!fh) {
458
                t->tcm_handle = ~0; /* whatever ... */
459
                RTA_PUT(skb,TCA_TCINDEX_HASH,sizeof(p->hash),&p->hash);
460
                RTA_PUT(skb,TCA_TCINDEX_MASK,sizeof(p->mask),&p->mask);
461
                RTA_PUT(skb,TCA_TCINDEX_SHIFT,sizeof(p->shift),&p->shift);
462
                RTA_PUT(skb,TCA_TCINDEX_FALL_THROUGH,sizeof(p->fall_through),
463
                    &p->fall_through);
464
                rta->rta_len = skb_tail_pointer(skb) - b;
465
        } else {
466
                if (p->perfect) {
467
                        t->tcm_handle = r-p->perfect;
468
                } else {
469
                        struct tcindex_filter *f;
470
                        int i;
471
 
472
                        t->tcm_handle = 0;
473
                        for (i = 0; !t->tcm_handle && i < p->hash; i++) {
474
                                for (f = p->h[i]; !t->tcm_handle && f;
475
                                     f = f->next) {
476
                                        if (&f->result == r)
477
                                                t->tcm_handle = f->key;
478
                                }
479
                        }
480
                }
481
                DPRINTK("handle = %d\n",t->tcm_handle);
482
                if (r->res.class)
483
                        RTA_PUT(skb, TCA_TCINDEX_CLASSID, 4, &r->res.classid);
484
 
485
                if (tcf_exts_dump(skb, &r->exts, &tcindex_ext_map) < 0)
486
                        goto rtattr_failure;
487
                rta->rta_len = skb_tail_pointer(skb) - b;
488
 
489
                if (tcf_exts_dump_stats(skb, &r->exts, &tcindex_ext_map) < 0)
490
                        goto rtattr_failure;
491
        }
492
 
493
        return skb->len;
494
 
495
rtattr_failure:
496
        nlmsg_trim(skb, b);
497
        return -1;
498
}
499
 
500
static struct tcf_proto_ops cls_tcindex_ops = {
501
        .next           =       NULL,
502
        .kind           =       "tcindex",
503
        .classify       =       tcindex_classify,
504
        .init           =       tcindex_init,
505
        .destroy        =       tcindex_destroy,
506
        .get            =       tcindex_get,
507
        .put            =       tcindex_put,
508
        .change         =       tcindex_change,
509
        .delete         =       tcindex_delete,
510
        .walk           =       tcindex_walk,
511
        .dump           =       tcindex_dump,
512
        .owner          =       THIS_MODULE,
513
};
514
 
515
static int __init init_tcindex(void)
516
{
517
        return register_tcf_proto_ops(&cls_tcindex_ops);
518
}
519
 
520
static void __exit exit_tcindex(void)
521
{
522
        unregister_tcf_proto_ops(&cls_tcindex_ops);
523
}
524
 
525
module_init(init_tcindex)
526
module_exit(exit_tcindex)
527
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.