| .. | .. |
|---|
| 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 |
|---|