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