1 /*
2  * net/sched/cls_rsvp.h	Template file for RSVPv[46] classifiers.
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 /*
13    Comparing to general packet classification problem,
14    RSVP needs only sevaral relatively simple rules:
15 
16    * (dst, protocol) are always specified,
17      so that we are able to hash them.
18    * src may be exact, or may be wildcard, so that
19      we can keep a hash table plus one wildcard entry.
20    * source port (or flow label) is important only if src is given.
21 
22    IMPLEMENTATION.
23 
24    We use a two level hash table: The top level is keyed by
25    destination address and protocol ID, every bucket contains a list
26    of "rsvp sessions", identified by destination address, protocol and
27    DPI(="Destination Port ID"): triple (key, mask, offset).
28 
29    Every bucket has a smaller hash table keyed by source address
30    (cf. RSVP flowspec) and one wildcard entry for wildcard reservations.
31    Every bucket is again a list of "RSVP flows", selected by
32    source address and SPI(="Source Port ID" here rather than
33    "security parameter index"): triple (key, mask, offset).
34 
35 
36    NOTE 1. All the packets with IPv6 extension headers (but AH and ESP)
37    and all fragmented packets go to the best-effort traffic class.
38 
39 
40    NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires
41    only one "Generalized Port Identifier". So that for classic
42    ah, esp (and udp,tcp) both *pi should coincide or one of them
43    should be wildcard.
44 
45    At first sight, this redundancy is just a waste of CPU
46    resources. But DPI and SPI add the possibility to assign different
47    priorities to GPIs. Look also at note 4 about tunnels below.
48 
49 
50    NOTE 3. One complication is the case of tunneled packets.
51    We implement it as following: if the first lookup
52    matches a special session with "tunnelhdr" value not zero,
53    flowid doesn't contain the true flow ID, but the tunnel ID (1...255).
54    In this case, we pull tunnelhdr bytes and restart lookup
55    with tunnel ID added to the list of keys. Simple and stupid 8)8)
56    It's enough for PIMREG and IPIP.
57 
58 
59    NOTE 4. Two GPIs make it possible to parse even GRE packets.
60    F.e. DPI can select ETH_P_IP (and necessary flags to make
61    tunnelhdr correct) in GRE protocol field and SPI matches
62    GRE key. Is it not nice? 8)8)
63 
64 
65    Well, as result, despite its simplicity, we get a pretty
66    powerful classification engine.  */
67 
68 
69 struct rsvp_head {
70 	u32			tmap[256/32];
71 	u32			hgenerator;
72 	u8			tgenerator;
73 	struct rsvp_session __rcu *ht[256];
74 	struct rcu_head		rcu;
75 };
76 
77 struct rsvp_session {
78 	struct rsvp_session __rcu	*next;
79 	__be32				dst[RSVP_DST_LEN];
80 	struct tc_rsvp_gpi		dpi;
81 	u8				protocol;
82 	u8				tunnelid;
83 	/* 16 (src,sport) hash slots, and one wildcard source slot */
84 	struct rsvp_filter __rcu	*ht[16 + 1];
85 	struct rcu_head			rcu;
86 };
87 
88 
89 struct rsvp_filter {
90 	struct rsvp_filter __rcu	*next;
91 	__be32				src[RSVP_DST_LEN];
92 	struct tc_rsvp_gpi		spi;
93 	u8				tunnelhdr;
94 
95 	struct tcf_result		res;
96 	struct tcf_exts			exts;
97 
98 	u32				handle;
99 	struct rsvp_session		*sess;
100 	struct rcu_head			rcu;
101 };
102 
hash_dst(__be32 * dst,u8 protocol,u8 tunnelid)103 static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
104 {
105 	unsigned int h = (__force __u32)dst[RSVP_DST_LEN - 1];
106 
107 	h ^= h>>16;
108 	h ^= h>>8;
109 	return (h ^ protocol ^ tunnelid) & 0xFF;
110 }
111 
hash_src(__be32 * src)112 static inline unsigned int hash_src(__be32 *src)
113 {
114 	unsigned int h = (__force __u32)src[RSVP_DST_LEN-1];
115 
116 	h ^= h>>16;
117 	h ^= h>>8;
118 	h ^= h>>4;
119 	return h & 0xF;
120 }
121 
122 #define RSVP_APPLY_RESULT()				\
123 {							\
124 	int r = tcf_exts_exec(skb, &f->exts, res);	\
125 	if (r < 0)					\
126 		continue;				\
127 	else if (r > 0)					\
128 		return r;				\
129 }
130 
rsvp_classify(struct sk_buff * skb,const struct tcf_proto * tp,struct tcf_result * res)131 static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp,
132 			 struct tcf_result *res)
133 {
134 	struct rsvp_head *head = rcu_dereference_bh(tp->root);
135 	struct rsvp_session *s;
136 	struct rsvp_filter *f;
137 	unsigned int h1, h2;
138 	__be32 *dst, *src;
139 	u8 protocol;
140 	u8 tunnelid = 0;
141 	u8 *xprt;
142 #if RSVP_DST_LEN == 4
143 	struct ipv6hdr *nhptr;
144 
145 	if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
146 		return -1;
147 	nhptr = ipv6_hdr(skb);
148 #else
149 	struct iphdr *nhptr;
150 
151 	if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
152 		return -1;
153 	nhptr = ip_hdr(skb);
154 #endif
155 
156 restart:
157 
158 #if RSVP_DST_LEN == 4
159 	src = &nhptr->saddr.s6_addr32[0];
160 	dst = &nhptr->daddr.s6_addr32[0];
161 	protocol = nhptr->nexthdr;
162 	xprt = ((u8 *)nhptr) + sizeof(struct ipv6hdr);
163 #else
164 	src = &nhptr->saddr;
165 	dst = &nhptr->daddr;
166 	protocol = nhptr->protocol;
167 	xprt = ((u8 *)nhptr) + (nhptr->ihl<<2);
168 	if (ip_is_fragment(nhptr))
169 		return -1;
170 #endif
171 
172 	h1 = hash_dst(dst, protocol, tunnelid);
173 	h2 = hash_src(src);
174 
175 	for (s = rcu_dereference_bh(head->ht[h1]); s;
176 	     s = rcu_dereference_bh(s->next)) {
177 		if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] &&
178 		    protocol == s->protocol &&
179 		    !(s->dpi.mask &
180 		      (*(u32 *)(xprt + s->dpi.offset) ^ s->dpi.key)) &&
181 #if RSVP_DST_LEN == 4
182 		    dst[0] == s->dst[0] &&
183 		    dst[1] == s->dst[1] &&
184 		    dst[2] == s->dst[2] &&
185 #endif
186 		    tunnelid == s->tunnelid) {
187 
188 			for (f = rcu_dereference_bh(s->ht[h2]); f;
189 			     f = rcu_dereference_bh(f->next)) {
190 				if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] &&
191 				    !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key))
192 #if RSVP_DST_LEN == 4
193 				    &&
194 				    src[0] == f->src[0] &&
195 				    src[1] == f->src[1] &&
196 				    src[2] == f->src[2]
197 #endif
198 				    ) {
199 					*res = f->res;
200 					RSVP_APPLY_RESULT();
201 
202 matched:
203 					if (f->tunnelhdr == 0)
204 						return 0;
205 
206 					tunnelid = f->res.classid;
207 					nhptr = (void *)(xprt + f->tunnelhdr - sizeof(*nhptr));
208 					goto restart;
209 				}
210 			}
211 
212 			/* And wildcard bucket... */
213 			for (f = rcu_dereference_bh(s->ht[16]); f;
214 			     f = rcu_dereference_bh(f->next)) {
215 				*res = f->res;
216 				RSVP_APPLY_RESULT();
217 				goto matched;
218 			}
219 			return -1;
220 		}
221 	}
222 	return -1;
223 }
224 
rsvp_replace(struct tcf_proto * tp,struct rsvp_filter * n,u32 h)225 static void rsvp_replace(struct tcf_proto *tp, struct rsvp_filter *n, u32 h)
226 {
227 	struct rsvp_head *head = rtnl_dereference(tp->root);
228 	struct rsvp_session *s;
229 	struct rsvp_filter __rcu **ins;
230 	struct rsvp_filter *pins;
231 	unsigned int h1 = h & 0xFF;
232 	unsigned int h2 = (h >> 8) & 0xFF;
233 
234 	for (s = rtnl_dereference(head->ht[h1]); s;
235 	     s = rtnl_dereference(s->next)) {
236 		for (ins = &s->ht[h2], pins = rtnl_dereference(*ins); ;
237 		     ins = &pins->next, pins = rtnl_dereference(*ins)) {
238 			if (pins->handle == h) {
239 				RCU_INIT_POINTER(n->next, pins->next);
240 				rcu_assign_pointer(*ins, n);
241 				return;
242 			}
243 		}
244 	}
245 
246 	/* Something went wrong if we are trying to replace a non-existant
247 	 * node. Mind as well halt instead of silently failing.
248 	 */
249 	BUG_ON(1);
250 }
251 
rsvp_get(struct tcf_proto * tp,u32 handle)252 static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle)
253 {
254 	struct rsvp_head *head = rtnl_dereference(tp->root);
255 	struct rsvp_session *s;
256 	struct rsvp_filter *f;
257 	unsigned int h1 = handle & 0xFF;
258 	unsigned int h2 = (handle >> 8) & 0xFF;
259 
260 	if (h2 > 16)
261 		return 0;
262 
263 	for (s = rtnl_dereference(head->ht[h1]); s;
264 	     s = rtnl_dereference(s->next)) {
265 		for (f = rtnl_dereference(s->ht[h2]); f;
266 		     f = rtnl_dereference(f->next)) {
267 			if (f->handle == handle)
268 				return (unsigned long)f;
269 		}
270 	}
271 	return 0;
272 }
273 
rsvp_init(struct tcf_proto * tp)274 static int rsvp_init(struct tcf_proto *tp)
275 {
276 	struct rsvp_head *data;
277 
278 	data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL);
279 	if (data) {
280 		rcu_assign_pointer(tp->root, data);
281 		return 0;
282 	}
283 	return -ENOBUFS;
284 }
285 
rsvp_delete_filter_rcu(struct rcu_head * head)286 static void rsvp_delete_filter_rcu(struct rcu_head *head)
287 {
288 	struct rsvp_filter *f = container_of(head, struct rsvp_filter, rcu);
289 
290 	tcf_exts_destroy(&f->exts);
291 	kfree(f);
292 }
293 
rsvp_delete_filter(struct tcf_proto * tp,struct rsvp_filter * f)294 static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
295 {
296 	tcf_unbind_filter(tp, &f->res);
297 	/* all classifiers are required to call tcf_exts_destroy() after rcu
298 	 * grace period, since converted-to-rcu actions are relying on that
299 	 * in cleanup() callback
300 	 */
301 	call_rcu(&f->rcu, rsvp_delete_filter_rcu);
302 }
303 
rsvp_destroy(struct tcf_proto * tp,bool force)304 static bool rsvp_destroy(struct tcf_proto *tp, bool force)
305 {
306 	struct rsvp_head *data = rtnl_dereference(tp->root);
307 	int h1, h2;
308 
309 	if (data == NULL)
310 		return true;
311 
312 	if (!force) {
313 		for (h1 = 0; h1 < 256; h1++) {
314 			if (rcu_access_pointer(data->ht[h1]))
315 				return false;
316 		}
317 	}
318 
319 	RCU_INIT_POINTER(tp->root, NULL);
320 
321 	for (h1 = 0; h1 < 256; h1++) {
322 		struct rsvp_session *s;
323 
324 		while ((s = rtnl_dereference(data->ht[h1])) != NULL) {
325 			RCU_INIT_POINTER(data->ht[h1], s->next);
326 
327 			for (h2 = 0; h2 <= 16; h2++) {
328 				struct rsvp_filter *f;
329 
330 				while ((f = rtnl_dereference(s->ht[h2])) != NULL) {
331 					rcu_assign_pointer(s->ht[h2], f->next);
332 					rsvp_delete_filter(tp, f);
333 				}
334 			}
335 			kfree_rcu(s, rcu);
336 		}
337 	}
338 	kfree_rcu(data, rcu);
339 	return true;
340 }
341 
rsvp_delete(struct tcf_proto * tp,unsigned long arg)342 static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
343 {
344 	struct rsvp_head *head = rtnl_dereference(tp->root);
345 	struct rsvp_filter *nfp, *f = (struct rsvp_filter *)arg;
346 	struct rsvp_filter __rcu **fp;
347 	unsigned int h = f->handle;
348 	struct rsvp_session __rcu **sp;
349 	struct rsvp_session *nsp, *s = f->sess;
350 	int i;
351 
352 	fp = &s->ht[(h >> 8) & 0xFF];
353 	for (nfp = rtnl_dereference(*fp); nfp;
354 	     fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
355 		if (nfp == f) {
356 			RCU_INIT_POINTER(*fp, f->next);
357 			rsvp_delete_filter(tp, f);
358 
359 			/* Strip tree */
360 
361 			for (i = 0; i <= 16; i++)
362 				if (s->ht[i])
363 					return 0;
364 
365 			/* OK, session has no flows */
366 			sp = &head->ht[h & 0xFF];
367 			for (nsp = rtnl_dereference(*sp); nsp;
368 			     sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
369 				if (nsp == s) {
370 					RCU_INIT_POINTER(*sp, s->next);
371 					kfree_rcu(s, rcu);
372 					return 0;
373 				}
374 			}
375 
376 			return 0;
377 		}
378 	}
379 	return 0;
380 }
381 
gen_handle(struct tcf_proto * tp,unsigned salt)382 static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt)
383 {
384 	struct rsvp_head *data = rtnl_dereference(tp->root);
385 	int i = 0xFFFF;
386 
387 	while (i-- > 0) {
388 		u32 h;
389 
390 		if ((data->hgenerator += 0x10000) == 0)
391 			data->hgenerator = 0x10000;
392 		h = data->hgenerator|salt;
393 		if (rsvp_get(tp, h) == 0)
394 			return h;
395 	}
396 	return 0;
397 }
398 
tunnel_bts(struct rsvp_head * data)399 static int tunnel_bts(struct rsvp_head *data)
400 {
401 	int n = data->tgenerator >> 5;
402 	u32 b = 1 << (data->tgenerator & 0x1F);
403 
404 	if (data->tmap[n] & b)
405 		return 0;
406 	data->tmap[n] |= b;
407 	return 1;
408 }
409 
tunnel_recycle(struct rsvp_head * data)410 static void tunnel_recycle(struct rsvp_head *data)
411 {
412 	struct rsvp_session __rcu **sht = data->ht;
413 	u32 tmap[256/32];
414 	int h1, h2;
415 
416 	memset(tmap, 0, sizeof(tmap));
417 
418 	for (h1 = 0; h1 < 256; h1++) {
419 		struct rsvp_session *s;
420 		for (s = rtnl_dereference(sht[h1]); s;
421 		     s = rtnl_dereference(s->next)) {
422 			for (h2 = 0; h2 <= 16; h2++) {
423 				struct rsvp_filter *f;
424 
425 				for (f = rtnl_dereference(s->ht[h2]); f;
426 				     f = rtnl_dereference(f->next)) {
427 					if (f->tunnelhdr == 0)
428 						continue;
429 					data->tgenerator = f->res.classid;
430 					tunnel_bts(data);
431 				}
432 			}
433 		}
434 	}
435 
436 	memcpy(data->tmap, tmap, sizeof(tmap));
437 }
438 
gen_tunnel(struct rsvp_head * data)439 static u32 gen_tunnel(struct rsvp_head *data)
440 {
441 	int i, k;
442 
443 	for (k = 0; k < 2; k++) {
444 		for (i = 255; i > 0; i--) {
445 			if (++data->tgenerator == 0)
446 				data->tgenerator = 1;
447 			if (tunnel_bts(data))
448 				return data->tgenerator;
449 		}
450 		tunnel_recycle(data);
451 	}
452 	return 0;
453 }
454 
455 static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
456 	[TCA_RSVP_CLASSID]	= { .type = NLA_U32 },
457 	[TCA_RSVP_DST]		= { .type = NLA_BINARY,
458 				    .len = RSVP_DST_LEN * sizeof(u32) },
459 	[TCA_RSVP_SRC]		= { .type = NLA_BINARY,
460 				    .len = RSVP_DST_LEN * sizeof(u32) },
461 	[TCA_RSVP_PINFO]	= { .len = sizeof(struct tc_rsvp_pinfo) },
462 };
463 
rsvp_change(struct net * net,struct sk_buff * in_skb,struct tcf_proto * tp,unsigned long base,u32 handle,struct nlattr ** tca,unsigned long * arg,bool ovr)464 static int rsvp_change(struct net *net, struct sk_buff *in_skb,
465 		       struct tcf_proto *tp, unsigned long base,
466 		       u32 handle,
467 		       struct nlattr **tca,
468 		       unsigned long *arg, bool ovr)
469 {
470 	struct rsvp_head *data = rtnl_dereference(tp->root);
471 	struct rsvp_filter *f, *nfp;
472 	struct rsvp_filter __rcu **fp;
473 	struct rsvp_session *nsp, *s;
474 	struct rsvp_session __rcu **sp;
475 	struct tc_rsvp_pinfo *pinfo = NULL;
476 	struct nlattr *opt = tca[TCA_OPTIONS];
477 	struct nlattr *tb[TCA_RSVP_MAX + 1];
478 	struct tcf_exts e;
479 	unsigned int h1, h2;
480 	__be32 *dst;
481 	int err;
482 
483 	if (opt == NULL)
484 		return handle ? -EINVAL : 0;
485 
486 	err = nla_parse_nested(tb, TCA_RSVP_MAX, opt, rsvp_policy);
487 	if (err < 0)
488 		return err;
489 
490 	tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE);
491 	err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
492 	if (err < 0)
493 		return err;
494 
495 	f = (struct rsvp_filter *)*arg;
496 	if (f) {
497 		/* Node exists: adjust only classid */
498 		struct rsvp_filter *n;
499 
500 		if (f->handle != handle && handle)
501 			goto errout2;
502 
503 		n = kmemdup(f, sizeof(*f), GFP_KERNEL);
504 		if (!n) {
505 			err = -ENOMEM;
506 			goto errout2;
507 		}
508 
509 		tcf_exts_init(&n->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
510 
511 		if (tb[TCA_RSVP_CLASSID]) {
512 			n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
513 			tcf_bind_filter(tp, &n->res, base);
514 		}
515 
516 		tcf_exts_change(tp, &n->exts, &e);
517 		rsvp_replace(tp, n, handle);
518 		return 0;
519 	}
520 
521 	/* Now more serious part... */
522 	err = -EINVAL;
523 	if (handle)
524 		goto errout2;
525 	if (tb[TCA_RSVP_DST] == NULL)
526 		goto errout2;
527 
528 	err = -ENOBUFS;
529 	f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL);
530 	if (f == NULL)
531 		goto errout2;
532 
533 	tcf_exts_init(&f->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
534 	h2 = 16;
535 	if (tb[TCA_RSVP_SRC]) {
536 		memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
537 		h2 = hash_src(f->src);
538 	}
539 	if (tb[TCA_RSVP_PINFO]) {
540 		pinfo = nla_data(tb[TCA_RSVP_PINFO]);
541 		f->spi = pinfo->spi;
542 		f->tunnelhdr = pinfo->tunnelhdr;
543 	}
544 	if (tb[TCA_RSVP_CLASSID])
545 		f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
546 
547 	dst = nla_data(tb[TCA_RSVP_DST]);
548 	h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
549 
550 	err = -ENOMEM;
551 	if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0)
552 		goto errout;
553 
554 	if (f->tunnelhdr) {
555 		err = -EINVAL;
556 		if (f->res.classid > 255)
557 			goto errout;
558 
559 		err = -ENOMEM;
560 		if (f->res.classid == 0 &&
561 		    (f->res.classid = gen_tunnel(data)) == 0)
562 			goto errout;
563 	}
564 
565 	for (sp = &data->ht[h1];
566 	     (s = rtnl_dereference(*sp)) != NULL;
567 	     sp = &s->next) {
568 		if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
569 		    pinfo && pinfo->protocol == s->protocol &&
570 		    memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 &&
571 #if RSVP_DST_LEN == 4
572 		    dst[0] == s->dst[0] &&
573 		    dst[1] == s->dst[1] &&
574 		    dst[2] == s->dst[2] &&
575 #endif
576 		    pinfo->tunnelid == s->tunnelid) {
577 
578 insert:
579 			/* OK, we found appropriate session */
580 
581 			fp = &s->ht[h2];
582 
583 			f->sess = s;
584 			if (f->tunnelhdr == 0)
585 				tcf_bind_filter(tp, &f->res, base);
586 
587 			tcf_exts_change(tp, &f->exts, &e);
588 
589 			fp = &s->ht[h2];
590 			for (nfp = rtnl_dereference(*fp); nfp;
591 			     fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
592 				__u32 mask = nfp->spi.mask & f->spi.mask;
593 
594 				if (mask != f->spi.mask)
595 					break;
596 			}
597 			RCU_INIT_POINTER(f->next, nfp);
598 			rcu_assign_pointer(*fp, f);
599 
600 			*arg = (unsigned long)f;
601 			return 0;
602 		}
603 	}
604 
605 	/* No session found. Create new one. */
606 
607 	err = -ENOBUFS;
608 	s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL);
609 	if (s == NULL)
610 		goto errout;
611 	memcpy(s->dst, dst, sizeof(s->dst));
612 
613 	if (pinfo) {
614 		s->dpi = pinfo->dpi;
615 		s->protocol = pinfo->protocol;
616 		s->tunnelid = pinfo->tunnelid;
617 	}
618 	sp = &data->ht[h1];
619 	for (nsp = rtnl_dereference(*sp); nsp;
620 	     sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
621 		if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask)
622 			break;
623 	}
624 	RCU_INIT_POINTER(s->next, nsp);
625 	rcu_assign_pointer(*sp, s);
626 
627 	goto insert;
628 
629 errout:
630 	kfree(f);
631 errout2:
632 	tcf_exts_destroy(&e);
633 	return err;
634 }
635 
rsvp_walk(struct tcf_proto * tp,struct tcf_walker * arg)636 static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
637 {
638 	struct rsvp_head *head = rtnl_dereference(tp->root);
639 	unsigned int h, h1;
640 
641 	if (arg->stop)
642 		return;
643 
644 	for (h = 0; h < 256; h++) {
645 		struct rsvp_session *s;
646 
647 		for (s = rtnl_dereference(head->ht[h]); s;
648 		     s = rtnl_dereference(s->next)) {
649 			for (h1 = 0; h1 <= 16; h1++) {
650 				struct rsvp_filter *f;
651 
652 				for (f = rtnl_dereference(s->ht[h1]); f;
653 				     f = rtnl_dereference(f->next)) {
654 					if (arg->count < arg->skip) {
655 						arg->count++;
656 						continue;
657 					}
658 					if (arg->fn(tp, (unsigned long)f, arg) < 0) {
659 						arg->stop = 1;
660 						return;
661 					}
662 					arg->count++;
663 				}
664 			}
665 		}
666 	}
667 }
668 
rsvp_dump(struct net * net,struct tcf_proto * tp,unsigned long fh,struct sk_buff * skb,struct tcmsg * t)669 static int rsvp_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
670 		     struct sk_buff *skb, struct tcmsg *t)
671 {
672 	struct rsvp_filter *f = (struct rsvp_filter *)fh;
673 	struct rsvp_session *s;
674 	struct nlattr *nest;
675 	struct tc_rsvp_pinfo pinfo;
676 
677 	if (f == NULL)
678 		return skb->len;
679 	s = f->sess;
680 
681 	t->tcm_handle = f->handle;
682 
683 	nest = nla_nest_start(skb, TCA_OPTIONS);
684 	if (nest == NULL)
685 		goto nla_put_failure;
686 
687 	if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst))
688 		goto nla_put_failure;
689 	pinfo.dpi = s->dpi;
690 	pinfo.spi = f->spi;
691 	pinfo.protocol = s->protocol;
692 	pinfo.tunnelid = s->tunnelid;
693 	pinfo.tunnelhdr = f->tunnelhdr;
694 	pinfo.pad = 0;
695 	if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo))
696 		goto nla_put_failure;
697 	if (f->res.classid &&
698 	    nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid))
699 		goto nla_put_failure;
700 	if (((f->handle >> 8) & 0xFF) != 16 &&
701 	    nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src))
702 		goto nla_put_failure;
703 
704 	if (tcf_exts_dump(skb, &f->exts) < 0)
705 		goto nla_put_failure;
706 
707 	nla_nest_end(skb, nest);
708 
709 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
710 		goto nla_put_failure;
711 	return skb->len;
712 
713 nla_put_failure:
714 	nla_nest_cancel(skb, nest);
715 	return -1;
716 }
717 
718 static struct tcf_proto_ops RSVP_OPS __read_mostly = {
719 	.kind		=	RSVP_ID,
720 	.classify	=	rsvp_classify,
721 	.init		=	rsvp_init,
722 	.destroy	=	rsvp_destroy,
723 	.get		=	rsvp_get,
724 	.change		=	rsvp_change,
725 	.delete		=	rsvp_delete,
726 	.walk		=	rsvp_walk,
727 	.dump		=	rsvp_dump,
728 	.owner		=	THIS_MODULE,
729 };
730 
init_rsvp(void)731 static int __init init_rsvp(void)
732 {
733 	return register_tcf_proto_ops(&RSVP_OPS);
734 }
735 
exit_rsvp(void)736 static void __exit exit_rsvp(void)
737 {
738 	unregister_tcf_proto_ops(&RSVP_OPS);
739 }
740 
741 module_init(init_rsvp)
742 module_exit(exit_rsvp)
743