18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/sched/cls_matchll.c Match-all classifier 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/percpu.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <net/sch_generic.h> 148c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct cls_mall_head { 178c2ecf20Sopenharmony_ci struct tcf_exts exts; 188c2ecf20Sopenharmony_ci struct tcf_result res; 198c2ecf20Sopenharmony_ci u32 handle; 208c2ecf20Sopenharmony_ci u32 flags; 218c2ecf20Sopenharmony_ci unsigned int in_hw_count; 228c2ecf20Sopenharmony_ci struct tc_matchall_pcnt __percpu *pf; 238c2ecf20Sopenharmony_ci struct rcu_work rwork; 248c2ecf20Sopenharmony_ci bool deleting; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp, 288c2ecf20Sopenharmony_ci struct tcf_result *res) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct cls_mall_head *head = rcu_dereference_bh(tp->root); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (unlikely(!head)) 338c2ecf20Sopenharmony_ci return -1; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (tc_skip_sw(head->flags)) 368c2ecf20Sopenharmony_ci return -1; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci *res = head->res; 398c2ecf20Sopenharmony_ci __this_cpu_inc(head->pf->rhit); 408c2ecf20Sopenharmony_ci return tcf_exts_exec(skb, &head->exts, res); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int mall_init(struct tcf_proto *tp) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void __mall_destroy(struct cls_mall_head *head) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci tcf_exts_destroy(&head->exts); 518c2ecf20Sopenharmony_ci tcf_exts_put_net(&head->exts); 528c2ecf20Sopenharmony_ci free_percpu(head->pf); 538c2ecf20Sopenharmony_ci kfree(head); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void mall_destroy_work(struct work_struct *work) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct cls_mall_head *head = container_of(to_rcu_work(work), 598c2ecf20Sopenharmony_ci struct cls_mall_head, 608c2ecf20Sopenharmony_ci rwork); 618c2ecf20Sopenharmony_ci rtnl_lock(); 628c2ecf20Sopenharmony_ci __mall_destroy(head); 638c2ecf20Sopenharmony_ci rtnl_unlock(); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void mall_destroy_hw_filter(struct tcf_proto *tp, 678c2ecf20Sopenharmony_ci struct cls_mall_head *head, 688c2ecf20Sopenharmony_ci unsigned long cookie, 698c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload cls_mall = {}; 728c2ecf20Sopenharmony_ci struct tcf_block *block = tp->chain->block; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack); 758c2ecf20Sopenharmony_ci cls_mall.command = TC_CLSMATCHALL_DESTROY; 768c2ecf20Sopenharmony_ci cls_mall.cookie = cookie; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci tc_setup_cb_destroy(block, tp, TC_SETUP_CLSMATCHALL, &cls_mall, false, 798c2ecf20Sopenharmony_ci &head->flags, &head->in_hw_count, true); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int mall_replace_hw_filter(struct tcf_proto *tp, 838c2ecf20Sopenharmony_ci struct cls_mall_head *head, 848c2ecf20Sopenharmony_ci unsigned long cookie, 858c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload cls_mall = {}; 888c2ecf20Sopenharmony_ci struct tcf_block *block = tp->chain->block; 898c2ecf20Sopenharmony_ci bool skip_sw = tc_skip_sw(head->flags); 908c2ecf20Sopenharmony_ci int err; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci cls_mall.rule = flow_rule_alloc(tcf_exts_num_actions(&head->exts)); 938c2ecf20Sopenharmony_ci if (!cls_mall.rule) 948c2ecf20Sopenharmony_ci return -ENOMEM; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack); 978c2ecf20Sopenharmony_ci cls_mall.command = TC_CLSMATCHALL_REPLACE; 988c2ecf20Sopenharmony_ci cls_mall.cookie = cookie; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts); 1018c2ecf20Sopenharmony_ci if (err) { 1028c2ecf20Sopenharmony_ci kfree(cls_mall.rule); 1038c2ecf20Sopenharmony_ci mall_destroy_hw_filter(tp, head, cookie, NULL); 1048c2ecf20Sopenharmony_ci if (skip_sw) 1058c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action"); 1068c2ecf20Sopenharmony_ci else 1078c2ecf20Sopenharmony_ci err = 0; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return err; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci err = tc_setup_cb_add(block, tp, TC_SETUP_CLSMATCHALL, &cls_mall, 1138c2ecf20Sopenharmony_ci skip_sw, &head->flags, &head->in_hw_count, true); 1148c2ecf20Sopenharmony_ci tc_cleanup_flow_action(&cls_mall.rule->action); 1158c2ecf20Sopenharmony_ci kfree(cls_mall.rule); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (err) { 1188c2ecf20Sopenharmony_ci mall_destroy_hw_filter(tp, head, cookie, NULL); 1198c2ecf20Sopenharmony_ci return err; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (skip_sw && !(head->flags & TCA_CLS_FLAGS_IN_HW)) 1238c2ecf20Sopenharmony_ci return -EINVAL; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void mall_destroy(struct tcf_proto *tp, bool rtnl_held, 1298c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct cls_mall_head *head = rtnl_dereference(tp->root); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!head) 1348c2ecf20Sopenharmony_ci return; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci tcf_unbind_filter(tp, &head->res); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (!tc_skip_hw(head->flags)) 1398c2ecf20Sopenharmony_ci mall_destroy_hw_filter(tp, head, (unsigned long) head, extack); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (tcf_exts_get_net(&head->exts)) 1428c2ecf20Sopenharmony_ci tcf_queue_work(&head->rwork, mall_destroy_work); 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci __mall_destroy(head); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void *mall_get(struct tcf_proto *tp, u32 handle) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct cls_mall_head *head = rtnl_dereference(tp->root); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (head && head->handle == handle) 1528c2ecf20Sopenharmony_ci return head; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return NULL; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = { 1588c2ecf20Sopenharmony_ci [TCA_MATCHALL_UNSPEC] = { .type = NLA_UNSPEC }, 1598c2ecf20Sopenharmony_ci [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 }, 1608c2ecf20Sopenharmony_ci [TCA_MATCHALL_FLAGS] = { .type = NLA_U32 }, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int mall_set_parms(struct net *net, struct tcf_proto *tp, 1648c2ecf20Sopenharmony_ci struct cls_mall_head *head, 1658c2ecf20Sopenharmony_ci unsigned long base, struct nlattr **tb, 1668c2ecf20Sopenharmony_ci struct nlattr *est, bool ovr, 1678c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci int err; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci err = tcf_exts_validate(net, tp, tb, est, &head->exts, ovr, true, 1728c2ecf20Sopenharmony_ci extack); 1738c2ecf20Sopenharmony_ci if (err < 0) 1748c2ecf20Sopenharmony_ci return err; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (tb[TCA_MATCHALL_CLASSID]) { 1778c2ecf20Sopenharmony_ci head->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]); 1788c2ecf20Sopenharmony_ci tcf_bind_filter(tp, &head->res, base); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int mall_change(struct net *net, struct sk_buff *in_skb, 1848c2ecf20Sopenharmony_ci struct tcf_proto *tp, unsigned long base, 1858c2ecf20Sopenharmony_ci u32 handle, struct nlattr **tca, 1868c2ecf20Sopenharmony_ci void **arg, bool ovr, bool rtnl_held, 1878c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct cls_mall_head *head = rtnl_dereference(tp->root); 1908c2ecf20Sopenharmony_ci struct nlattr *tb[TCA_MATCHALL_MAX + 1]; 1918c2ecf20Sopenharmony_ci struct cls_mall_head *new; 1928c2ecf20Sopenharmony_ci u32 flags = 0; 1938c2ecf20Sopenharmony_ci int err; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (!tca[TCA_OPTIONS]) 1968c2ecf20Sopenharmony_ci return -EINVAL; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (head) 1998c2ecf20Sopenharmony_ci return -EEXIST; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(tb, TCA_MATCHALL_MAX, 2028c2ecf20Sopenharmony_ci tca[TCA_OPTIONS], mall_policy, NULL); 2038c2ecf20Sopenharmony_ci if (err < 0) 2048c2ecf20Sopenharmony_ci return err; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (tb[TCA_MATCHALL_FLAGS]) { 2078c2ecf20Sopenharmony_ci flags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]); 2088c2ecf20Sopenharmony_ci if (!tc_flags_valid(flags)) 2098c2ecf20Sopenharmony_ci return -EINVAL; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci new = kzalloc(sizeof(*new), GFP_KERNEL); 2138c2ecf20Sopenharmony_ci if (!new) 2148c2ecf20Sopenharmony_ci return -ENOBUFS; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci err = tcf_exts_init(&new->exts, net, TCA_MATCHALL_ACT, 0); 2178c2ecf20Sopenharmony_ci if (err) 2188c2ecf20Sopenharmony_ci goto err_exts_init; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!handle) 2218c2ecf20Sopenharmony_ci handle = 1; 2228c2ecf20Sopenharmony_ci new->handle = handle; 2238c2ecf20Sopenharmony_ci new->flags = flags; 2248c2ecf20Sopenharmony_ci new->pf = alloc_percpu(struct tc_matchall_pcnt); 2258c2ecf20Sopenharmony_ci if (!new->pf) { 2268c2ecf20Sopenharmony_ci err = -ENOMEM; 2278c2ecf20Sopenharmony_ci goto err_alloc_percpu; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr, 2318c2ecf20Sopenharmony_ci extack); 2328c2ecf20Sopenharmony_ci if (err) 2338c2ecf20Sopenharmony_ci goto err_set_parms; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!tc_skip_hw(new->flags)) { 2368c2ecf20Sopenharmony_ci err = mall_replace_hw_filter(tp, new, (unsigned long)new, 2378c2ecf20Sopenharmony_ci extack); 2388c2ecf20Sopenharmony_ci if (err) 2398c2ecf20Sopenharmony_ci goto err_replace_hw_filter; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!tc_in_hw(new->flags)) 2438c2ecf20Sopenharmony_ci new->flags |= TCA_CLS_FLAGS_NOT_IN_HW; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci *arg = head; 2468c2ecf20Sopenharmony_ci rcu_assign_pointer(tp->root, new); 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cierr_replace_hw_filter: 2508c2ecf20Sopenharmony_cierr_set_parms: 2518c2ecf20Sopenharmony_ci free_percpu(new->pf); 2528c2ecf20Sopenharmony_cierr_alloc_percpu: 2538c2ecf20Sopenharmony_ci tcf_exts_destroy(&new->exts); 2548c2ecf20Sopenharmony_cierr_exts_init: 2558c2ecf20Sopenharmony_ci kfree(new); 2568c2ecf20Sopenharmony_ci return err; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int mall_delete(struct tcf_proto *tp, void *arg, bool *last, 2608c2ecf20Sopenharmony_ci bool rtnl_held, struct netlink_ext_ack *extack) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct cls_mall_head *head = rtnl_dereference(tp->root); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci head->deleting = true; 2658c2ecf20Sopenharmony_ci *last = true; 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg, 2708c2ecf20Sopenharmony_ci bool rtnl_held) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct cls_mall_head *head = rtnl_dereference(tp->root); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (arg->count < arg->skip) 2758c2ecf20Sopenharmony_ci goto skip; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (!head || head->deleting) 2788c2ecf20Sopenharmony_ci return; 2798c2ecf20Sopenharmony_ci if (arg->fn(tp, head, arg) < 0) 2808c2ecf20Sopenharmony_ci arg->stop = 1; 2818c2ecf20Sopenharmony_ciskip: 2828c2ecf20Sopenharmony_ci arg->count++; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int mall_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, 2868c2ecf20Sopenharmony_ci void *cb_priv, struct netlink_ext_ack *extack) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct cls_mall_head *head = rtnl_dereference(tp->root); 2898c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload cls_mall = {}; 2908c2ecf20Sopenharmony_ci struct tcf_block *block = tp->chain->block; 2918c2ecf20Sopenharmony_ci int err; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (tc_skip_hw(head->flags)) 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci cls_mall.rule = flow_rule_alloc(tcf_exts_num_actions(&head->exts)); 2978c2ecf20Sopenharmony_ci if (!cls_mall.rule) 2988c2ecf20Sopenharmony_ci return -ENOMEM; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack); 3018c2ecf20Sopenharmony_ci cls_mall.command = add ? 3028c2ecf20Sopenharmony_ci TC_CLSMATCHALL_REPLACE : TC_CLSMATCHALL_DESTROY; 3038c2ecf20Sopenharmony_ci cls_mall.cookie = (unsigned long)head; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts); 3068c2ecf20Sopenharmony_ci if (err) { 3078c2ecf20Sopenharmony_ci kfree(cls_mall.rule); 3088c2ecf20Sopenharmony_ci if (add && tc_skip_sw(head->flags)) { 3098c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action"); 3108c2ecf20Sopenharmony_ci return err; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci err = tc_setup_cb_reoffload(block, tp, add, cb, TC_SETUP_CLSMATCHALL, 3168c2ecf20Sopenharmony_ci &cls_mall, cb_priv, &head->flags, 3178c2ecf20Sopenharmony_ci &head->in_hw_count); 3188c2ecf20Sopenharmony_ci tc_cleanup_flow_action(&cls_mall.rule->action); 3198c2ecf20Sopenharmony_ci kfree(cls_mall.rule); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (err) 3228c2ecf20Sopenharmony_ci return err; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void mall_stats_hw_filter(struct tcf_proto *tp, 3288c2ecf20Sopenharmony_ci struct cls_mall_head *head, 3298c2ecf20Sopenharmony_ci unsigned long cookie) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload cls_mall = {}; 3328c2ecf20Sopenharmony_ci struct tcf_block *block = tp->chain->block; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, NULL); 3358c2ecf20Sopenharmony_ci cls_mall.command = TC_CLSMATCHALL_STATS; 3368c2ecf20Sopenharmony_ci cls_mall.cookie = cookie; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci tc_setup_cb_call(block, TC_SETUP_CLSMATCHALL, &cls_mall, false, true); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci tcf_exts_stats_update(&head->exts, cls_mall.stats.bytes, 3418c2ecf20Sopenharmony_ci cls_mall.stats.pkts, cls_mall.stats.drops, 3428c2ecf20Sopenharmony_ci cls_mall.stats.lastused, 3438c2ecf20Sopenharmony_ci cls_mall.stats.used_hw_stats, 3448c2ecf20Sopenharmony_ci cls_mall.stats.used_hw_stats_valid); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int mall_dump(struct net *net, struct tcf_proto *tp, void *fh, 3488c2ecf20Sopenharmony_ci struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct tc_matchall_pcnt gpf = {}; 3518c2ecf20Sopenharmony_ci struct cls_mall_head *head = fh; 3528c2ecf20Sopenharmony_ci struct nlattr *nest; 3538c2ecf20Sopenharmony_ci int cpu; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!head) 3568c2ecf20Sopenharmony_ci return skb->len; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!tc_skip_hw(head->flags)) 3598c2ecf20Sopenharmony_ci mall_stats_hw_filter(tp, head, (unsigned long)head); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci t->tcm_handle = head->handle; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 3648c2ecf20Sopenharmony_ci if (!nest) 3658c2ecf20Sopenharmony_ci goto nla_put_failure; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (head->res.classid && 3688c2ecf20Sopenharmony_ci nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid)) 3698c2ecf20Sopenharmony_ci goto nla_put_failure; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (head->flags && nla_put_u32(skb, TCA_MATCHALL_FLAGS, head->flags)) 3728c2ecf20Sopenharmony_ci goto nla_put_failure; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 3758c2ecf20Sopenharmony_ci struct tc_matchall_pcnt *pf = per_cpu_ptr(head->pf, cpu); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci gpf.rhit += pf->rhit; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (nla_put_64bit(skb, TCA_MATCHALL_PCNT, 3818c2ecf20Sopenharmony_ci sizeof(struct tc_matchall_pcnt), 3828c2ecf20Sopenharmony_ci &gpf, TCA_MATCHALL_PAD)) 3838c2ecf20Sopenharmony_ci goto nla_put_failure; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (tcf_exts_dump(skb, &head->exts)) 3868c2ecf20Sopenharmony_ci goto nla_put_failure; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci nla_nest_end(skb, nest); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (tcf_exts_dump_stats(skb, &head->exts) < 0) 3918c2ecf20Sopenharmony_ci goto nla_put_failure; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return skb->len; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cinla_put_failure: 3968c2ecf20Sopenharmony_ci nla_nest_cancel(skb, nest); 3978c2ecf20Sopenharmony_ci return -1; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void mall_bind_class(void *fh, u32 classid, unsigned long cl, void *q, 4018c2ecf20Sopenharmony_ci unsigned long base) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct cls_mall_head *head = fh; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (head && head->res.classid == classid) { 4068c2ecf20Sopenharmony_ci if (cl) 4078c2ecf20Sopenharmony_ci __tcf_bind_filter(q, &head->res, base); 4088c2ecf20Sopenharmony_ci else 4098c2ecf20Sopenharmony_ci __tcf_unbind_filter(q, &head->res); 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic struct tcf_proto_ops cls_mall_ops __read_mostly = { 4148c2ecf20Sopenharmony_ci .kind = "matchall", 4158c2ecf20Sopenharmony_ci .classify = mall_classify, 4168c2ecf20Sopenharmony_ci .init = mall_init, 4178c2ecf20Sopenharmony_ci .destroy = mall_destroy, 4188c2ecf20Sopenharmony_ci .get = mall_get, 4198c2ecf20Sopenharmony_ci .change = mall_change, 4208c2ecf20Sopenharmony_ci .delete = mall_delete, 4218c2ecf20Sopenharmony_ci .walk = mall_walk, 4228c2ecf20Sopenharmony_ci .reoffload = mall_reoffload, 4238c2ecf20Sopenharmony_ci .dump = mall_dump, 4248c2ecf20Sopenharmony_ci .bind_class = mall_bind_class, 4258c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int __init cls_mall_init(void) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci return register_tcf_proto_ops(&cls_mall_ops); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void __exit cls_mall_exit(void) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci unregister_tcf_proto_ops(&cls_mall_ops); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cimodule_init(cls_mall_init); 4398c2ecf20Sopenharmony_cimodule_exit(cls_mall_exit); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 4428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Match-all classifier"); 4438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 444