| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * net/sched/ife.c Inter-FE action based on ForCES WG InterFE LFB |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 9 | 10 | * Subsystem" |
|---|
| 10 | 11 | * Authors: Jamal Hadi Salim and Damascene M. Joachimpillai |
|---|
| 11 | 12 | * |
|---|
| 12 | | - * This program is free software; you can redistribute it and/or |
|---|
| 13 | | - * modify it under the terms of the GNU General Public License |
|---|
| 14 | | - * as published by the Free Software Foundation; either version |
|---|
| 15 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 16 | | - * |
|---|
| 17 | 13 | * copyright Jamal Hadi Salim (2015) |
|---|
| 18 | | - * |
|---|
| 19 | 14 | */ |
|---|
| 20 | 15 | |
|---|
| 21 | 16 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 29 | 24 | #include <net/net_namespace.h> |
|---|
| 30 | 25 | #include <net/netlink.h> |
|---|
| 31 | 26 | #include <net/pkt_sched.h> |
|---|
| 27 | +#include <net/pkt_cls.h> |
|---|
| 32 | 28 | #include <uapi/linux/tc_act/tc_ife.h> |
|---|
| 33 | 29 | #include <net/tc_act/tc_ife.h> |
|---|
| 34 | 30 | #include <linux/etherdevice.h> |
|---|
| .. | .. |
|---|
| 386 | 382 | if (list_empty(&ife->metalist)) |
|---|
| 387 | 383 | return 0; |
|---|
| 388 | 384 | |
|---|
| 389 | | - nest = nla_nest_start(skb, TCA_IFE_METALST); |
|---|
| 385 | + nest = nla_nest_start_noflag(skb, TCA_IFE_METALST); |
|---|
| 390 | 386 | if (!nest) |
|---|
| 391 | 387 | goto out_nlmsg_trim; |
|---|
| 392 | 388 | |
|---|
| .. | .. |
|---|
| 440 | 436 | kfree_rcu(p, rcu); |
|---|
| 441 | 437 | } |
|---|
| 442 | 438 | |
|---|
| 439 | +static int load_metalist(struct nlattr **tb, bool rtnl_held) |
|---|
| 440 | +{ |
|---|
| 441 | + int i; |
|---|
| 442 | + |
|---|
| 443 | + for (i = 1; i < max_metacnt; i++) { |
|---|
| 444 | + if (tb[i]) { |
|---|
| 445 | + void *val = nla_data(tb[i]); |
|---|
| 446 | + int len = nla_len(tb[i]); |
|---|
| 447 | + int rc; |
|---|
| 448 | + |
|---|
| 449 | + rc = load_metaops_and_vet(i, val, len, rtnl_held); |
|---|
| 450 | + if (rc != 0) |
|---|
| 451 | + return rc; |
|---|
| 452 | + } |
|---|
| 453 | + } |
|---|
| 454 | + |
|---|
| 455 | + return 0; |
|---|
| 456 | +} |
|---|
| 457 | + |
|---|
| 443 | 458 | static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb, |
|---|
| 444 | 459 | bool exists, bool rtnl_held) |
|---|
| 445 | 460 | { |
|---|
| .. | .. |
|---|
| 453 | 468 | val = nla_data(tb[i]); |
|---|
| 454 | 469 | len = nla_len(tb[i]); |
|---|
| 455 | 470 | |
|---|
| 456 | | - rc = load_metaops_and_vet(i, val, len, rtnl_held); |
|---|
| 457 | | - if (rc != 0) |
|---|
| 458 | | - return rc; |
|---|
| 459 | | - |
|---|
| 460 | 471 | rc = add_metainfo(ife, i, val, len, exists); |
|---|
| 461 | 472 | if (rc) |
|---|
| 462 | 473 | return rc; |
|---|
| .. | .. |
|---|
| 469 | 480 | static int tcf_ife_init(struct net *net, struct nlattr *nla, |
|---|
| 470 | 481 | struct nlattr *est, struct tc_action **a, |
|---|
| 471 | 482 | int ovr, int bind, bool rtnl_held, |
|---|
| 483 | + struct tcf_proto *tp, u32 flags, |
|---|
| 472 | 484 | struct netlink_ext_ack *extack) |
|---|
| 473 | 485 | { |
|---|
| 474 | 486 | struct tc_action_net *tn = net_generic(net, ife_net_id); |
|---|
| 475 | 487 | struct nlattr *tb[TCA_IFE_MAX + 1]; |
|---|
| 476 | 488 | struct nlattr *tb2[IFE_META_MAX + 1]; |
|---|
| 489 | + struct tcf_chain *goto_ch = NULL; |
|---|
| 477 | 490 | struct tcf_ife_params *p; |
|---|
| 478 | 491 | struct tcf_ife_info *ife; |
|---|
| 479 | 492 | u16 ife_type = ETH_P_IFE; |
|---|
| .. | .. |
|---|
| 490 | 503 | return -EINVAL; |
|---|
| 491 | 504 | } |
|---|
| 492 | 505 | |
|---|
| 493 | | - err = nla_parse_nested(tb, TCA_IFE_MAX, nla, ife_policy, NULL); |
|---|
| 506 | + err = nla_parse_nested_deprecated(tb, TCA_IFE_MAX, nla, ife_policy, |
|---|
| 507 | + NULL); |
|---|
| 494 | 508 | if (err < 0) |
|---|
| 495 | 509 | return err; |
|---|
| 496 | 510 | |
|---|
| .. | .. |
|---|
| 510 | 524 | if (!p) |
|---|
| 511 | 525 | return -ENOMEM; |
|---|
| 512 | 526 | |
|---|
| 527 | + if (tb[TCA_IFE_METALST]) { |
|---|
| 528 | + err = nla_parse_nested_deprecated(tb2, IFE_META_MAX, |
|---|
| 529 | + tb[TCA_IFE_METALST], NULL, |
|---|
| 530 | + NULL); |
|---|
| 531 | + if (err) { |
|---|
| 532 | + kfree(p); |
|---|
| 533 | + return err; |
|---|
| 534 | + } |
|---|
| 535 | + err = load_metalist(tb2, rtnl_held); |
|---|
| 536 | + if (err) { |
|---|
| 537 | + kfree(p); |
|---|
| 538 | + return err; |
|---|
| 539 | + } |
|---|
| 540 | + } |
|---|
| 541 | + |
|---|
| 513 | 542 | index = parm->index; |
|---|
| 514 | 543 | err = tcf_idr_check_alloc(tn, &index, a, bind); |
|---|
| 515 | 544 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 524 | 553 | |
|---|
| 525 | 554 | if (!exists) { |
|---|
| 526 | 555 | ret = tcf_idr_create(tn, index, est, a, &act_ife_ops, |
|---|
| 527 | | - bind, true); |
|---|
| 556 | + bind, true, flags); |
|---|
| 528 | 557 | if (ret) { |
|---|
| 529 | 558 | tcf_idr_cleanup(tn, index); |
|---|
| 530 | 559 | kfree(p); |
|---|
| .. | .. |
|---|
| 538 | 567 | } |
|---|
| 539 | 568 | |
|---|
| 540 | 569 | ife = to_ife(*a); |
|---|
| 570 | + if (ret == ACT_P_CREATED) |
|---|
| 571 | + INIT_LIST_HEAD(&ife->metalist); |
|---|
| 572 | + |
|---|
| 573 | + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
|---|
| 574 | + if (err < 0) |
|---|
| 575 | + goto release_idr; |
|---|
| 576 | + |
|---|
| 541 | 577 | p->flags = parm->flags; |
|---|
| 542 | 578 | |
|---|
| 543 | 579 | if (parm->flags & IFE_ENCODE) { |
|---|
| .. | .. |
|---|
| 563 | 599 | p->eth_type = ife_type; |
|---|
| 564 | 600 | } |
|---|
| 565 | 601 | |
|---|
| 566 | | - |
|---|
| 567 | | - if (ret == ACT_P_CREATED) |
|---|
| 568 | | - INIT_LIST_HEAD(&ife->metalist); |
|---|
| 569 | | - |
|---|
| 570 | 602 | if (tb[TCA_IFE_METALST]) { |
|---|
| 571 | | - err = nla_parse_nested(tb2, IFE_META_MAX, tb[TCA_IFE_METALST], |
|---|
| 572 | | - NULL, NULL); |
|---|
| 573 | | - if (err) { |
|---|
| 574 | | -metadata_parse_err: |
|---|
| 575 | | - tcf_idr_release(*a, bind); |
|---|
| 576 | | - kfree(p); |
|---|
| 577 | | - return err; |
|---|
| 578 | | - } |
|---|
| 579 | | - |
|---|
| 580 | 603 | err = populate_metalist(ife, tb2, exists, rtnl_held); |
|---|
| 581 | 604 | if (err) |
|---|
| 582 | 605 | goto metadata_parse_err; |
|---|
| 583 | | - |
|---|
| 584 | 606 | } else { |
|---|
| 585 | 607 | /* if no passed metadata allow list or passed allow-all |
|---|
| 586 | 608 | * then here we process by adding as many supported metadatum |
|---|
| .. | .. |
|---|
| 588 | 610 | * going to bail out |
|---|
| 589 | 611 | */ |
|---|
| 590 | 612 | err = use_all_metadata(ife, exists); |
|---|
| 591 | | - if (err) { |
|---|
| 592 | | - tcf_idr_release(*a, bind); |
|---|
| 593 | | - kfree(p); |
|---|
| 594 | | - return err; |
|---|
| 595 | | - } |
|---|
| 613 | + if (err) |
|---|
| 614 | + goto metadata_parse_err; |
|---|
| 596 | 615 | } |
|---|
| 597 | 616 | |
|---|
| 598 | 617 | if (exists) |
|---|
| 599 | 618 | spin_lock_bh(&ife->tcf_lock); |
|---|
| 600 | | - ife->tcf_action = parm->action; |
|---|
| 601 | 619 | /* protected by tcf_lock when modifying existing action */ |
|---|
| 602 | | - rcu_swap_protected(ife->params, p, 1); |
|---|
| 620 | + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
|---|
| 621 | + p = rcu_replace_pointer(ife->params, p, 1); |
|---|
| 603 | 622 | |
|---|
| 604 | 623 | if (exists) |
|---|
| 605 | 624 | spin_unlock_bh(&ife->tcf_lock); |
|---|
| 625 | + if (goto_ch) |
|---|
| 626 | + tcf_chain_put_by_act(goto_ch); |
|---|
| 606 | 627 | if (p) |
|---|
| 607 | 628 | kfree_rcu(p, rcu); |
|---|
| 608 | 629 | |
|---|
| 609 | | - if (ret == ACT_P_CREATED) |
|---|
| 610 | | - tcf_idr_insert(tn, *a); |
|---|
| 611 | | - |
|---|
| 612 | 630 | return ret; |
|---|
| 631 | +metadata_parse_err: |
|---|
| 632 | + if (goto_ch) |
|---|
| 633 | + tcf_chain_put_by_act(goto_ch); |
|---|
| 634 | +release_idr: |
|---|
| 635 | + kfree(p); |
|---|
| 636 | + tcf_idr_release(*a, bind); |
|---|
| 637 | + return err; |
|---|
| 613 | 638 | } |
|---|
| 614 | 639 | |
|---|
| 615 | 640 | static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind, |
|---|
| .. | .. |
|---|
| 862 | 887 | return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
|---|
| 863 | 888 | } |
|---|
| 864 | 889 | |
|---|
| 865 | | -static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index, |
|---|
| 866 | | - struct netlink_ext_ack *extack) |
|---|
| 890 | +static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index) |
|---|
| 867 | 891 | { |
|---|
| 868 | 892 | struct tc_action_net *tn = net_generic(net, ife_net_id); |
|---|
| 869 | 893 | |
|---|
| .. | .. |
|---|
| 872 | 896 | |
|---|
| 873 | 897 | static struct tc_action_ops act_ife_ops = { |
|---|
| 874 | 898 | .kind = "ife", |
|---|
| 875 | | - .type = TCA_ACT_IFE, |
|---|
| 899 | + .id = TCA_ID_IFE, |
|---|
| 876 | 900 | .owner = THIS_MODULE, |
|---|
| 877 | 901 | .act = tcf_ife_act, |
|---|
| 878 | 902 | .dump = tcf_ife_dump, |
|---|