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