.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * net/sched/cls_u32.c Ugly (or Universal) 32bit key Packet 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 | 4 | * |
---|
9 | 5 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
---|
10 | 6 | * |
---|
.. | .. |
---|
23 | 19 | * It is especially useful for link sharing combined with QoS; |
---|
24 | 20 | * pure RSVP doesn't need such a general approach and can use |
---|
25 | 21 | * much simpler (and faster) schemes, sort of cls_rsvp.c. |
---|
26 | | - * |
---|
27 | | - * JHS: We should remove the CONFIG_NET_CLS_IND from here |
---|
28 | | - * eventually when the meta match extension is made available |
---|
29 | 22 | * |
---|
30 | 23 | * nfmark match added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> |
---|
31 | 24 | */ |
---|
.. | .. |
---|
52 | 45 | u32 handle; |
---|
53 | 46 | struct tc_u_hnode __rcu *ht_up; |
---|
54 | 47 | struct tcf_exts exts; |
---|
55 | | -#ifdef CONFIG_NET_CLS_IND |
---|
56 | 48 | int ifindex; |
---|
57 | | -#endif |
---|
58 | 49 | u8 fshift; |
---|
59 | 50 | struct tcf_result res; |
---|
60 | 51 | struct tc_u_hnode __rcu *ht_down; |
---|
.. | .. |
---|
68 | 59 | u32 mask; |
---|
69 | 60 | u32 __percpu *pcpu_success; |
---|
70 | 61 | #endif |
---|
71 | | - struct tcf_proto *tp; |
---|
72 | 62 | struct rcu_work rwork; |
---|
73 | 63 | /* The 'sel' field MUST be the last field in structure to allow for |
---|
74 | 64 | * tc_u32_keys allocated at end of structure. |
---|
.. | .. |
---|
80 | 70 | struct tc_u_hnode __rcu *next; |
---|
81 | 71 | u32 handle; |
---|
82 | 72 | u32 prio; |
---|
83 | | - struct tc_u_common *tp_c; |
---|
84 | 73 | int refcnt; |
---|
85 | 74 | unsigned int divisor; |
---|
86 | 75 | struct idr handle_idr; |
---|
| 76 | + bool is_root; |
---|
87 | 77 | struct rcu_head rcu; |
---|
88 | 78 | u32 flags; |
---|
89 | 79 | /* The 'ht' field MUST be the last field in structure to allow for |
---|
90 | 80 | * more entries allocated at end of structure. |
---|
91 | 81 | */ |
---|
92 | | - struct tc_u_knode __rcu *ht[1]; |
---|
| 82 | + struct tc_u_knode __rcu *ht[]; |
---|
93 | 83 | }; |
---|
94 | 84 | |
---|
95 | 85 | struct tc_u_common { |
---|
.. | .. |
---|
98 | 88 | int refcnt; |
---|
99 | 89 | struct idr handle_idr; |
---|
100 | 90 | struct hlist_node hnode; |
---|
101 | | - struct rcu_head rcu; |
---|
| 91 | + long knodes; |
---|
102 | 92 | }; |
---|
103 | 93 | |
---|
104 | 94 | static inline unsigned int u32_hash_fold(__be32 key, |
---|
.. | .. |
---|
181 | 171 | if (n->sel.flags & TC_U32_TERMINAL) { |
---|
182 | 172 | |
---|
183 | 173 | *res = n->res; |
---|
184 | | -#ifdef CONFIG_NET_CLS_IND |
---|
185 | 174 | if (!tcf_match_indev(skb, n->ifindex)) { |
---|
186 | 175 | n = rcu_dereference_bh(n->next); |
---|
187 | 176 | goto next_knode; |
---|
188 | 177 | } |
---|
189 | | -#endif |
---|
190 | 178 | #ifdef CONFIG_CLS_U32_PERF |
---|
191 | 179 | __this_cpu_inc(n->pf->rhit); |
---|
192 | 180 | #endif |
---|
.. | .. |
---|
344 | 332 | return block->q; |
---|
345 | 333 | } |
---|
346 | 334 | |
---|
347 | | -static unsigned int tc_u_hash(const struct tcf_proto *tp) |
---|
| 335 | +static struct hlist_head *tc_u_hash(void *key) |
---|
348 | 336 | { |
---|
349 | | - return hash_ptr(tc_u_common_ptr(tp), U32_HASH_SHIFT); |
---|
| 337 | + return tc_u_common_hash + hash_ptr(key, U32_HASH_SHIFT); |
---|
350 | 338 | } |
---|
351 | 339 | |
---|
352 | | -static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp) |
---|
| 340 | +static struct tc_u_common *tc_u_common_find(void *key) |
---|
353 | 341 | { |
---|
354 | 342 | struct tc_u_common *tc; |
---|
355 | | - unsigned int h; |
---|
356 | | - |
---|
357 | | - h = tc_u_hash(tp); |
---|
358 | | - hlist_for_each_entry(tc, &tc_u_common_hash[h], hnode) { |
---|
359 | | - if (tc->ptr == tc_u_common_ptr(tp)) |
---|
| 343 | + hlist_for_each_entry(tc, tc_u_hash(key), hnode) { |
---|
| 344 | + if (tc->ptr == key) |
---|
360 | 345 | return tc; |
---|
361 | 346 | } |
---|
362 | 347 | return NULL; |
---|
.. | .. |
---|
365 | 350 | static int u32_init(struct tcf_proto *tp) |
---|
366 | 351 | { |
---|
367 | 352 | struct tc_u_hnode *root_ht; |
---|
368 | | - struct tc_u_common *tp_c; |
---|
369 | | - unsigned int h; |
---|
| 353 | + void *key = tc_u_common_ptr(tp); |
---|
| 354 | + struct tc_u_common *tp_c = tc_u_common_find(key); |
---|
370 | 355 | |
---|
371 | | - tp_c = tc_u_common_find(tp); |
---|
372 | | - |
---|
373 | | - root_ht = kzalloc(sizeof(*root_ht), GFP_KERNEL); |
---|
| 356 | + root_ht = kzalloc(struct_size(root_ht, ht, 1), GFP_KERNEL); |
---|
374 | 357 | if (root_ht == NULL) |
---|
375 | 358 | return -ENOBUFS; |
---|
376 | 359 | |
---|
377 | 360 | root_ht->refcnt++; |
---|
378 | 361 | root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : 0x80000000; |
---|
379 | 362 | root_ht->prio = tp->prio; |
---|
| 363 | + root_ht->is_root = true; |
---|
380 | 364 | idr_init(&root_ht->handle_idr); |
---|
381 | 365 | |
---|
382 | 366 | if (tp_c == NULL) { |
---|
383 | | - tp_c = kzalloc(sizeof(*tp_c), GFP_KERNEL); |
---|
| 367 | + tp_c = kzalloc(struct_size(tp_c, hlist->ht, 1), GFP_KERNEL); |
---|
384 | 368 | if (tp_c == NULL) { |
---|
385 | 369 | kfree(root_ht); |
---|
386 | 370 | return -ENOBUFS; |
---|
387 | 371 | } |
---|
388 | | - tp_c->ptr = tc_u_common_ptr(tp); |
---|
| 372 | + tp_c->ptr = key; |
---|
389 | 373 | INIT_HLIST_NODE(&tp_c->hnode); |
---|
390 | 374 | idr_init(&tp_c->handle_idr); |
---|
391 | 375 | |
---|
392 | | - h = tc_u_hash(tp); |
---|
393 | | - hlist_add_head(&tp_c->hnode, &tc_u_common_hash[h]); |
---|
| 376 | + hlist_add_head(&tp_c->hnode, tc_u_hash(key)); |
---|
394 | 377 | } |
---|
395 | 378 | |
---|
396 | 379 | tp_c->refcnt++; |
---|
397 | 380 | RCU_INIT_POINTER(root_ht->next, tp_c->hlist); |
---|
398 | 381 | rcu_assign_pointer(tp_c->hlist, root_ht); |
---|
399 | | - root_ht->tp_c = tp_c; |
---|
400 | 382 | |
---|
401 | 383 | root_ht->refcnt++; |
---|
402 | 384 | rcu_assign_pointer(tp->root, root_ht); |
---|
.. | .. |
---|
404 | 386 | return 0; |
---|
405 | 387 | } |
---|
406 | 388 | |
---|
407 | | -static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, |
---|
408 | | - bool free_pf) |
---|
| 389 | +static void __u32_destroy_key(struct tc_u_knode *n) |
---|
409 | 390 | { |
---|
410 | 391 | struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); |
---|
411 | 392 | |
---|
412 | 393 | tcf_exts_destroy(&n->exts); |
---|
413 | | - tcf_exts_put_net(&n->exts); |
---|
414 | 394 | if (ht && --ht->refcnt == 0) |
---|
415 | 395 | kfree(ht); |
---|
| 396 | + kfree(n); |
---|
| 397 | +} |
---|
| 398 | + |
---|
| 399 | +static void u32_destroy_key(struct tc_u_knode *n, bool free_pf) |
---|
| 400 | +{ |
---|
| 401 | + tcf_exts_put_net(&n->exts); |
---|
416 | 402 | #ifdef CONFIG_CLS_U32_PERF |
---|
417 | 403 | if (free_pf) |
---|
418 | 404 | free_percpu(n->pf); |
---|
.. | .. |
---|
421 | 407 | if (free_pf) |
---|
422 | 408 | free_percpu(n->pcpu_success); |
---|
423 | 409 | #endif |
---|
424 | | - kfree(n); |
---|
425 | | - return 0; |
---|
| 410 | + __u32_destroy_key(n); |
---|
426 | 411 | } |
---|
427 | 412 | |
---|
428 | 413 | /* u32_delete_key_rcu should be called when free'ing a copied |
---|
.. | .. |
---|
439 | 424 | struct tc_u_knode, |
---|
440 | 425 | rwork); |
---|
441 | 426 | rtnl_lock(); |
---|
442 | | - u32_destroy_key(key->tp, key, false); |
---|
| 427 | + u32_destroy_key(key, false); |
---|
443 | 428 | rtnl_unlock(); |
---|
444 | 429 | } |
---|
445 | 430 | |
---|
.. | .. |
---|
456 | 441 | struct tc_u_knode, |
---|
457 | 442 | rwork); |
---|
458 | 443 | rtnl_lock(); |
---|
459 | | - u32_destroy_key(key->tp, key, true); |
---|
| 444 | + u32_destroy_key(key, true); |
---|
460 | 445 | rtnl_unlock(); |
---|
461 | 446 | } |
---|
462 | 447 | |
---|
463 | 448 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) |
---|
464 | 449 | { |
---|
| 450 | + struct tc_u_common *tp_c = tp->data; |
---|
465 | 451 | struct tc_u_knode __rcu **kp; |
---|
466 | 452 | struct tc_u_knode *pkp; |
---|
467 | 453 | struct tc_u_hnode *ht = rtnl_dereference(key->ht_up); |
---|
.. | .. |
---|
472 | 458 | kp = &pkp->next, pkp = rtnl_dereference(*kp)) { |
---|
473 | 459 | if (pkp == key) { |
---|
474 | 460 | RCU_INIT_POINTER(*kp, key->next); |
---|
| 461 | + tp_c->knodes--; |
---|
475 | 462 | |
---|
476 | 463 | tcf_unbind_filter(tp, &key->res); |
---|
477 | 464 | idr_remove(&ht->handle_idr, key->handle); |
---|
.. | .. |
---|
497 | 484 | cls_u32.hnode.handle = h->handle; |
---|
498 | 485 | cls_u32.hnode.prio = h->prio; |
---|
499 | 486 | |
---|
500 | | - tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, false); |
---|
| 487 | + tc_setup_cb_call(block, TC_SETUP_CLSU32, &cls_u32, false, true); |
---|
501 | 488 | } |
---|
502 | 489 | |
---|
503 | 490 | static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h, |
---|
.. | .. |
---|
515 | 502 | cls_u32.hnode.handle = h->handle; |
---|
516 | 503 | cls_u32.hnode.prio = h->prio; |
---|
517 | 504 | |
---|
518 | | - err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw); |
---|
| 505 | + err = tc_setup_cb_call(block, TC_SETUP_CLSU32, &cls_u32, skip_sw, true); |
---|
519 | 506 | if (err < 0) { |
---|
520 | 507 | u32_clear_hw_hnode(tp, h, NULL); |
---|
521 | 508 | return err; |
---|
.. | .. |
---|
539 | 526 | cls_u32.command = TC_CLSU32_DELETE_KNODE; |
---|
540 | 527 | cls_u32.knode.handle = n->handle; |
---|
541 | 528 | |
---|
542 | | - tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, false); |
---|
543 | | - tcf_block_offload_dec(block, &n->flags); |
---|
| 529 | + tc_setup_cb_destroy(block, tp, TC_SETUP_CLSU32, &cls_u32, false, |
---|
| 530 | + &n->flags, &n->in_hw_count, true); |
---|
544 | 531 | } |
---|
545 | 532 | |
---|
546 | 533 | static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n, |
---|
.. | .. |
---|
564 | 551 | cls_u32.knode.mask = 0; |
---|
565 | 552 | #endif |
---|
566 | 553 | cls_u32.knode.sel = &n->sel; |
---|
| 554 | + cls_u32.knode.res = &n->res; |
---|
567 | 555 | cls_u32.knode.exts = &n->exts; |
---|
568 | 556 | if (n->ht_down) |
---|
569 | 557 | cls_u32.knode.link_handle = ht->handle; |
---|
570 | 558 | |
---|
571 | | - err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw); |
---|
572 | | - if (err < 0) { |
---|
| 559 | + err = tc_setup_cb_add(block, tp, TC_SETUP_CLSU32, &cls_u32, skip_sw, |
---|
| 560 | + &n->flags, &n->in_hw_count, true); |
---|
| 561 | + if (err) { |
---|
573 | 562 | u32_remove_hw_knode(tp, n, NULL); |
---|
574 | 563 | return err; |
---|
575 | | - } else if (err > 0) { |
---|
576 | | - n->in_hw_count = err; |
---|
577 | | - tcf_block_offload_inc(block, &n->flags); |
---|
578 | 564 | } |
---|
579 | 565 | |
---|
580 | 566 | if (skip_sw && !(n->flags & TCA_CLS_FLAGS_IN_HW)) |
---|
.. | .. |
---|
586 | 572 | static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, |
---|
587 | 573 | struct netlink_ext_ack *extack) |
---|
588 | 574 | { |
---|
| 575 | + struct tc_u_common *tp_c = tp->data; |
---|
589 | 576 | struct tc_u_knode *n; |
---|
590 | 577 | unsigned int h; |
---|
591 | 578 | |
---|
.. | .. |
---|
593 | 580 | while ((n = rtnl_dereference(ht->ht[h])) != NULL) { |
---|
594 | 581 | RCU_INIT_POINTER(ht->ht[h], |
---|
595 | 582 | rtnl_dereference(n->next)); |
---|
| 583 | + tp_c->knodes--; |
---|
596 | 584 | tcf_unbind_filter(tp, &n->res); |
---|
597 | 585 | u32_remove_hw_knode(tp, n, extack); |
---|
598 | 586 | idr_remove(&ht->handle_idr, n->handle); |
---|
599 | 587 | if (tcf_exts_get_net(&n->exts)) |
---|
600 | 588 | tcf_queue_work(&n->rwork, u32_delete_key_freepf_work); |
---|
601 | 589 | else |
---|
602 | | - u32_destroy_key(n->tp, n, true); |
---|
| 590 | + u32_destroy_key(n, true); |
---|
603 | 591 | } |
---|
604 | 592 | } |
---|
605 | 593 | } |
---|
.. | .. |
---|
632 | 620 | return -ENOENT; |
---|
633 | 621 | } |
---|
634 | 622 | |
---|
635 | | -static bool ht_empty(struct tc_u_hnode *ht) |
---|
636 | | -{ |
---|
637 | | - unsigned int h; |
---|
638 | | - |
---|
639 | | - for (h = 0; h <= ht->divisor; h++) |
---|
640 | | - if (rcu_access_pointer(ht->ht[h])) |
---|
641 | | - return false; |
---|
642 | | - |
---|
643 | | - return true; |
---|
644 | | -} |
---|
645 | | - |
---|
646 | | -static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) |
---|
| 623 | +static void u32_destroy(struct tcf_proto *tp, bool rtnl_held, |
---|
| 624 | + struct netlink_ext_ack *extack) |
---|
647 | 625 | { |
---|
648 | 626 | struct tc_u_common *tp_c = tp->data; |
---|
649 | 627 | struct tc_u_hnode *root_ht = rtnl_dereference(tp->root); |
---|
.. | .. |
---|
677 | 655 | } |
---|
678 | 656 | |
---|
679 | 657 | static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, |
---|
680 | | - struct netlink_ext_ack *extack) |
---|
| 658 | + bool rtnl_held, struct netlink_ext_ack *extack) |
---|
681 | 659 | { |
---|
682 | 660 | struct tc_u_hnode *ht = arg; |
---|
683 | | - struct tc_u_hnode *root_ht = rtnl_dereference(tp->root); |
---|
684 | 661 | struct tc_u_common *tp_c = tp->data; |
---|
685 | 662 | int ret = 0; |
---|
686 | | - |
---|
687 | | - if (ht == NULL) |
---|
688 | | - goto out; |
---|
689 | 663 | |
---|
690 | 664 | if (TC_U32_KEY(ht->handle)) { |
---|
691 | 665 | u32_remove_hw_knode(tp, (struct tc_u_knode *)ht, extack); |
---|
.. | .. |
---|
693 | 667 | goto out; |
---|
694 | 668 | } |
---|
695 | 669 | |
---|
696 | | - if (root_ht == ht) { |
---|
| 670 | + if (ht->is_root) { |
---|
697 | 671 | NL_SET_ERR_MSG_MOD(extack, "Not allowed to delete root node"); |
---|
698 | 672 | return -EINVAL; |
---|
699 | 673 | } |
---|
.. | .. |
---|
706 | 680 | } |
---|
707 | 681 | |
---|
708 | 682 | out: |
---|
709 | | - *last = true; |
---|
710 | | - if (root_ht) { |
---|
711 | | - if (root_ht->refcnt > 2) { |
---|
712 | | - *last = false; |
---|
713 | | - goto ret; |
---|
714 | | - } |
---|
715 | | - if (root_ht->refcnt == 2) { |
---|
716 | | - if (!ht_empty(root_ht)) { |
---|
717 | | - *last = false; |
---|
718 | | - goto ret; |
---|
719 | | - } |
---|
720 | | - } |
---|
721 | | - } |
---|
722 | | - |
---|
723 | | - if (tp_c->refcnt > 1) { |
---|
724 | | - *last = false; |
---|
725 | | - goto ret; |
---|
726 | | - } |
---|
727 | | - |
---|
728 | | - if (tp_c->refcnt == 1) { |
---|
729 | | - struct tc_u_hnode *ht; |
---|
730 | | - |
---|
731 | | - for (ht = rtnl_dereference(tp_c->hlist); |
---|
732 | | - ht; |
---|
733 | | - ht = rtnl_dereference(ht->next)) |
---|
734 | | - if (!ht_empty(ht)) { |
---|
735 | | - *last = false; |
---|
736 | | - break; |
---|
737 | | - } |
---|
738 | | - } |
---|
739 | | - |
---|
740 | | -ret: |
---|
| 683 | + *last = tp_c->refcnt == 1 && tp_c->knodes == 0; |
---|
741 | 684 | return ret; |
---|
742 | 685 | } |
---|
743 | 686 | |
---|
.. | .. |
---|
768 | 711 | }; |
---|
769 | 712 | |
---|
770 | 713 | static int u32_set_parms(struct net *net, struct tcf_proto *tp, |
---|
771 | | - unsigned long base, struct tc_u_hnode *ht, |
---|
| 714 | + unsigned long base, |
---|
772 | 715 | struct tc_u_knode *n, struct nlattr **tb, |
---|
773 | 716 | struct nlattr *est, bool ovr, |
---|
774 | 717 | struct netlink_ext_ack *extack) |
---|
775 | 718 | { |
---|
776 | 719 | int err; |
---|
777 | 720 | |
---|
778 | | - err = tcf_exts_validate(net, tp, tb, est, &n->exts, ovr, extack); |
---|
| 721 | + err = tcf_exts_validate(net, tp, tb, est, &n->exts, ovr, true, extack); |
---|
779 | 722 | if (err < 0) |
---|
780 | 723 | return err; |
---|
781 | 724 | |
---|
.. | .. |
---|
789 | 732 | } |
---|
790 | 733 | |
---|
791 | 734 | if (handle) { |
---|
792 | | - ht_down = u32_lookup_ht(ht->tp_c, handle); |
---|
| 735 | + ht_down = u32_lookup_ht(tp->data, handle); |
---|
793 | 736 | |
---|
794 | 737 | if (!ht_down) { |
---|
795 | 738 | NL_SET_ERR_MSG_MOD(extack, "Link hash table not found"); |
---|
| 739 | + return -EINVAL; |
---|
| 740 | + } |
---|
| 741 | + if (ht_down->is_root) { |
---|
| 742 | + NL_SET_ERR_MSG_MOD(extack, "Not linking to root node"); |
---|
796 | 743 | return -EINVAL; |
---|
797 | 744 | } |
---|
798 | 745 | ht_down->refcnt++; |
---|
.. | .. |
---|
809 | 756 | tcf_bind_filter(tp, &n->res, base); |
---|
810 | 757 | } |
---|
811 | 758 | |
---|
812 | | -#ifdef CONFIG_NET_CLS_IND |
---|
813 | 759 | if (tb[TCA_U32_INDEV]) { |
---|
814 | 760 | int ret; |
---|
815 | 761 | ret = tcf_change_indev(net, tb[TCA_U32_INDEV], extack); |
---|
.. | .. |
---|
817 | 763 | return -EINVAL; |
---|
818 | 764 | n->ifindex = ret; |
---|
819 | 765 | } |
---|
820 | | -#endif |
---|
821 | 766 | return 0; |
---|
822 | 767 | } |
---|
823 | 768 | |
---|
.. | .. |
---|
848 | 793 | rcu_assign_pointer(*ins, n); |
---|
849 | 794 | } |
---|
850 | 795 | |
---|
851 | | -static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp, |
---|
| 796 | +static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, |
---|
852 | 797 | struct tc_u_knode *n) |
---|
853 | 798 | { |
---|
854 | 799 | struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); |
---|
855 | 800 | struct tc_u32_sel *s = &n->sel; |
---|
856 | 801 | struct tc_u_knode *new; |
---|
857 | 802 | |
---|
858 | | - new = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), |
---|
859 | | - GFP_KERNEL); |
---|
860 | | - |
---|
| 803 | + new = kzalloc(struct_size(new, sel.keys, s->nkeys), GFP_KERNEL); |
---|
861 | 804 | if (!new) |
---|
862 | 805 | return NULL; |
---|
863 | 806 | |
---|
.. | .. |
---|
865 | 808 | new->handle = n->handle; |
---|
866 | 809 | RCU_INIT_POINTER(new->ht_up, n->ht_up); |
---|
867 | 810 | |
---|
868 | | -#ifdef CONFIG_NET_CLS_IND |
---|
869 | 811 | new->ifindex = n->ifindex; |
---|
870 | | -#endif |
---|
871 | 812 | new->fshift = n->fshift; |
---|
872 | 813 | new->res = n->res; |
---|
873 | 814 | new->flags = n->flags; |
---|
874 | 815 | RCU_INIT_POINTER(new->ht_down, ht); |
---|
875 | | - |
---|
876 | | - /* bump reference count as long as we hold pointer to structure */ |
---|
877 | | - if (ht) |
---|
878 | | - ht->refcnt++; |
---|
879 | 816 | |
---|
880 | 817 | #ifdef CONFIG_CLS_U32_PERF |
---|
881 | 818 | /* Statistics may be incremented by readers during update |
---|
.. | .. |
---|
891 | 828 | /* Similarly success statistics must be moved as pointers */ |
---|
892 | 829 | new->pcpu_success = n->pcpu_success; |
---|
893 | 830 | #endif |
---|
894 | | - new->tp = tp; |
---|
895 | | - memcpy(&new->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key)); |
---|
| 831 | + memcpy(&new->sel, s, struct_size(s, keys, s->nkeys)); |
---|
896 | 832 | |
---|
897 | | - if (tcf_exts_init(&new->exts, TCA_U32_ACT, TCA_U32_POLICE)) { |
---|
| 833 | + if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) { |
---|
898 | 834 | kfree(new); |
---|
899 | 835 | return NULL; |
---|
900 | 836 | } |
---|
| 837 | + |
---|
| 838 | + /* bump reference count as long as we hold pointer to structure */ |
---|
| 839 | + if (ht) |
---|
| 840 | + ht->refcnt++; |
---|
901 | 841 | |
---|
902 | 842 | return new; |
---|
903 | 843 | } |
---|
904 | 844 | |
---|
905 | 845 | static int u32_change(struct net *net, struct sk_buff *in_skb, |
---|
906 | 846 | struct tcf_proto *tp, unsigned long base, u32 handle, |
---|
907 | | - struct nlattr **tca, void **arg, bool ovr, |
---|
| 847 | + struct nlattr **tca, void **arg, bool ovr, bool rtnl_held, |
---|
908 | 848 | struct netlink_ext_ack *extack) |
---|
909 | 849 | { |
---|
910 | 850 | struct tc_u_common *tp_c = tp->data; |
---|
.. | .. |
---|
916 | 856 | u32 htid, flags = 0; |
---|
917 | 857 | size_t sel_size; |
---|
918 | 858 | int err; |
---|
919 | | -#ifdef CONFIG_CLS_U32_PERF |
---|
920 | | - size_t size; |
---|
921 | | -#endif |
---|
922 | 859 | |
---|
923 | 860 | if (!opt) { |
---|
924 | 861 | if (handle) { |
---|
.. | .. |
---|
929 | 866 | } |
---|
930 | 867 | } |
---|
931 | 868 | |
---|
932 | | - err = nla_parse_nested(tb, TCA_U32_MAX, opt, u32_policy, extack); |
---|
| 869 | + err = nla_parse_nested_deprecated(tb, TCA_U32_MAX, opt, u32_policy, |
---|
| 870 | + extack); |
---|
933 | 871 | if (err < 0) |
---|
934 | 872 | return err; |
---|
935 | 873 | |
---|
.. | .. |
---|
956 | 894 | return -EINVAL; |
---|
957 | 895 | } |
---|
958 | 896 | |
---|
959 | | - new = u32_init_knode(tp, n); |
---|
| 897 | + new = u32_init_knode(net, tp, n); |
---|
960 | 898 | if (!new) |
---|
961 | 899 | return -ENOMEM; |
---|
962 | 900 | |
---|
963 | | - err = u32_set_parms(net, tp, base, |
---|
964 | | - rtnl_dereference(n->ht_up), new, tb, |
---|
| 901 | + err = u32_set_parms(net, tp, base, new, tb, |
---|
965 | 902 | tca[TCA_RATE], ovr, extack); |
---|
966 | 903 | |
---|
967 | 904 | if (err) { |
---|
968 | | - u32_destroy_key(tp, new, false); |
---|
| 905 | + __u32_destroy_key(new); |
---|
969 | 906 | return err; |
---|
970 | 907 | } |
---|
971 | 908 | |
---|
972 | 909 | err = u32_replace_hw_knode(tp, new, flags, extack); |
---|
973 | 910 | if (err) { |
---|
974 | | - u32_destroy_key(tp, new, false); |
---|
| 911 | + __u32_destroy_key(new); |
---|
975 | 912 | return err; |
---|
976 | 913 | } |
---|
977 | 914 | |
---|
.. | .. |
---|
988 | 925 | if (tb[TCA_U32_DIVISOR]) { |
---|
989 | 926 | unsigned int divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); |
---|
990 | 927 | |
---|
991 | | - if (--divisor > 0x100) { |
---|
| 928 | + if (!is_power_of_2(divisor)) { |
---|
| 929 | + NL_SET_ERR_MSG_MOD(extack, "Divisor is not a power of 2"); |
---|
| 930 | + return -EINVAL; |
---|
| 931 | + } |
---|
| 932 | + if (divisor-- > 0x100) { |
---|
992 | 933 | NL_SET_ERR_MSG_MOD(extack, "Exceeded maximum 256 hash buckets"); |
---|
993 | 934 | return -EINVAL; |
---|
994 | 935 | } |
---|
.. | .. |
---|
996 | 937 | NL_SET_ERR_MSG_MOD(extack, "Divisor can only be used on a hash table"); |
---|
997 | 938 | return -EINVAL; |
---|
998 | 939 | } |
---|
999 | | - ht = kzalloc(sizeof(*ht) + divisor*sizeof(void *), GFP_KERNEL); |
---|
| 940 | + ht = kzalloc(struct_size(ht, ht, divisor + 1), GFP_KERNEL); |
---|
1000 | 941 | if (ht == NULL) |
---|
1001 | 942 | return -ENOBUFS; |
---|
1002 | 943 | if (handle == 0) { |
---|
.. | .. |
---|
1013 | 954 | return err; |
---|
1014 | 955 | } |
---|
1015 | 956 | } |
---|
1016 | | - ht->tp_c = tp_c; |
---|
1017 | 957 | ht->refcnt = 1; |
---|
1018 | 958 | ht->divisor = divisor; |
---|
1019 | 959 | ht->handle = handle; |
---|
.. | .. |
---|
1083 | 1023 | goto erridr; |
---|
1084 | 1024 | } |
---|
1085 | 1025 | |
---|
1086 | | - n = kzalloc(offsetof(typeof(*n), sel) + sel_size, GFP_KERNEL); |
---|
| 1026 | + n = kzalloc(struct_size(n, sel.keys, s->nkeys), GFP_KERNEL); |
---|
1087 | 1027 | if (n == NULL) { |
---|
1088 | 1028 | err = -ENOBUFS; |
---|
1089 | 1029 | goto erridr; |
---|
1090 | 1030 | } |
---|
1091 | 1031 | |
---|
1092 | 1032 | #ifdef CONFIG_CLS_U32_PERF |
---|
1093 | | - size = sizeof(struct tc_u32_pcnt) + s->nkeys * sizeof(u64); |
---|
1094 | | - n->pf = __alloc_percpu(size, __alignof__(struct tc_u32_pcnt)); |
---|
| 1033 | + n->pf = __alloc_percpu(struct_size(n->pf, kcnts, s->nkeys), |
---|
| 1034 | + __alignof__(struct tc_u32_pcnt)); |
---|
1095 | 1035 | if (!n->pf) { |
---|
1096 | 1036 | err = -ENOBUFS; |
---|
1097 | 1037 | goto errfree; |
---|
.. | .. |
---|
1103 | 1043 | n->handle = handle; |
---|
1104 | 1044 | n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; |
---|
1105 | 1045 | n->flags = flags; |
---|
1106 | | - n->tp = tp; |
---|
1107 | 1046 | |
---|
1108 | | - err = tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE); |
---|
| 1047 | + err = tcf_exts_init(&n->exts, net, TCA_U32_ACT, TCA_U32_POLICE); |
---|
1109 | 1048 | if (err < 0) |
---|
1110 | 1049 | goto errout; |
---|
1111 | 1050 | |
---|
.. | .. |
---|
1125 | 1064 | } |
---|
1126 | 1065 | #endif |
---|
1127 | 1066 | |
---|
1128 | | - err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE], ovr, |
---|
| 1067 | + err = u32_set_parms(net, tp, base, n, tb, tca[TCA_RATE], ovr, |
---|
1129 | 1068 | extack); |
---|
1130 | 1069 | if (err == 0) { |
---|
1131 | 1070 | struct tc_u_knode __rcu **ins; |
---|
.. | .. |
---|
1146 | 1085 | |
---|
1147 | 1086 | RCU_INIT_POINTER(n->next, pins); |
---|
1148 | 1087 | rcu_assign_pointer(*ins, n); |
---|
| 1088 | + tp_c->knodes++; |
---|
1149 | 1089 | *arg = n; |
---|
1150 | 1090 | return 0; |
---|
1151 | 1091 | } |
---|
.. | .. |
---|
1167 | 1107 | return err; |
---|
1168 | 1108 | } |
---|
1169 | 1109 | |
---|
1170 | | -static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg) |
---|
| 1110 | +static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg, |
---|
| 1111 | + bool rtnl_held) |
---|
1171 | 1112 | { |
---|
1172 | 1113 | struct tc_u_common *tp_c = tp->data; |
---|
1173 | 1114 | struct tc_u_hnode *ht; |
---|
.. | .. |
---|
1208 | 1149 | } |
---|
1209 | 1150 | |
---|
1210 | 1151 | static int u32_reoffload_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, |
---|
1211 | | - bool add, tc_setup_cb_t *cb, void *cb_priv, |
---|
| 1152 | + bool add, flow_setup_cb_t *cb, void *cb_priv, |
---|
1212 | 1153 | struct netlink_ext_ack *extack) |
---|
1213 | 1154 | { |
---|
1214 | 1155 | struct tc_cls_u32_offload cls_u32 = {}; |
---|
.. | .. |
---|
1228 | 1169 | } |
---|
1229 | 1170 | |
---|
1230 | 1171 | static int u32_reoffload_knode(struct tcf_proto *tp, struct tc_u_knode *n, |
---|
1231 | | - bool add, tc_setup_cb_t *cb, void *cb_priv, |
---|
| 1172 | + bool add, flow_setup_cb_t *cb, void *cb_priv, |
---|
1232 | 1173 | struct netlink_ext_ack *extack) |
---|
1233 | 1174 | { |
---|
1234 | 1175 | struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); |
---|
.. | .. |
---|
1251 | 1192 | cls_u32.knode.mask = 0; |
---|
1252 | 1193 | #endif |
---|
1253 | 1194 | cls_u32.knode.sel = &n->sel; |
---|
| 1195 | + cls_u32.knode.res = &n->res; |
---|
1254 | 1196 | cls_u32.knode.exts = &n->exts; |
---|
1255 | 1197 | if (n->ht_down) |
---|
1256 | 1198 | cls_u32.knode.link_handle = ht->handle; |
---|
1257 | 1199 | } |
---|
1258 | 1200 | |
---|
1259 | | - err = cb(TC_SETUP_CLSU32, &cls_u32, cb_priv); |
---|
1260 | | - if (err) { |
---|
1261 | | - if (add && tc_skip_sw(n->flags)) |
---|
1262 | | - return err; |
---|
1263 | | - return 0; |
---|
1264 | | - } |
---|
1265 | | - |
---|
1266 | | - tc_cls_offload_cnt_update(block, &n->in_hw_count, &n->flags, add); |
---|
| 1201 | + err = tc_setup_cb_reoffload(block, tp, add, cb, TC_SETUP_CLSU32, |
---|
| 1202 | + &cls_u32, cb_priv, &n->flags, |
---|
| 1203 | + &n->in_hw_count); |
---|
| 1204 | + if (err) |
---|
| 1205 | + return err; |
---|
1267 | 1206 | |
---|
1268 | 1207 | return 0; |
---|
1269 | 1208 | } |
---|
1270 | 1209 | |
---|
1271 | | -static int u32_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, |
---|
| 1210 | +static int u32_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, |
---|
1272 | 1211 | void *cb_priv, struct netlink_ext_ack *extack) |
---|
1273 | 1212 | { |
---|
1274 | 1213 | struct tc_u_common *tp_c = tp->data; |
---|
.. | .. |
---|
1329 | 1268 | } |
---|
1330 | 1269 | |
---|
1331 | 1270 | static int u32_dump(struct net *net, struct tcf_proto *tp, void *fh, |
---|
1332 | | - struct sk_buff *skb, struct tcmsg *t) |
---|
| 1271 | + struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) |
---|
1333 | 1272 | { |
---|
1334 | 1273 | struct tc_u_knode *n = fh; |
---|
1335 | 1274 | struct tc_u_hnode *ht_up, *ht_down; |
---|
.. | .. |
---|
1340 | 1279 | |
---|
1341 | 1280 | t->tcm_handle = n->handle; |
---|
1342 | 1281 | |
---|
1343 | | - nest = nla_nest_start(skb, TCA_OPTIONS); |
---|
| 1282 | + nest = nla_nest_start_noflag(skb, TCA_OPTIONS); |
---|
1344 | 1283 | if (nest == NULL) |
---|
1345 | 1284 | goto nla_put_failure; |
---|
1346 | 1285 | |
---|
.. | .. |
---|
1356 | 1295 | int cpu; |
---|
1357 | 1296 | #endif |
---|
1358 | 1297 | |
---|
1359 | | - if (nla_put(skb, TCA_U32_SEL, |
---|
1360 | | - sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key), |
---|
| 1298 | + if (nla_put(skb, TCA_U32_SEL, struct_size(&n->sel, keys, n->sel.nkeys), |
---|
1361 | 1299 | &n->sel)) |
---|
1362 | 1300 | goto nla_put_failure; |
---|
1363 | 1301 | |
---|
.. | .. |
---|
1400 | 1338 | if (tcf_exts_dump(skb, &n->exts) < 0) |
---|
1401 | 1339 | goto nla_put_failure; |
---|
1402 | 1340 | |
---|
1403 | | -#ifdef CONFIG_NET_CLS_IND |
---|
1404 | 1341 | if (n->ifindex) { |
---|
1405 | 1342 | struct net_device *dev; |
---|
1406 | 1343 | dev = __dev_get_by_index(net, n->ifindex); |
---|
1407 | 1344 | if (dev && nla_put_string(skb, TCA_U32_INDEV, dev->name)) |
---|
1408 | 1345 | goto nla_put_failure; |
---|
1409 | 1346 | } |
---|
1410 | | -#endif |
---|
1411 | 1347 | #ifdef CONFIG_CLS_U32_PERF |
---|
1412 | | - gpf = kzalloc(sizeof(struct tc_u32_pcnt) + |
---|
1413 | | - n->sel.nkeys * sizeof(u64), |
---|
1414 | | - GFP_KERNEL); |
---|
| 1348 | + gpf = kzalloc(struct_size(gpf, kcnts, n->sel.nkeys), GFP_KERNEL); |
---|
1415 | 1349 | if (!gpf) |
---|
1416 | 1350 | goto nla_put_failure; |
---|
1417 | 1351 | |
---|
.. | .. |
---|
1425 | 1359 | gpf->kcnts[i] += pf->kcnts[i]; |
---|
1426 | 1360 | } |
---|
1427 | 1361 | |
---|
1428 | | - if (nla_put_64bit(skb, TCA_U32_PCNT, |
---|
1429 | | - sizeof(struct tc_u32_pcnt) + |
---|
1430 | | - n->sel.nkeys * sizeof(u64), |
---|
| 1362 | + if (nla_put_64bit(skb, TCA_U32_PCNT, struct_size(gpf, kcnts, n->sel.nkeys), |
---|
1431 | 1363 | gpf, TCA_U32_PAD)) { |
---|
1432 | 1364 | kfree(gpf); |
---|
1433 | 1365 | goto nla_put_failure; |
---|
.. | .. |
---|
1471 | 1403 | #ifdef CONFIG_CLS_U32_PERF |
---|
1472 | 1404 | pr_info(" Performance counters on\n"); |
---|
1473 | 1405 | #endif |
---|
1474 | | -#ifdef CONFIG_NET_CLS_IND |
---|
1475 | 1406 | pr_info(" input device check on\n"); |
---|
1476 | | -#endif |
---|
1477 | 1407 | #ifdef CONFIG_NET_CLS_ACT |
---|
1478 | 1408 | pr_info(" Actions configured\n"); |
---|
1479 | 1409 | #endif |
---|