~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/sched/cls_fw.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  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 #ifdef CONFIG_RTNETLINK
303 static int fw_dump(struct tcf_proto *tp, unsigned long fh,
304                    struct sk_buff *skb, struct tcmsg *t)
305 {
306         struct fw_filter *f = (struct fw_filter*)fh;
307         unsigned char    *b = skb->tail;
308         struct rtattr *rta;
309 
310         if (f == NULL)
311                 return skb->len;
312 
313         t->tcm_handle = f->id;
314 
315        if (!f->res.classid
316 #ifdef CONFIG_NET_CLS_POLICE
317            && !f->police
318 #endif
319            )
320                 return skb->len;
321 
322         rta = (struct rtattr*)b;
323         RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
324 
325         if (f->res.classid)
326                 RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid);
327 #ifdef CONFIG_NET_CLS_POLICE
328         if (f->police) {
329                 struct rtattr * p_rta = (struct rtattr*)skb->tail;
330 
331                 RTA_PUT(skb, TCA_FW_POLICE, 0, NULL);
332 
333                 if (tcf_police_dump(skb, f->police) < 0)
334                         goto rtattr_failure;
335 
336                 p_rta->rta_len = skb->tail - (u8*)p_rta;
337         }
338 #endif
339 
340         rta->rta_len = skb->tail - b;
341 #ifdef CONFIG_NET_CLS_POLICE
342         if (f->police) {
343                 if (qdisc_copy_stats(skb, &f->police->stats))
344                         goto rtattr_failure;
345         }
346 #endif
347         return skb->len;
348 
349 rtattr_failure:
350         skb_trim(skb, b - skb->data);
351         return -1;
352 }
353 #endif
354 
355 
356 struct tcf_proto_ops cls_fw_ops = {
357         NULL,
358         "fw",
359         fw_classify,
360         fw_init,
361         fw_destroy,
362 
363         fw_get,
364         fw_put,
365         fw_change,
366         fw_delete,
367         fw_walk,
368 #ifdef CONFIG_RTNETLINK
369         fw_dump
370 #else
371         NULL
372 #endif
373 };
374 
375 #ifdef MODULE
376 int init_module(void)
377 {
378         return register_tcf_proto_ops(&cls_fw_ops);
379 }
380 
381 void cleanup_module(void) 
382 {
383         unregister_tcf_proto_ops(&cls_fw_ops);
384 }
385 #endif
386 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.