• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_put(struct tcf_proto * tp,unsigned long f)274 static void rsvp_put(struct tcf_proto *tp, unsigned long f)
275 {
276 }
277 
rsvp_init(struct tcf_proto * tp)278 static int rsvp_init(struct tcf_proto *tp)
279 {
280 	struct rsvp_head *data;
281 
282 	data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL);
283 	if (data) {
284 		rcu_assign_pointer(tp->root, data);
285 		return 0;
286 	}
287 	return -ENOBUFS;
288 }
289 
290 static void
rsvp_delete_filter(struct tcf_proto * tp,struct rsvp_filter * f)291 rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
292 {
293 	tcf_unbind_filter(tp, &f->res);
294 	tcf_exts_destroy(&f->exts);
295 	kfree_rcu(f, rcu);
296 }
297 
rsvp_destroy(struct tcf_proto * tp)298 static void rsvp_destroy(struct tcf_proto *tp)
299 {
300 	struct rsvp_head *data = rtnl_dereference(tp->root);
301 	int h1, h2;
302 
303 	if (data == NULL)
304 		return;
305 
306 	RCU_INIT_POINTER(tp->root, NULL);
307 
308 	for (h1 = 0; h1 < 256; h1++) {
309 		struct rsvp_session *s;
310 
311 		while ((s = rtnl_dereference(data->ht[h1])) != NULL) {
312 			RCU_INIT_POINTER(data->ht[h1], s->next);
313 
314 			for (h2 = 0; h2 <= 16; h2++) {
315 				struct rsvp_filter *f;
316 
317 				while ((f = rtnl_dereference(s->ht[h2])) != NULL) {
318 					rcu_assign_pointer(s->ht[h2], f->next);
319 					rsvp_delete_filter(tp, f);
320 				}
321 			}
322 			kfree_rcu(s, rcu);
323 		}
324 	}
325 	kfree_rcu(data, rcu);
326 }
327 
rsvp_delete(struct tcf_proto * tp,unsigned long arg)328 static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
329 {
330 	struct rsvp_head *head = rtnl_dereference(tp->root);
331 	struct rsvp_filter *nfp, *f = (struct rsvp_filter *)arg;
332 	struct rsvp_filter __rcu **fp;
333 	unsigned int h = f->handle;
334 	struct rsvp_session __rcu **sp;
335 	struct rsvp_session *nsp, *s = f->sess;
336 	int i;
337 
338 	fp = &s->ht[(h >> 8) & 0xFF];
339 	for (nfp = rtnl_dereference(*fp); nfp;
340 	     fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
341 		if (nfp == f) {
342 			RCU_INIT_POINTER(*fp, f->next);
343 			rsvp_delete_filter(tp, f);
344 
345 			/* Strip tree */
346 
347 			for (i = 0; i <= 16; i++)
348 				if (s->ht[i])
349 					return 0;
350 
351 			/* OK, session has no flows */
352 			sp = &head->ht[h & 0xFF];
353 			for (nsp = rtnl_dereference(*sp); nsp;
354 			     sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
355 				if (nsp == s) {
356 					RCU_INIT_POINTER(*sp, s->next);
357 					kfree_rcu(s, rcu);
358 					return 0;
359 				}
360 			}
361 
362 			return 0;
363 		}
364 	}
365 	return 0;
366 }
367 
gen_handle(struct tcf_proto * tp,unsigned salt)368 static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt)
369 {
370 	struct rsvp_head *data = rtnl_dereference(tp->root);
371 	int i = 0xFFFF;
372 
373 	while (i-- > 0) {
374 		u32 h;
375 
376 		if ((data->hgenerator += 0x10000) == 0)
377 			data->hgenerator = 0x10000;
378 		h = data->hgenerator|salt;
379 		if (rsvp_get(tp, h) == 0)
380 			return h;
381 	}
382 	return 0;
383 }
384 
tunnel_bts(struct rsvp_head * data)385 static int tunnel_bts(struct rsvp_head *data)
386 {
387 	int n = data->tgenerator >> 5;
388 	u32 b = 1 << (data->tgenerator & 0x1F);
389 
390 	if (data->tmap[n] & b)
391 		return 0;
392 	data->tmap[n] |= b;
393 	return 1;
394 }
395 
tunnel_recycle(struct rsvp_head * data)396 static void tunnel_recycle(struct rsvp_head *data)
397 {
398 	struct rsvp_session __rcu **sht = data->ht;
399 	u32 tmap[256/32];
400 	int h1, h2;
401 
402 	memset(tmap, 0, sizeof(tmap));
403 
404 	for (h1 = 0; h1 < 256; h1++) {
405 		struct rsvp_session *s;
406 		for (s = rtnl_dereference(sht[h1]); s;
407 		     s = rtnl_dereference(s->next)) {
408 			for (h2 = 0; h2 <= 16; h2++) {
409 				struct rsvp_filter *f;
410 
411 				for (f = rtnl_dereference(s->ht[h2]); f;
412 				     f = rtnl_dereference(f->next)) {
413 					if (f->tunnelhdr == 0)
414 						continue;
415 					data->tgenerator = f->res.classid;
416 					tunnel_bts(data);
417 				}
418 			}
419 		}
420 	}
421 
422 	memcpy(data->tmap, tmap, sizeof(tmap));
423 }
424 
gen_tunnel(struct rsvp_head * data)425 static u32 gen_tunnel(struct rsvp_head *data)
426 {
427 	int i, k;
428 
429 	for (k = 0; k < 2; k++) {
430 		for (i = 255; i > 0; i--) {
431 			if (++data->tgenerator == 0)
432 				data->tgenerator = 1;
433 			if (tunnel_bts(data))
434 				return data->tgenerator;
435 		}
436 		tunnel_recycle(data);
437 	}
438 	return 0;
439 }
440 
441 static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
442 	[TCA_RSVP_CLASSID]	= { .type = NLA_U32 },
443 	[TCA_RSVP_DST]		= { .type = NLA_BINARY,
444 				    .len = RSVP_DST_LEN * sizeof(u32) },
445 	[TCA_RSVP_SRC]		= { .type = NLA_BINARY,
446 				    .len = RSVP_DST_LEN * sizeof(u32) },
447 	[TCA_RSVP_PINFO]	= { .len = sizeof(struct tc_rsvp_pinfo) },
448 };
449 
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)450 static int rsvp_change(struct net *net, struct sk_buff *in_skb,
451 		       struct tcf_proto *tp, unsigned long base,
452 		       u32 handle,
453 		       struct nlattr **tca,
454 		       unsigned long *arg, bool ovr)
455 {
456 	struct rsvp_head *data = rtnl_dereference(tp->root);
457 	struct rsvp_filter *f, *nfp;
458 	struct rsvp_filter __rcu **fp;
459 	struct rsvp_session *nsp, *s;
460 	struct rsvp_session __rcu **sp;
461 	struct tc_rsvp_pinfo *pinfo = NULL;
462 	struct nlattr *opt = tca[TCA_OPTIONS];
463 	struct nlattr *tb[TCA_RSVP_MAX + 1];
464 	struct tcf_exts e;
465 	unsigned int h1, h2;
466 	__be32 *dst;
467 	int err;
468 
469 	if (opt == NULL)
470 		return handle ? -EINVAL : 0;
471 
472 	err = nla_parse_nested(tb, TCA_RSVP_MAX, opt, rsvp_policy);
473 	if (err < 0)
474 		return err;
475 
476 	tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE);
477 	err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
478 	if (err < 0)
479 		return err;
480 
481 	f = (struct rsvp_filter *)*arg;
482 	if (f) {
483 		/* Node exists: adjust only classid */
484 		struct rsvp_filter *n;
485 
486 		if (f->handle != handle && handle)
487 			goto errout2;
488 
489 		n = kmemdup(f, sizeof(*f), GFP_KERNEL);
490 		if (!n) {
491 			err = -ENOMEM;
492 			goto errout2;
493 		}
494 
495 		tcf_exts_init(&n->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
496 
497 		if (tb[TCA_RSVP_CLASSID]) {
498 			n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
499 			tcf_bind_filter(tp, &n->res, base);
500 		}
501 
502 		tcf_exts_change(tp, &n->exts, &e);
503 		rsvp_replace(tp, n, handle);
504 		return 0;
505 	}
506 
507 	/* Now more serious part... */
508 	err = -EINVAL;
509 	if (handle)
510 		goto errout2;
511 	if (tb[TCA_RSVP_DST] == NULL)
512 		goto errout2;
513 
514 	err = -ENOBUFS;
515 	f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL);
516 	if (f == NULL)
517 		goto errout2;
518 
519 	tcf_exts_init(&f->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
520 	h2 = 16;
521 	if (tb[TCA_RSVP_SRC]) {
522 		memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
523 		h2 = hash_src(f->src);
524 	}
525 	if (tb[TCA_RSVP_PINFO]) {
526 		pinfo = nla_data(tb[TCA_RSVP_PINFO]);
527 		f->spi = pinfo->spi;
528 		f->tunnelhdr = pinfo->tunnelhdr;
529 	}
530 	if (tb[TCA_RSVP_CLASSID])
531 		f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
532 
533 	dst = nla_data(tb[TCA_RSVP_DST]);
534 	h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
535 
536 	err = -ENOMEM;
537 	if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0)
538 		goto errout;
539 
540 	if (f->tunnelhdr) {
541 		err = -EINVAL;
542 		if (f->res.classid > 255)
543 			goto errout;
544 
545 		err = -ENOMEM;
546 		if (f->res.classid == 0 &&
547 		    (f->res.classid = gen_tunnel(data)) == 0)
548 			goto errout;
549 	}
550 
551 	for (sp = &data->ht[h1];
552 	     (s = rtnl_dereference(*sp)) != NULL;
553 	     sp = &s->next) {
554 		if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
555 		    pinfo && pinfo->protocol == s->protocol &&
556 		    memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 &&
557 #if RSVP_DST_LEN == 4
558 		    dst[0] == s->dst[0] &&
559 		    dst[1] == s->dst[1] &&
560 		    dst[2] == s->dst[2] &&
561 #endif
562 		    pinfo->tunnelid == s->tunnelid) {
563 
564 insert:
565 			/* OK, we found appropriate session */
566 
567 			fp = &s->ht[h2];
568 
569 			f->sess = s;
570 			if (f->tunnelhdr == 0)
571 				tcf_bind_filter(tp, &f->res, base);
572 
573 			tcf_exts_change(tp, &f->exts, &e);
574 
575 			fp = &s->ht[h2];
576 			for (nfp = rtnl_dereference(*fp); nfp;
577 			     fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
578 				__u32 mask = nfp->spi.mask & f->spi.mask;
579 
580 				if (mask != f->spi.mask)
581 					break;
582 			}
583 			RCU_INIT_POINTER(f->next, nfp);
584 			rcu_assign_pointer(*fp, f);
585 
586 			*arg = (unsigned long)f;
587 			return 0;
588 		}
589 	}
590 
591 	/* No session found. Create new one. */
592 
593 	err = -ENOBUFS;
594 	s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL);
595 	if (s == NULL)
596 		goto errout;
597 	memcpy(s->dst, dst, sizeof(s->dst));
598 
599 	if (pinfo) {
600 		s->dpi = pinfo->dpi;
601 		s->protocol = pinfo->protocol;
602 		s->tunnelid = pinfo->tunnelid;
603 	}
604 	sp = &data->ht[h1];
605 	for (nsp = rtnl_dereference(*sp); nsp;
606 	     sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
607 		if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask)
608 			break;
609 	}
610 	RCU_INIT_POINTER(s->next, nsp);
611 	rcu_assign_pointer(*sp, s);
612 
613 	goto insert;
614 
615 errout:
616 	kfree(f);
617 errout2:
618 	tcf_exts_destroy(&e);
619 	return err;
620 }
621 
rsvp_walk(struct tcf_proto * tp,struct tcf_walker * arg)622 static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
623 {
624 	struct rsvp_head *head = rtnl_dereference(tp->root);
625 	unsigned int h, h1;
626 
627 	if (arg->stop)
628 		return;
629 
630 	for (h = 0; h < 256; h++) {
631 		struct rsvp_session *s;
632 
633 		for (s = rtnl_dereference(head->ht[h]); s;
634 		     s = rtnl_dereference(s->next)) {
635 			for (h1 = 0; h1 <= 16; h1++) {
636 				struct rsvp_filter *f;
637 
638 				for (f = rtnl_dereference(s->ht[h1]); f;
639 				     f = rtnl_dereference(f->next)) {
640 					if (arg->count < arg->skip) {
641 						arg->count++;
642 						continue;
643 					}
644 					if (arg->fn(tp, (unsigned long)f, arg) < 0) {
645 						arg->stop = 1;
646 						return;
647 					}
648 					arg->count++;
649 				}
650 			}
651 		}
652 	}
653 }
654 
rsvp_dump(struct net * net,struct tcf_proto * tp,unsigned long fh,struct sk_buff * skb,struct tcmsg * t)655 static int rsvp_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
656 		     struct sk_buff *skb, struct tcmsg *t)
657 {
658 	struct rsvp_filter *f = (struct rsvp_filter *)fh;
659 	struct rsvp_session *s;
660 	unsigned char *b = skb_tail_pointer(skb);
661 	struct nlattr *nest;
662 	struct tc_rsvp_pinfo pinfo;
663 
664 	if (f == NULL)
665 		return skb->len;
666 	s = f->sess;
667 
668 	t->tcm_handle = f->handle;
669 
670 	nest = nla_nest_start(skb, TCA_OPTIONS);
671 	if (nest == NULL)
672 		goto nla_put_failure;
673 
674 	if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst))
675 		goto nla_put_failure;
676 	pinfo.dpi = s->dpi;
677 	pinfo.spi = f->spi;
678 	pinfo.protocol = s->protocol;
679 	pinfo.tunnelid = s->tunnelid;
680 	pinfo.tunnelhdr = f->tunnelhdr;
681 	pinfo.pad = 0;
682 	if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo))
683 		goto nla_put_failure;
684 	if (f->res.classid &&
685 	    nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid))
686 		goto nla_put_failure;
687 	if (((f->handle >> 8) & 0xFF) != 16 &&
688 	    nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src))
689 		goto nla_put_failure;
690 
691 	if (tcf_exts_dump(skb, &f->exts) < 0)
692 		goto nla_put_failure;
693 
694 	nla_nest_end(skb, nest);
695 
696 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
697 		goto nla_put_failure;
698 	return skb->len;
699 
700 nla_put_failure:
701 	nlmsg_trim(skb, b);
702 	return -1;
703 }
704 
705 static struct tcf_proto_ops RSVP_OPS __read_mostly = {
706 	.kind		=	RSVP_ID,
707 	.classify	=	rsvp_classify,
708 	.init		=	rsvp_init,
709 	.destroy	=	rsvp_destroy,
710 	.get		=	rsvp_get,
711 	.put		=	rsvp_put,
712 	.change		=	rsvp_change,
713 	.delete		=	rsvp_delete,
714 	.walk		=	rsvp_walk,
715 	.dump		=	rsvp_dump,
716 	.owner		=	THIS_MODULE,
717 };
718 
init_rsvp(void)719 static int __init init_rsvp(void)
720 {
721 	return register_tcf_proto_ops(&RSVP_OPS);
722 }
723 
exit_rsvp(void)724 static void __exit exit_rsvp(void)
725 {
726 	unregister_tcf_proto_ops(&RSVP_OPS);
727 }
728 
729 module_init(init_rsvp)
730 module_exit(exit_rsvp)
731