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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sched/] [sch_dsmark.c] - Blame information for rev 1275

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

Line No. Rev Author Line
1 1275 phoenix
/* net/sched/sch_dsmark.c - Differentiated Services field marker */
2
 
3
/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
4
 
5
 
6
#include <linux/config.h>
7
#include <linux/module.h>
8
#include <linux/types.h>
9
#include <linux/string.h>
10
#include <linux/errno.h>
11
#include <linux/skbuff.h>
12
#include <linux/netdevice.h> /* for pkt_sched */
13
#include <linux/rtnetlink.h>
14
#include <net/pkt_sched.h>
15
#include <net/dsfield.h>
16
#include <asm/byteorder.h>
17
 
18
 
19
#if 1 /* control */
20
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
21
#else
22
#define DPRINTK(format,args...)
23
#endif
24
 
25
#if 0 /* data */
26
#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
27
#else
28
#define D2PRINTK(format,args...)
29
#endif
30
 
31
 
32
#define PRIV(sch) ((struct dsmark_qdisc_data *) (sch)->data)
33
 
34
 
35
/*
36
 * classid      class           marking
37
 * -------      -----           -------
38
 *   n/a          0             n/a
39
 *   x:0          1             use entry [0]
40
 *   ...         ...            ...
41
 *   x:y y>0      y+1            use entry [y]
42
 *   ...         ...            ...
43
 * x:indices-1  indices         use entry [indices-1]
44
 *   ...         ...            ...
45
 *   x:y         y+1            use entry [y & (indices-1)]
46
 *   ...         ...            ...
47
 * 0xffff       0x10000         use entry [indices-1]
48
 */
49
 
50
 
51
#define NO_DEFAULT_INDEX        (1 << 16)
52
 
53
struct dsmark_qdisc_data {
54
        struct Qdisc            *q;
55
        struct tcf_proto        *filter_list;
56
        __u8                    *mask;  /* "owns" the array */
57
        __u8                    *value;
58
        __u16                   indices;
59
        __u32                   default_index;  /* index range is 0...0xffff */
60
        int                     set_tc_index;
61
};
62
 
63
 
64
/* ------------------------- Class/flow operations ------------------------- */
65
 
66
 
67
static int dsmark_graft(struct Qdisc *sch,unsigned long arg,
68
    struct Qdisc *new,struct Qdisc **old)
69
{
70
        struct dsmark_qdisc_data *p = PRIV(sch);
71
 
72
        DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new,
73
            old);
74
        if (!new)
75
                new = &noop_qdisc;
76
        sch_tree_lock(sch);
77
        *old = xchg(&p->q,new);
78
        if (*old)
79
                qdisc_reset(*old);
80
        sch->q.qlen = 0;
81
        sch_tree_unlock(sch); /* @@@ move up ? */
82
        return 0;
83
}
84
 
85
 
86
static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg)
87
{
88
        struct dsmark_qdisc_data *p = PRIV(sch);
89
 
90
        return p->q;
91
}
92
 
93
 
94
static unsigned long dsmark_get(struct Qdisc *sch,u32 classid)
95
{
96
        struct dsmark_qdisc_data *p __attribute__((unused)) = PRIV(sch);
97
 
98
        DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid);
99
        return TC_H_MIN(classid)+1;
100
}
101
 
102
 
103
static unsigned long dsmark_bind_filter(struct Qdisc *sch,
104
    unsigned long parent, u32 classid)
105
{
106
        return dsmark_get(sch,classid);
107
}
108
 
109
 
110
static void dsmark_put(struct Qdisc *sch, unsigned long cl)
111
{
112
}
113
 
114
 
115
static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent,
116
    struct rtattr **tca, unsigned long *arg)
117
{
118
        struct dsmark_qdisc_data *p = PRIV(sch);
119
        struct rtattr *opt = tca[TCA_OPTIONS-1];
120
        struct rtattr *tb[TCA_DSMARK_MAX];
121
 
122
        DPRINTK("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x),"
123
            "arg 0x%lx\n",sch,p,classid,parent,*arg);
124
        if (*arg > p->indices)
125
                return -ENOENT;
126
        if (!opt || rtattr_parse(tb, TCA_DSMARK_MAX, RTA_DATA(opt),
127
                                 RTA_PAYLOAD(opt)))
128
                return -EINVAL;
129
        if (tb[TCA_DSMARK_MASK-1]) {
130
                if (!RTA_PAYLOAD(tb[TCA_DSMARK_MASK-1]))
131
                        return -EINVAL;
132
                p->mask[*arg-1] = *(__u8 *) RTA_DATA(tb[TCA_DSMARK_MASK-1]);
133
        }
134
        if (tb[TCA_DSMARK_VALUE-1]) {
135
                if (!RTA_PAYLOAD(tb[TCA_DSMARK_VALUE-1]))
136
                        return -EINVAL;
137
                p->value[*arg-1] = *(__u8 *) RTA_DATA(tb[TCA_DSMARK_VALUE-1]);
138
        }
139
        return 0;
140
}
141
 
142
 
143
static int dsmark_delete(struct Qdisc *sch,unsigned long arg)
144
{
145
        struct dsmark_qdisc_data *p = PRIV(sch);
146
 
147
        if (!arg || arg > p->indices)
148
                return -EINVAL;
149
        p->mask[arg-1] = 0xff;
150
        p->value[arg-1] = 0;
151
        return 0;
152
}
153
 
154
 
155
static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker)
156
{
157
        struct dsmark_qdisc_data *p = PRIV(sch);
158
        int i;
159
 
160
        DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker);
161
        if (walker->stop)
162
                return;
163
        for (i = 0; i < p->indices; i++) {
164
                if (p->mask[i] == 0xff && !p->value[i])
165
                        continue;
166
                if (walker->count >= walker->skip) {
167
                        if (walker->fn(sch, i+1, walker) < 0) {
168
                                walker->stop = 1;
169
                                break;
170
                        }
171
                }
172
                walker->count++;
173
        }
174
}
175
 
176
 
177
static struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl)
178
{
179
        struct dsmark_qdisc_data *p = PRIV(sch);
180
 
181
        return &p->filter_list;
182
}
183
 
184
 
185
/* --------------------------- Qdisc operations ---------------------------- */
186
 
187
 
188
static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
189
{
190
        struct dsmark_qdisc_data *p = PRIV(sch);
191
        struct tcf_result res;
192
        int result;
193
        int ret = NET_XMIT_POLICED;
194
 
195
        D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
196
        if (p->set_tc_index) {
197
                switch (skb->protocol) {
198
                        case __constant_htons(ETH_P_IP):
199
                                skb->tc_index = ipv4_get_dsfield(skb->nh.iph);
200
                                break;
201
                        case __constant_htons(ETH_P_IPV6):
202
                                skb->tc_index = ipv6_get_dsfield(skb->nh.ipv6h);
203
                                break;
204
                        default:
205
                                skb->tc_index = 0;
206
                                break;
207
                };
208
        }
209
        result = TC_POLICE_OK; /* be nice to gcc */
210
        if (TC_H_MAJ(skb->priority) == sch->handle) {
211
                skb->tc_index = TC_H_MIN(skb->priority);
212
        } else {
213
                result = tc_classify(skb,p->filter_list,&res);
214
                D2PRINTK("result %d class 0x%04x\n",result,res.classid);
215
                switch (result) {
216
#ifdef CONFIG_NET_CLS_POLICE
217
                        case TC_POLICE_SHOT:
218
                                kfree_skb(skb);
219
                                break;
220
#if 0
221
                        case TC_POLICE_RECLASSIFY:
222
                                /* FIXME: what to do here ??? */
223
#endif
224
#endif
225
                        case TC_POLICE_OK:
226
                                skb->tc_index = TC_H_MIN(res.classid);
227
                                break;
228
                        case TC_POLICE_UNSPEC:
229
                                /* fall through */
230
                        default:
231
                                if (p->default_index != NO_DEFAULT_INDEX)
232
                                        skb->tc_index = p->default_index;
233
                                break;
234
                };
235
        }
236
        if (
237
#ifdef CONFIG_NET_CLS_POLICE
238
            result == TC_POLICE_SHOT ||
239
#endif
240
 
241
            ((ret = p->q->enqueue(skb,p->q)) != 0)) {
242
                sch->stats.drops++;
243
                return ret;
244
        }
245
        sch->stats.bytes += skb->len;
246
        sch->stats.packets++;
247
        sch->q.qlen++;
248
        return ret;
249
}
250
 
251
 
252
static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
253
{
254
        struct dsmark_qdisc_data *p = PRIV(sch);
255
        struct sk_buff *skb;
256
        int index;
257
 
258
        D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n",sch,p);
259
        skb = p->q->ops->dequeue(p->q);
260
        if (!skb)
261
                return NULL;
262
        sch->q.qlen--;
263
        index = skb->tc_index & (p->indices-1);
264
        D2PRINTK("index %d->%d\n",skb->tc_index,index);
265
        switch (skb->protocol) {
266
                case __constant_htons(ETH_P_IP):
267
                        ipv4_change_dsfield(skb->nh.iph,
268
                            p->mask[index],p->value[index]);
269
                        break;
270
                case __constant_htons(ETH_P_IPV6):
271
                        ipv6_change_dsfield(skb->nh.ipv6h,
272
                            p->mask[index],p->value[index]);
273
                        break;
274
                default:
275
                        /*
276
                         * Only complain if a change was actually attempted.
277
                         * This way, we can send non-IP traffic through dsmark
278
                         * and don't need yet another qdisc as a bypass.
279
                         */
280
                        if (p->mask[index] != 0xff || p->value[index])
281
                                printk(KERN_WARNING "dsmark_dequeue: "
282
                                       "unsupported protocol %d\n",
283
                                       htons(skb->protocol));
284
                        break;
285
        };
286
        return skb;
287
}
288
 
289
 
290
static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch)
291
{
292
        int ret;
293
        struct dsmark_qdisc_data *p = PRIV(sch);
294
 
295
        D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
296
        if ((ret = p->q->ops->requeue(skb, p->q)) == 0) {
297
                sch->q.qlen++;
298
                return 0;
299
        }
300
        sch->stats.drops++;
301
        return ret;
302
}
303
 
304
 
305
static unsigned int dsmark_drop(struct Qdisc *sch)
306
{
307
        struct dsmark_qdisc_data *p = PRIV(sch);
308
        unsigned int len;
309
 
310
        DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch,p);
311
        if (!p->q->ops->drop)
312
                return 0;
313
        if (!(len = p->q->ops->drop(p->q)))
314
                return 0;
315
        sch->q.qlen--;
316
        return len;
317
}
318
 
319
 
320
int dsmark_init(struct Qdisc *sch,struct rtattr *opt)
321
{
322
        struct dsmark_qdisc_data *p = PRIV(sch);
323
        struct rtattr *tb[TCA_DSMARK_MAX];
324
        __u16 tmp;
325
 
326
        DPRINTK("dsmark_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
327
        if (rtattr_parse(tb,TCA_DSMARK_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0 ||
328
            !tb[TCA_DSMARK_INDICES-1] ||
329
            RTA_PAYLOAD(tb[TCA_DSMARK_INDICES-1]) < sizeof(__u16))
330
                return -EINVAL;
331
        memset(p,0,sizeof(*p));
332
        p->filter_list = NULL;
333
        p->indices = *(__u16 *) RTA_DATA(tb[TCA_DSMARK_INDICES-1]);
334
        if (!p->indices)
335
                return -EINVAL;
336
        for (tmp = p->indices; tmp != 1; tmp >>= 1) {
337
                if (tmp & 1)
338
                        return -EINVAL;
339
        }
340
        p->default_index = NO_DEFAULT_INDEX;
341
        if (tb[TCA_DSMARK_DEFAULT_INDEX-1]) {
342
                if (RTA_PAYLOAD(tb[TCA_DSMARK_DEFAULT_INDEX-1]) < sizeof(__u16))
343
                        return -EINVAL;
344
                p->default_index =
345
                    *(__u16 *) RTA_DATA(tb[TCA_DSMARK_DEFAULT_INDEX-1]);
346
        }
347
        p->set_tc_index = !!tb[TCA_DSMARK_SET_TC_INDEX-1];
348
        p->mask = kmalloc(p->indices*2,GFP_KERNEL);
349
        if (!p->mask)
350
                return -ENOMEM;
351
        p->value = p->mask+p->indices;
352
        memset(p->mask,0xff,p->indices);
353
        memset(p->value,0,p->indices);
354
        if (!(p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)))
355
                p->q = &noop_qdisc;
356
        DPRINTK("dsmark_init: qdisc %p\n",&p->q);
357
        MOD_INC_USE_COUNT;
358
        return 0;
359
}
360
 
361
 
362
static void dsmark_reset(struct Qdisc *sch)
363
{
364
        struct dsmark_qdisc_data *p = PRIV(sch);
365
 
366
        DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch,p);
367
        qdisc_reset(p->q);
368
        sch->q.qlen = 0;
369
}
370
 
371
 
372
static void dsmark_destroy(struct Qdisc *sch)
373
{
374
        struct dsmark_qdisc_data *p = PRIV(sch);
375
        struct tcf_proto *tp;
376
 
377
        DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n",sch,p);
378
        while (p->filter_list) {
379
                tp = p->filter_list;
380
                p->filter_list = tp->next;
381
                tcf_destroy(tp);
382
        }
383
        qdisc_destroy(p->q);
384
        p->q = &noop_qdisc;
385
        kfree(p->mask);
386
        MOD_DEC_USE_COUNT;
387
}
388
 
389
 
390
static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
391
    struct sk_buff *skb, struct tcmsg *tcm)
392
{
393
        struct dsmark_qdisc_data *p = PRIV(sch);
394
        unsigned char *b = skb->tail;
395
        struct rtattr *rta;
396
 
397
        DPRINTK("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n",sch,p,cl);
398
        if (!cl || cl > p->indices)
399
                return -EINVAL;
400
        tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle),cl-1);
401
        rta = (struct rtattr *) b;
402
        RTA_PUT(skb,TCA_OPTIONS,0,NULL);
403
        RTA_PUT(skb,TCA_DSMARK_MASK,1,&p->mask[cl-1]);
404
        RTA_PUT(skb,TCA_DSMARK_VALUE,1,&p->value[cl-1]);
405
        rta->rta_len = skb->tail-b;
406
        return skb->len;
407
 
408
rtattr_failure:
409
        skb_trim(skb,b-skb->data);
410
        return -1;
411
}
412
 
413
static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
414
{
415
        struct dsmark_qdisc_data *p = PRIV(sch);
416
        unsigned char *b = skb->tail;
417
        struct rtattr *rta;
418
 
419
        rta = (struct rtattr *) b;
420
        RTA_PUT(skb,TCA_OPTIONS,0,NULL);
421
        RTA_PUT(skb,TCA_DSMARK_INDICES,sizeof(__u16),&p->indices);
422
        if (p->default_index != NO_DEFAULT_INDEX) {
423
                __u16 tmp = p->default_index;
424
 
425
                RTA_PUT(skb,TCA_DSMARK_DEFAULT_INDEX, sizeof(__u16), &tmp);
426
        }
427
        if (p->set_tc_index)
428
                RTA_PUT(skb, TCA_DSMARK_SET_TC_INDEX, 0, NULL);
429
        rta->rta_len = skb->tail-b;
430
        return skb->len;
431
 
432
rtattr_failure:
433
        skb_trim(skb,b-skb->data);
434
        return -1;
435
}
436
 
437
static struct Qdisc_class_ops dsmark_class_ops =
438
{
439
        dsmark_graft,                   /* graft */
440
        dsmark_leaf,                    /* leaf */
441
        dsmark_get,                     /* get */
442
        dsmark_put,                     /* put */
443
        dsmark_change,                  /* change */
444
        dsmark_delete,                  /* delete */
445
        dsmark_walk,                    /* walk */
446
 
447
        dsmark_find_tcf,                /* tcf_chain */
448
        dsmark_bind_filter,             /* bind_tcf */
449
        dsmark_put,                     /* unbind_tcf */
450
 
451
        dsmark_dump_class,              /* dump */
452
};
453
 
454
struct Qdisc_ops dsmark_qdisc_ops =
455
{
456
        NULL,                           /* next */
457
        &dsmark_class_ops,              /* cl_ops */
458
        "dsmark",
459
        sizeof(struct dsmark_qdisc_data),
460
 
461
        dsmark_enqueue,                 /* enqueue */
462
        dsmark_dequeue,                 /* dequeue */
463
        dsmark_requeue,                 /* requeue */
464
        dsmark_drop,                    /* drop */
465
 
466
        dsmark_init,                    /* init */
467
        dsmark_reset,                   /* reset */
468
        dsmark_destroy,                 /* destroy */
469
        NULL,                           /* change */
470
 
471
        dsmark_dump                     /* dump */
472
};
473
 
474
#ifdef MODULE
475
int init_module(void)
476
{
477
        return register_qdisc(&dsmark_qdisc_ops);
478
}
479
 
480
 
481
void cleanup_module(void)
482
{
483
        unregister_qdisc(&dsmark_qdisc_ops);
484
}
485
#endif
486
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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