This source file includes following definitions.
- hash_dst
- hash_src
- rsvp_classify
- rsvp_replace
- rsvp_get
- rsvp_init
- __rsvp_delete_filter
- rsvp_delete_filter_work
- rsvp_delete_filter
- rsvp_destroy
- rsvp_delete
- gen_handle
- tunnel_bts
- tunnel_recycle
- gen_tunnel
- rsvp_change
- rsvp_walk
- rsvp_dump
- rsvp_bind_class
- init_rsvp
- exit_rsvp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
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
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
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
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
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
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
242
243
244 BUG_ON(1);
245 }
246
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
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
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
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
298 static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
299 {
300 tcf_unbind_filter(tp, &f->res);
301
302
303
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
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
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
359
360 for (i = 0; i <= 16; i++)
361 if (s->ht[i])
362 goto out;
363
364
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
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
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
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
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] = { .len = RSVP_DST_LEN * sizeof(u32) },
467 [TCA_RSVP_SRC] = { .len = RSVP_DST_LEN * sizeof(u32) },
468 [TCA_RSVP_PINFO] = { .len = sizeof(struct tc_rsvp_pinfo) },
469 };
470
471 static int rsvp_change(struct net *net, struct sk_buff *in_skb,
472 struct tcf_proto *tp, unsigned long base,
473 u32 handle,
474 struct nlattr **tca,
475 void **arg, bool ovr, bool rtnl_held,
476 struct netlink_ext_ack *extack)
477 {
478 struct rsvp_head *data = rtnl_dereference(tp->root);
479 struct rsvp_filter *f, *nfp;
480 struct rsvp_filter __rcu **fp;
481 struct rsvp_session *nsp, *s;
482 struct rsvp_session __rcu **sp;
483 struct tc_rsvp_pinfo *pinfo = NULL;
484 struct nlattr *opt = tca[TCA_OPTIONS];
485 struct nlattr *tb[TCA_RSVP_MAX + 1];
486 struct tcf_exts e;
487 unsigned int h1, h2;
488 __be32 *dst;
489 int err;
490
491 if (opt == NULL)
492 return handle ? -EINVAL : 0;
493
494 err = nla_parse_nested_deprecated(tb, TCA_RSVP_MAX, opt, rsvp_policy,
495 NULL);
496 if (err < 0)
497 return err;
498
499 err = tcf_exts_init(&e, net, TCA_RSVP_ACT, TCA_RSVP_POLICE);
500 if (err < 0)
501 return err;
502 err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr, true,
503 extack);
504 if (err < 0)
505 goto errout2;
506
507 f = *arg;
508 if (f) {
509
510 struct rsvp_filter *n;
511
512 if (f->handle != handle && handle)
513 goto errout2;
514
515 n = kmemdup(f, sizeof(*f), GFP_KERNEL);
516 if (!n) {
517 err = -ENOMEM;
518 goto errout2;
519 }
520
521 err = tcf_exts_init(&n->exts, net, TCA_RSVP_ACT,
522 TCA_RSVP_POLICE);
523 if (err < 0) {
524 kfree(n);
525 goto errout2;
526 }
527
528 if (tb[TCA_RSVP_CLASSID]) {
529 n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
530 tcf_bind_filter(tp, &n->res, base);
531 }
532
533 tcf_exts_change(&n->exts, &e);
534 rsvp_replace(tp, n, handle);
535 return 0;
536 }
537
538
539 err = -EINVAL;
540 if (handle)
541 goto errout2;
542 if (tb[TCA_RSVP_DST] == NULL)
543 goto errout2;
544
545 err = -ENOBUFS;
546 f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL);
547 if (f == NULL)
548 goto errout2;
549
550 err = tcf_exts_init(&f->exts, net, TCA_RSVP_ACT, TCA_RSVP_POLICE);
551 if (err < 0)
552 goto errout;
553 h2 = 16;
554 if (tb[TCA_RSVP_SRC]) {
555 memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
556 h2 = hash_src(f->src);
557 }
558 if (tb[TCA_RSVP_PINFO]) {
559 pinfo = nla_data(tb[TCA_RSVP_PINFO]);
560 f->spi = pinfo->spi;
561 f->tunnelhdr = pinfo->tunnelhdr;
562 }
563 if (tb[TCA_RSVP_CLASSID])
564 f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
565
566 dst = nla_data(tb[TCA_RSVP_DST]);
567 h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
568
569 err = -ENOMEM;
570 if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0)
571 goto errout;
572
573 if (f->tunnelhdr) {
574 err = -EINVAL;
575 if (f->res.classid > 255)
576 goto errout;
577
578 err = -ENOMEM;
579 if (f->res.classid == 0 &&
580 (f->res.classid = gen_tunnel(data)) == 0)
581 goto errout;
582 }
583
584 for (sp = &data->ht[h1];
585 (s = rtnl_dereference(*sp)) != NULL;
586 sp = &s->next) {
587 if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
588 pinfo && pinfo->protocol == s->protocol &&
589 memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 &&
590 #if RSVP_DST_LEN == 4
591 dst[0] == s->dst[0] &&
592 dst[1] == s->dst[1] &&
593 dst[2] == s->dst[2] &&
594 #endif
595 pinfo->tunnelid == s->tunnelid) {
596
597 insert:
598
599
600 fp = &s->ht[h2];
601
602 f->sess = s;
603 if (f->tunnelhdr == 0)
604 tcf_bind_filter(tp, &f->res, base);
605
606 tcf_exts_change(&f->exts, &e);
607
608 fp = &s->ht[h2];
609 for (nfp = rtnl_dereference(*fp); nfp;
610 fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
611 __u32 mask = nfp->spi.mask & f->spi.mask;
612
613 if (mask != f->spi.mask)
614 break;
615 }
616 RCU_INIT_POINTER(f->next, nfp);
617 rcu_assign_pointer(*fp, f);
618
619 *arg = f;
620 return 0;
621 }
622 }
623
624
625
626 err = -ENOBUFS;
627 s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL);
628 if (s == NULL)
629 goto errout;
630 memcpy(s->dst, dst, sizeof(s->dst));
631
632 if (pinfo) {
633 s->dpi = pinfo->dpi;
634 s->protocol = pinfo->protocol;
635 s->tunnelid = pinfo->tunnelid;
636 }
637 sp = &data->ht[h1];
638 for (nsp = rtnl_dereference(*sp); nsp;
639 sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
640 if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask)
641 break;
642 }
643 RCU_INIT_POINTER(s->next, nsp);
644 rcu_assign_pointer(*sp, s);
645
646 goto insert;
647
648 errout:
649 tcf_exts_destroy(&f->exts);
650 kfree(f);
651 errout2:
652 tcf_exts_destroy(&e);
653 return err;
654 }
655
656 static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg,
657 bool rtnl_held)
658 {
659 struct rsvp_head *head = rtnl_dereference(tp->root);
660 unsigned int h, h1;
661
662 if (arg->stop)
663 return;
664
665 for (h = 0; h < 256; h++) {
666 struct rsvp_session *s;
667
668 for (s = rtnl_dereference(head->ht[h]); s;
669 s = rtnl_dereference(s->next)) {
670 for (h1 = 0; h1 <= 16; h1++) {
671 struct rsvp_filter *f;
672
673 for (f = rtnl_dereference(s->ht[h1]); f;
674 f = rtnl_dereference(f->next)) {
675 if (arg->count < arg->skip) {
676 arg->count++;
677 continue;
678 }
679 if (arg->fn(tp, f, arg) < 0) {
680 arg->stop = 1;
681 return;
682 }
683 arg->count++;
684 }
685 }
686 }
687 }
688 }
689
690 static int rsvp_dump(struct net *net, struct tcf_proto *tp, void *fh,
691 struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
692 {
693 struct rsvp_filter *f = fh;
694 struct rsvp_session *s;
695 struct nlattr *nest;
696 struct tc_rsvp_pinfo pinfo;
697
698 if (f == NULL)
699 return skb->len;
700 s = f->sess;
701
702 t->tcm_handle = f->handle;
703
704 nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
705 if (nest == NULL)
706 goto nla_put_failure;
707
708 if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst))
709 goto nla_put_failure;
710 pinfo.dpi = s->dpi;
711 pinfo.spi = f->spi;
712 pinfo.protocol = s->protocol;
713 pinfo.tunnelid = s->tunnelid;
714 pinfo.tunnelhdr = f->tunnelhdr;
715 pinfo.pad = 0;
716 if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo))
717 goto nla_put_failure;
718 if (f->res.classid &&
719 nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid))
720 goto nla_put_failure;
721 if (((f->handle >> 8) & 0xFF) != 16 &&
722 nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src))
723 goto nla_put_failure;
724
725 if (tcf_exts_dump(skb, &f->exts) < 0)
726 goto nla_put_failure;
727
728 nla_nest_end(skb, nest);
729
730 if (tcf_exts_dump_stats(skb, &f->exts) < 0)
731 goto nla_put_failure;
732 return skb->len;
733
734 nla_put_failure:
735 nla_nest_cancel(skb, nest);
736 return -1;
737 }
738
739 static void rsvp_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
740 unsigned long base)
741 {
742 struct rsvp_filter *f = fh;
743
744 if (f && f->res.classid == classid) {
745 if (cl)
746 __tcf_bind_filter(q, &f->res, base);
747 else
748 __tcf_unbind_filter(q, &f->res);
749 }
750 }
751
752 static struct tcf_proto_ops RSVP_OPS __read_mostly = {
753 .kind = RSVP_ID,
754 .classify = rsvp_classify,
755 .init = rsvp_init,
756 .destroy = rsvp_destroy,
757 .get = rsvp_get,
758 .change = rsvp_change,
759 .delete = rsvp_delete,
760 .walk = rsvp_walk,
761 .dump = rsvp_dump,
762 .bind_class = rsvp_bind_class,
763 .owner = THIS_MODULE,
764 };
765
766 static int __init init_rsvp(void)
767 {
768 return register_tcf_proto_ops(&RSVP_OPS);
769 }
770
771 static void __exit exit_rsvp(void)
772 {
773 unregister_tcf_proto_ops(&RSVP_OPS);
774 }
775
776 module_init(init_rsvp)
777 module_exit(exit_rsvp)