xref: /openbmc/linux/net/sched/cls_route.c (revision cd354f1a)
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 <asm/uaccess.h>
14 #include <asm/system.h>
15 #include <linux/bitops.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/string.h>
19 #include <linux/mm.h>
20 #include <linux/socket.h>
21 #include <linux/sockios.h>
22 #include <linux/in.h>
23 #include <linux/errno.h>
24 #include <linux/interrupt.h>
25 #include <linux/if_ether.h>
26 #include <linux/inet.h>
27 #include <linux/netdevice.h>
28 #include <linux/etherdevice.h>
29 #include <linux/notifier.h>
30 #include <net/ip.h>
31 #include <net/route.h>
32 #include <linux/skbuff.h>
33 #include <net/sock.h>
34 #include <net/act_api.h>
35 #include <net/pkt_cls.h>
36 
37 /*
38    1. For now we assume that route tags < 256.
39       It allows to use direct table lookups, instead of hash tables.
40    2. For now we assume that "from TAG" and "fromdev DEV" statements
41       are mutually  exclusive.
42    3. "to TAG from ANY" has higher priority, than "to ANY from XXX"
43  */
44 
45 struct route4_fastmap
46 {
47 	struct route4_filter	*filter;
48 	u32			id;
49 	int			iif;
50 };
51 
52 struct route4_head
53 {
54 	struct route4_fastmap	fastmap[16];
55 	struct route4_bucket	*table[256+1];
56 };
57 
58 struct route4_bucket
59 {
60 	/* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */
61 	struct route4_filter	*ht[16+16+1];
62 };
63 
64 struct route4_filter
65 {
66 	struct route4_filter	*next;
67 	u32			id;
68 	int			iif;
69 
70 	struct tcf_result	res;
71 	struct tcf_exts		exts;
72 	u32			handle;
73 	struct route4_bucket	*bkt;
74 };
75 
76 #define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
77 
78 static struct tcf_ext_map route_ext_map = {
79 	.police = TCA_ROUTE4_POLICE,
80 	.action = TCA_ROUTE4_ACT
81 };
82 
83 static __inline__ int route4_fastmap_hash(u32 id, int iif)
84 {
85 	return id&0xF;
86 }
87 
88 static inline
89 void route4_reset_fastmap(struct net_device *dev, struct route4_head *head, u32 id)
90 {
91 	spin_lock_bh(&dev->queue_lock);
92 	memset(head->fastmap, 0, sizeof(head->fastmap));
93 	spin_unlock_bh(&dev->queue_lock);
94 }
95 
96 static void __inline__
97 route4_set_fastmap(struct route4_head *head, u32 id, int iif,
98 		   struct route4_filter *f)
99 {
100 	int h = route4_fastmap_hash(id, iif);
101 	head->fastmap[h].id = id;
102 	head->fastmap[h].iif = iif;
103 	head->fastmap[h].filter = f;
104 }
105 
106 static __inline__ int route4_hash_to(u32 id)
107 {
108 	return id&0xFF;
109 }
110 
111 static __inline__ int route4_hash_from(u32 id)
112 {
113 	return (id>>16)&0xF;
114 }
115 
116 static __inline__ int route4_hash_iif(int iif)
117 {
118 	return 16 + ((iif>>16)&0xF);
119 }
120 
121 static __inline__ int route4_hash_wild(void)
122 {
123 	return 32;
124 }
125 
126 #define ROUTE4_APPLY_RESULT()					\
127 {								\
128 	*res = f->res;						\
129 	if (tcf_exts_is_available(&f->exts)) {			\
130 		int r = tcf_exts_exec(skb, &f->exts, res);	\
131 		if (r < 0) {					\
132 			dont_cache = 1;				\
133 			continue;				\
134 		}						\
135 		return r;					\
136 	} else if (!dont_cache)					\
137 		route4_set_fastmap(head, id, iif, f);		\
138 	return 0;						\
139 }
140 
141 static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
142 			   struct tcf_result *res)
143 {
144 	struct route4_head *head = (struct route4_head*)tp->root;
145 	struct dst_entry *dst;
146 	struct route4_bucket *b;
147 	struct route4_filter *f;
148 	u32 id, h;
149 	int iif, dont_cache = 0;
150 
151 	if ((dst = skb->dst) == NULL)
152 		goto failure;
153 
154 	id = dst->tclassid;
155 	if (head == NULL)
156 		goto old_method;
157 
158 	iif = ((struct rtable*)dst)->fl.iif;
159 
160 	h = route4_fastmap_hash(id, iif);
161 	if (id == head->fastmap[h].id &&
162 	    iif == head->fastmap[h].iif &&
163 	    (f = head->fastmap[h].filter) != NULL) {
164 		if (f == ROUTE4_FAILURE)
165 			goto failure;
166 
167 		*res = f->res;
168 		return 0;
169 	}
170 
171 	h = route4_hash_to(id);
172 
173 restart:
174 	if ((b = head->table[h]) != NULL) {
175 		for (f = b->ht[route4_hash_from(id)]; f; f = f->next)
176 			if (f->id == id)
177 				ROUTE4_APPLY_RESULT();
178 
179 		for (f = b->ht[route4_hash_iif(iif)]; f; f = f->next)
180 			if (f->iif == iif)
181 				ROUTE4_APPLY_RESULT();
182 
183 		for (f = b->ht[route4_hash_wild()]; f; f = f->next)
184 			ROUTE4_APPLY_RESULT();
185 
186 	}
187 	if (h < 256) {
188 		h = 256;
189 		id &= ~0xFFFF;
190 		goto restart;
191 	}
192 
193 	if (!dont_cache)
194 		route4_set_fastmap(head, id, iif, ROUTE4_FAILURE);
195 failure:
196 	return -1;
197 
198 old_method:
199 	if (id && (TC_H_MAJ(id) == 0 ||
200 		   !(TC_H_MAJ(id^tp->q->handle)))) {
201 		res->classid = id;
202 		res->class = 0;
203 		return 0;
204 	}
205 	return -1;
206 }
207 
208 static inline u32 to_hash(u32 id)
209 {
210 	u32 h = id&0xFF;
211 	if (id&0x8000)
212 		h += 256;
213 	return h;
214 }
215 
216 static inline u32 from_hash(u32 id)
217 {
218 	id &= 0xFFFF;
219 	if (id == 0xFFFF)
220 		return 32;
221 	if (!(id & 0x8000)) {
222 		if (id > 255)
223 			return 256;
224 		return id&0xF;
225 	}
226 	return 16 + (id&0xF);
227 }
228 
229 static unsigned long route4_get(struct tcf_proto *tp, u32 handle)
230 {
231 	struct route4_head *head = (struct route4_head*)tp->root;
232 	struct route4_bucket *b;
233 	struct route4_filter *f;
234 	unsigned h1, h2;
235 
236 	if (!head)
237 		return 0;
238 
239 	h1 = to_hash(handle);
240 	if (h1 > 256)
241 		return 0;
242 
243 	h2 = from_hash(handle>>16);
244 	if (h2 > 32)
245 		return 0;
246 
247 	if ((b = head->table[h1]) != NULL) {
248 		for (f = b->ht[h2]; f; f = f->next)
249 			if (f->handle == handle)
250 				return (unsigned long)f;
251 	}
252 	return 0;
253 }
254 
255 static void route4_put(struct tcf_proto *tp, unsigned long f)
256 {
257 }
258 
259 static int route4_init(struct tcf_proto *tp)
260 {
261 	return 0;
262 }
263 
264 static inline void
265 route4_delete_filter(struct tcf_proto *tp, struct route4_filter *f)
266 {
267 	tcf_unbind_filter(tp, &f->res);
268 	tcf_exts_destroy(tp, &f->exts);
269 	kfree(f);
270 }
271 
272 static void route4_destroy(struct tcf_proto *tp)
273 {
274 	struct route4_head *head = xchg(&tp->root, NULL);
275 	int h1, h2;
276 
277 	if (head == NULL)
278 		return;
279 
280 	for (h1=0; h1<=256; h1++) {
281 		struct route4_bucket *b;
282 
283 		if ((b = head->table[h1]) != NULL) {
284 			for (h2=0; h2<=32; h2++) {
285 				struct route4_filter *f;
286 
287 				while ((f = b->ht[h2]) != NULL) {
288 					b->ht[h2] = f->next;
289 					route4_delete_filter(tp, f);
290 				}
291 			}
292 			kfree(b);
293 		}
294 	}
295 	kfree(head);
296 }
297 
298 static int route4_delete(struct tcf_proto *tp, unsigned long arg)
299 {
300 	struct route4_head *head = (struct route4_head*)tp->root;
301 	struct route4_filter **fp, *f = (struct route4_filter*)arg;
302 	unsigned h = 0;
303 	struct route4_bucket *b;
304 	int i;
305 
306 	if (!head || !f)
307 		return -EINVAL;
308 
309 	h = f->handle;
310 	b = f->bkt;
311 
312 	for (fp = &b->ht[from_hash(h>>16)]; *fp; fp = &(*fp)->next) {
313 		if (*fp == f) {
314 			tcf_tree_lock(tp);
315 			*fp = f->next;
316 			tcf_tree_unlock(tp);
317 
318 			route4_reset_fastmap(tp->q->dev, head, f->id);
319 			route4_delete_filter(tp, f);
320 
321 			/* Strip tree */
322 
323 			for (i=0; i<=32; i++)
324 				if (b->ht[i])
325 					return 0;
326 
327 			/* OK, session has no flows */
328 			tcf_tree_lock(tp);
329 			head->table[to_hash(h)] = NULL;
330 			tcf_tree_unlock(tp);
331 
332 			kfree(b);
333 			return 0;
334 		}
335 	}
336 	return 0;
337 }
338 
339 static int route4_set_parms(struct tcf_proto *tp, unsigned long base,
340 	struct route4_filter *f, u32 handle, struct route4_head *head,
341 	struct rtattr **tb, struct rtattr *est, int new)
342 {
343 	int err;
344 	u32 id = 0, to = 0, nhandle = 0x8000;
345 	struct route4_filter *fp;
346 	unsigned int h1;
347 	struct route4_bucket *b;
348 	struct tcf_exts e;
349 
350 	err = tcf_exts_validate(tp, tb, est, &e, &route_ext_map);
351 	if (err < 0)
352 		return err;
353 
354 	err = -EINVAL;
355 	if (tb[TCA_ROUTE4_CLASSID-1])
356 		if (RTA_PAYLOAD(tb[TCA_ROUTE4_CLASSID-1]) < sizeof(u32))
357 			goto errout;
358 
359 	if (tb[TCA_ROUTE4_TO-1]) {
360 		if (new && handle & 0x8000)
361 			goto errout;
362 		if (RTA_PAYLOAD(tb[TCA_ROUTE4_TO-1]) < sizeof(u32))
363 			goto errout;
364 		to = *(u32*)RTA_DATA(tb[TCA_ROUTE4_TO-1]);
365 		if (to > 0xFF)
366 			goto errout;
367 		nhandle = to;
368 	}
369 
370 	if (tb[TCA_ROUTE4_FROM-1]) {
371 		if (tb[TCA_ROUTE4_IIF-1])
372 			goto errout;
373 		if (RTA_PAYLOAD(tb[TCA_ROUTE4_FROM-1]) < sizeof(u32))
374 			goto errout;
375 		id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_FROM-1]);
376 		if (id > 0xFF)
377 			goto errout;
378 		nhandle |= id << 16;
379 	} else if (tb[TCA_ROUTE4_IIF-1]) {
380 		if (RTA_PAYLOAD(tb[TCA_ROUTE4_IIF-1]) < sizeof(u32))
381 			goto errout;
382 		id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_IIF-1]);
383 		if (id > 0x7FFF)
384 			goto errout;
385 		nhandle |= (id | 0x8000) << 16;
386 	} else
387 		nhandle |= 0xFFFF << 16;
388 
389 	if (handle && new) {
390 		nhandle |= handle & 0x7F00;
391 		if (nhandle != handle)
392 			goto errout;
393 	}
394 
395 	h1 = to_hash(nhandle);
396 	if ((b = head->table[h1]) == NULL) {
397 		err = -ENOBUFS;
398 		b = kzalloc(sizeof(struct route4_bucket), GFP_KERNEL);
399 		if (b == NULL)
400 			goto errout;
401 
402 		tcf_tree_lock(tp);
403 		head->table[h1] = b;
404 		tcf_tree_unlock(tp);
405 	} else {
406 		unsigned int h2 = from_hash(nhandle >> 16);
407 		err = -EEXIST;
408 		for (fp = b->ht[h2]; fp; fp = fp->next)
409 			if (fp->handle == f->handle)
410 				goto errout;
411 	}
412 
413 	tcf_tree_lock(tp);
414 	if (tb[TCA_ROUTE4_TO-1])
415 		f->id = to;
416 
417 	if (tb[TCA_ROUTE4_FROM-1])
418 		f->id = to | id<<16;
419 	else if (tb[TCA_ROUTE4_IIF-1])
420 		f->iif = id;
421 
422 	f->handle = nhandle;
423 	f->bkt = b;
424 	tcf_tree_unlock(tp);
425 
426 	if (tb[TCA_ROUTE4_CLASSID-1]) {
427 		f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]);
428 		tcf_bind_filter(tp, &f->res, base);
429 	}
430 
431 	tcf_exts_change(tp, &f->exts, &e);
432 
433 	return 0;
434 errout:
435 	tcf_exts_destroy(tp, &e);
436 	return err;
437 }
438 
439 static int route4_change(struct tcf_proto *tp, unsigned long base,
440 		       u32 handle,
441 		       struct rtattr **tca,
442 		       unsigned long *arg)
443 {
444 	struct route4_head *head = tp->root;
445 	struct route4_filter *f, *f1, **fp;
446 	struct route4_bucket *b;
447 	struct rtattr *opt = tca[TCA_OPTIONS-1];
448 	struct rtattr *tb[TCA_ROUTE4_MAX];
449 	unsigned int h, th;
450 	u32 old_handle = 0;
451 	int err;
452 
453 	if (opt == NULL)
454 		return handle ? -EINVAL : 0;
455 
456 	if (rtattr_parse_nested(tb, TCA_ROUTE4_MAX, opt) < 0)
457 		return -EINVAL;
458 
459 	if ((f = (struct route4_filter*)*arg) != NULL) {
460 		if (f->handle != handle && handle)
461 			return -EINVAL;
462 
463 		if (f->bkt)
464 			old_handle = f->handle;
465 
466 		err = route4_set_parms(tp, base, f, handle, head, tb,
467 			tca[TCA_RATE-1], 0);
468 		if (err < 0)
469 			return err;
470 
471 		goto reinsert;
472 	}
473 
474 	err = -ENOBUFS;
475 	if (head == NULL) {
476 		head = kzalloc(sizeof(struct route4_head), GFP_KERNEL);
477 		if (head == NULL)
478 			goto errout;
479 
480 		tcf_tree_lock(tp);
481 		tp->root = head;
482 		tcf_tree_unlock(tp);
483 	}
484 
485 	f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL);
486 	if (f == NULL)
487 		goto errout;
488 
489 	err = route4_set_parms(tp, base, f, handle, head, tb,
490 		tca[TCA_RATE-1], 1);
491 	if (err < 0)
492 		goto errout;
493 
494 reinsert:
495 	h = from_hash(f->handle >> 16);
496 	for (fp = &f->bkt->ht[h]; (f1=*fp) != NULL; fp = &f1->next)
497 		if (f->handle < f1->handle)
498 			break;
499 
500 	f->next = f1;
501 	tcf_tree_lock(tp);
502 	*fp = f;
503 
504 	if (old_handle && f->handle != old_handle) {
505 		th = to_hash(old_handle);
506 		h = from_hash(old_handle >> 16);
507 		if ((b = head->table[th]) != NULL) {
508 			for (fp = &b->ht[h]; *fp; fp = &(*fp)->next) {
509 				if (*fp == f) {
510 					*fp = f->next;
511 					break;
512 				}
513 			}
514 		}
515 	}
516 	tcf_tree_unlock(tp);
517 
518 	route4_reset_fastmap(tp->q->dev, head, f->id);
519 	*arg = (unsigned long)f;
520 	return 0;
521 
522 errout:
523 	kfree(f);
524 	return err;
525 }
526 
527 static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
528 {
529 	struct route4_head *head = tp->root;
530 	unsigned h, h1;
531 
532 	if (head == NULL)
533 		arg->stop = 1;
534 
535 	if (arg->stop)
536 		return;
537 
538 	for (h = 0; h <= 256; h++) {
539 		struct route4_bucket *b = head->table[h];
540 
541 		if (b) {
542 			for (h1 = 0; h1 <= 32; h1++) {
543 				struct route4_filter *f;
544 
545 				for (f = b->ht[h1]; f; f = f->next) {
546 					if (arg->count < arg->skip) {
547 						arg->count++;
548 						continue;
549 					}
550 					if (arg->fn(tp, (unsigned long)f, arg) < 0) {
551 						arg->stop = 1;
552 						return;
553 					}
554 					arg->count++;
555 				}
556 			}
557 		}
558 	}
559 }
560 
561 static int route4_dump(struct tcf_proto *tp, unsigned long fh,
562 		       struct sk_buff *skb, struct tcmsg *t)
563 {
564 	struct route4_filter *f = (struct route4_filter*)fh;
565 	unsigned char	 *b = skb->tail;
566 	struct rtattr *rta;
567 	u32 id;
568 
569 	if (f == NULL)
570 		return skb->len;
571 
572 	t->tcm_handle = f->handle;
573 
574 	rta = (struct rtattr*)b;
575 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
576 
577 	if (!(f->handle&0x8000)) {
578 		id = f->id&0xFF;
579 		RTA_PUT(skb, TCA_ROUTE4_TO, sizeof(id), &id);
580 	}
581 	if (f->handle&0x80000000) {
582 		if ((f->handle>>16) != 0xFFFF)
583 			RTA_PUT(skb, TCA_ROUTE4_IIF, sizeof(f->iif), &f->iif);
584 	} else {
585 		id = f->id>>16;
586 		RTA_PUT(skb, TCA_ROUTE4_FROM, sizeof(id), &id);
587 	}
588 	if (f->res.classid)
589 		RTA_PUT(skb, TCA_ROUTE4_CLASSID, 4, &f->res.classid);
590 
591 	if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0)
592 		goto rtattr_failure;
593 
594 	rta->rta_len = skb->tail - b;
595 
596 	if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0)
597 		goto rtattr_failure;
598 
599 	return skb->len;
600 
601 rtattr_failure:
602 	skb_trim(skb, b - skb->data);
603 	return -1;
604 }
605 
606 static struct tcf_proto_ops cls_route4_ops = {
607 	.next		=	NULL,
608 	.kind		=	"route",
609 	.classify	=	route4_classify,
610 	.init		=	route4_init,
611 	.destroy	=	route4_destroy,
612 	.get		=	route4_get,
613 	.put		=	route4_put,
614 	.change		=	route4_change,
615 	.delete		=	route4_delete,
616 	.walk		=	route4_walk,
617 	.dump		=	route4_dump,
618 	.owner		=	THIS_MODULE,
619 };
620 
621 static int __init init_route4(void)
622 {
623 	return register_tcf_proto_ops(&cls_route4_ops);
624 }
625 
626 static void __exit exit_route4(void)
627 {
628 	unregister_tcf_proto_ops(&cls_route4_ops);
629 }
630 
631 module_init(init_route4)
632 module_exit(exit_route4)
633 MODULE_LICENSE("GPL");
634