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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * net/sched/cls_fw.c   Classifier mapping ipchains' fwmark to traffic class.
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
 * Changes:
12
 * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_walk off by one
13
 * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_delete killed all the filter (and kernel).
14
 */
15
 
16
#include <linux/config.h>
17
#include <linux/module.h>
18
#include <asm/uaccess.h>
19
#include <asm/system.h>
20
#include <asm/bitops.h>
21
#include <linux/types.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/string.h>
25
#include <linux/mm.h>
26
#include <linux/socket.h>
27
#include <linux/sockios.h>
28
#include <linux/in.h>
29
#include <linux/errno.h>
30
#include <linux/interrupt.h>
31
#include <linux/if_ether.h>
32
#include <linux/inet.h>
33
#include <linux/netdevice.h>
34
#include <linux/etherdevice.h>
35
#include <linux/notifier.h>
36
#include <linux/netfilter.h>
37
#include <net/ip.h>
38
#include <net/route.h>
39
#include <linux/skbuff.h>
40
#include <net/sock.h>
41
#include <net/pkt_sched.h>
42
 
43
struct fw_head
44
{
45
        struct fw_filter *ht[256];
46
};
47
 
48
struct fw_filter
49
{
50
        struct fw_filter        *next;
51
        u32                     id;
52
        struct tcf_result       res;
53
#ifdef CONFIG_NET_CLS_POLICE
54
        struct tcf_police       *police;
55
#endif
56
};
57
 
58
static __inline__ int fw_hash(u32 handle)
59
{
60
        return handle&0xFF;
61
}
62
 
63
static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
64
                          struct tcf_result *res)
65
{
66
        struct fw_head *head = (struct fw_head*)tp->root;
67
        struct fw_filter *f;
68
#ifdef CONFIG_NETFILTER
69
        u32 id = skb->nfmark;
70
#else
71
        u32 id = 0;
72
#endif
73
 
74
        if (head == NULL)
75
                goto old_method;
76
 
77
        for (f=head->ht[fw_hash(id)]; f; f=f->next) {
78
                if (f->id == id) {
79
                        *res = f->res;
80
#ifdef CONFIG_NET_CLS_POLICE
81
                        if (f->police)
82
                                return tcf_police(skb, f->police);
83
#endif
84
                        return 0;
85
                }
86
        }
87
        return -1;
88
 
89
old_method:
90
        if (id && (TC_H_MAJ(id) == 0 ||
91
                     !(TC_H_MAJ(id^tp->q->handle)))) {
92
                res->classid = id;
93
                res->class = 0;
94
                return 0;
95
        }
96
        return -1;
97
}
98
 
99
static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
100
{
101
        struct fw_head *head = (struct fw_head*)tp->root;
102
        struct fw_filter *f;
103
 
104
        if (head == NULL)
105
                return 0;
106
 
107
        for (f=head->ht[fw_hash(handle)]; f; f=f->next) {
108
                if (f->id == handle)
109
                        return (unsigned long)f;
110
        }
111
        return 0;
112
}
113
 
114
static void fw_put(struct tcf_proto *tp, unsigned long f)
115
{
116
}
117
 
118
static int fw_init(struct tcf_proto *tp)
119
{
120
        MOD_INC_USE_COUNT;
121
        return 0;
122
}
123
 
124
static void fw_destroy(struct tcf_proto *tp)
125
{
126
        struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);
127
        struct fw_filter *f;
128
        int h;
129
 
130
        if (head == NULL) {
131
                MOD_DEC_USE_COUNT;
132
                return;
133
        }
134
 
135
        for (h=0; h<256; h++) {
136
                while ((f=head->ht[h]) != NULL) {
137
                        unsigned long cl;
138
                        head->ht[h] = f->next;
139
 
140
                        if ((cl = __cls_set_class(&f->res.class, 0)) != 0)
141
                                tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
142
#ifdef CONFIG_NET_CLS_POLICE
143
                        tcf_police_release(f->police);
144
#endif
145
                        kfree(f);
146
                }
147
        }
148
        kfree(head);
149
        MOD_DEC_USE_COUNT;
150
}
151
 
152
static int fw_delete(struct tcf_proto *tp, unsigned long arg)
153
{
154
        struct fw_head *head = (struct fw_head*)tp->root;
155
        struct fw_filter *f = (struct fw_filter*)arg;
156
        struct fw_filter **fp;
157
 
158
        if (head == NULL || f == NULL)
159
                return -EINVAL;
160
 
161
        for (fp=&head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {
162
                if (*fp == f) {
163
                        unsigned long cl;
164
 
165
                        tcf_tree_lock(tp);
166
                        *fp = f->next;
167
                        tcf_tree_unlock(tp);
168
 
169
                        if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0)
170
                                tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
171
#ifdef CONFIG_NET_CLS_POLICE
172
                        tcf_police_release(f->police);
173
#endif
174
                        kfree(f);
175
                        return 0;
176
                }
177
        }
178
        return -EINVAL;
179
}
180
 
181
static int fw_change(struct tcf_proto *tp, unsigned long base,
182
                     u32 handle,
183
                     struct rtattr **tca,
184
                     unsigned long *arg)
185
{
186
        struct fw_head *head = (struct fw_head*)tp->root;
187
        struct fw_filter *f;
188
        struct rtattr *opt = tca[TCA_OPTIONS-1];
189
        struct rtattr *tb[TCA_FW_MAX];
190
        int err;
191
 
192
        if (!opt)
193
                return handle ? -EINVAL : 0;
194
 
195
        if (rtattr_parse(tb, TCA_FW_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)) < 0)
196
                return -EINVAL;
197
 
198
        if ((f = (struct fw_filter*)*arg) != NULL) {
199
                /* Node exists: adjust only classid */
200
 
201
                if (f->id != handle && handle)
202
                        return -EINVAL;
203
                if (tb[TCA_FW_CLASSID-1]) {
204
                        unsigned long cl;
205
 
206
                        f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
207
                        cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid);
208
                        cl = cls_set_class(tp, &f->res.class, cl);
209
                        if (cl)
210
                                tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
211
                }
212
#ifdef CONFIG_NET_CLS_POLICE
213
                if (tb[TCA_FW_POLICE-1]) {
214
                        struct tcf_police *police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
215
 
216
                        tcf_tree_lock(tp);
217
                        police = xchg(&f->police, police);
218
                        tcf_tree_unlock(tp);
219
 
220
                        tcf_police_release(police);
221
                }
222
#endif
223
                return 0;
224
        }
225
 
226
        if (!handle)
227
                return -EINVAL;
228
 
229
        if (head == NULL) {
230
                head = kmalloc(sizeof(struct fw_head), GFP_KERNEL);
231
                if (head == NULL)
232
                        return -ENOBUFS;
233
                memset(head, 0, sizeof(*head));
234
 
235
                tcf_tree_lock(tp);
236
                tp->root = head;
237
                tcf_tree_unlock(tp);
238
        }
239
 
240
        f = kmalloc(sizeof(struct fw_filter), GFP_KERNEL);
241
        if (f == NULL)
242
                return -ENOBUFS;
243
        memset(f, 0, sizeof(*f));
244
 
245
        f->id = handle;
246
 
247
        if (tb[TCA_FW_CLASSID-1]) {
248
                err = -EINVAL;
249
                if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != 4)
250
                        goto errout;
251
                f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
252
                cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
253
        }
254
 
255
#ifdef CONFIG_NET_CLS_POLICE
256
        if (tb[TCA_FW_POLICE-1])
257
                f->police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
258
#endif
259
 
260
        f->next = head->ht[fw_hash(handle)];
261
        tcf_tree_lock(tp);
262
        head->ht[fw_hash(handle)] = f;
263
        tcf_tree_unlock(tp);
264
 
265
        *arg = (unsigned long)f;
266
        return 0;
267
 
268
errout:
269
        if (f)
270
                kfree(f);
271
        return err;
272
}
273
 
274
static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
275
{
276
        struct fw_head *head = (struct fw_head*)tp->root;
277
        int h;
278
 
279
        if (head == NULL)
280
                arg->stop = 1;
281
 
282
        if (arg->stop)
283
                return;
284
 
285
        for (h = 0; h < 256; h++) {
286
                struct fw_filter *f;
287
 
288
                for (f = head->ht[h]; f; f = f->next) {
289
                        if (arg->count < arg->skip) {
290
                                arg->count++;
291
                                continue;
292
                        }
293
                        if (arg->fn(tp, (unsigned long)f, arg) < 0) {
294
                                arg->stop = 1;
295
                                break;
296
                        }
297
                        arg->count++;
298
                }
299
        }
300
}
301
 
302
static int fw_dump(struct tcf_proto *tp, unsigned long fh,
303
                   struct sk_buff *skb, struct tcmsg *t)
304
{
305
        struct fw_filter *f = (struct fw_filter*)fh;
306
        unsigned char    *b = skb->tail;
307
        struct rtattr *rta;
308
 
309
        if (f == NULL)
310
                return skb->len;
311
 
312
        t->tcm_handle = f->id;
313
 
314
       if (!f->res.classid
315
#ifdef CONFIG_NET_CLS_POLICE
316
           && !f->police
317
#endif
318
           )
319
                return skb->len;
320
 
321
        rta = (struct rtattr*)b;
322
        RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
323
 
324
        if (f->res.classid)
325
                RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid);
326
#ifdef CONFIG_NET_CLS_POLICE
327
        if (f->police) {
328
                struct rtattr * p_rta = (struct rtattr*)skb->tail;
329
 
330
                RTA_PUT(skb, TCA_FW_POLICE, 0, NULL);
331
 
332
                if (tcf_police_dump(skb, f->police) < 0)
333
                        goto rtattr_failure;
334
 
335
                p_rta->rta_len = skb->tail - (u8*)p_rta;
336
        }
337
#endif
338
 
339
        rta->rta_len = skb->tail - b;
340
#ifdef CONFIG_NET_CLS_POLICE
341
        if (f->police) {
342
                if (qdisc_copy_stats(skb, &f->police->stats))
343
                        goto rtattr_failure;
344
        }
345
#endif
346
        return skb->len;
347
 
348
rtattr_failure:
349
        skb_trim(skb, b - skb->data);
350
        return -1;
351
}
352
 
353
struct tcf_proto_ops cls_fw_ops = {
354
        NULL,
355
        "fw",
356
        fw_classify,
357
        fw_init,
358
        fw_destroy,
359
 
360
        fw_get,
361
        fw_put,
362
        fw_change,
363
        fw_delete,
364
        fw_walk,
365
        fw_dump
366
};
367
 
368
#ifdef MODULE
369
int init_module(void)
370
{
371
        return register_tcf_proto_ops(&cls_fw_ops);
372
}
373
 
374
void cleanup_module(void)
375
{
376
        unregister_tcf_proto_ops(&cls_fw_ops);
377
}
378
#endif
379
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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