12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2bf3994d2SJiri Pirko /*
3bf3994d2SJiri Pirko * net/sched/cls_matchll.c Match-all classifier
4bf3994d2SJiri Pirko *
5bf3994d2SJiri Pirko * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
6bf3994d2SJiri Pirko */
7bf3994d2SJiri Pirko
8bf3994d2SJiri Pirko #include <linux/kernel.h>
9bf3994d2SJiri Pirko #include <linux/init.h>
10bf3994d2SJiri Pirko #include <linux/module.h>
11f88c19aaSCong Wang #include <linux/percpu.h>
12bf3994d2SJiri Pirko
13bf3994d2SJiri Pirko #include <net/sch_generic.h>
14bf3994d2SJiri Pirko #include <net/pkt_cls.h>
159f3101dcSPedro Tammela #include <net/tc_wrapper.h>
16bf3994d2SJiri Pirko
17fd62d9f5SYotam Gigi struct cls_mall_head {
18bf3994d2SJiri Pirko struct tcf_exts exts;
19bf3994d2SJiri Pirko struct tcf_result res;
20bf3994d2SJiri Pirko u32 handle;
21b87f7936SYotam Gigi u32 flags;
220efd1b3aSJohn Hurley unsigned int in_hw_count;
23f88c19aaSCong Wang struct tc_matchall_pcnt __percpu *pf;
24aaa908ffSCong Wang struct rcu_work rwork;
25f517f271SJiri Pirko bool deleting;
26df2735eeSCong Wang };
27bf3994d2SJiri Pirko
mall_classify(struct sk_buff * skb,const struct tcf_proto * tp,struct tcf_result * res)289f3101dcSPedro Tammela TC_INDIRECT_SCOPE int mall_classify(struct sk_buff *skb,
299f3101dcSPedro Tammela const struct tcf_proto *tp,
30bf3994d2SJiri Pirko struct tcf_result *res)
31bf3994d2SJiri Pirko {
32bf3994d2SJiri Pirko struct cls_mall_head *head = rcu_dereference_bh(tp->root);
33bf3994d2SJiri Pirko
3425426043SMatteo Croce if (unlikely(!head))
3525426043SMatteo Croce return -1;
3625426043SMatteo Croce
37fd62d9f5SYotam Gigi if (tc_skip_sw(head->flags))
38b87f7936SYotam Gigi return -1;
39b87f7936SYotam Gigi
403ff4cbecSDavide Caratti *res = head->res;
41f88c19aaSCong Wang __this_cpu_inc(head->pf->rhit);
42fd62d9f5SYotam Gigi return tcf_exts_exec(skb, &head->exts, res);
43bf3994d2SJiri Pirko }
44bf3994d2SJiri Pirko
mall_init(struct tcf_proto * tp)45bf3994d2SJiri Pirko static int mall_init(struct tcf_proto *tp)
46bf3994d2SJiri Pirko {
47bf3994d2SJiri Pirko return 0;
48bf3994d2SJiri Pirko }
49bf3994d2SJiri Pirko
__mall_destroy(struct cls_mall_head * head)5057767e78SCong Wang static void __mall_destroy(struct cls_mall_head *head)
5157767e78SCong Wang {
5257767e78SCong Wang tcf_exts_destroy(&head->exts);
5357767e78SCong Wang tcf_exts_put_net(&head->exts);
54f88c19aaSCong Wang free_percpu(head->pf);
5557767e78SCong Wang kfree(head);
5657767e78SCong Wang }
5757767e78SCong Wang
mall_destroy_work(struct work_struct * work)58df2735eeSCong Wang static void mall_destroy_work(struct work_struct *work)
59df2735eeSCong Wang {
60aaa908ffSCong Wang struct cls_mall_head *head = container_of(to_rcu_work(work),
61aaa908ffSCong Wang struct cls_mall_head,
62aaa908ffSCong Wang rwork);
63df2735eeSCong Wang rtnl_lock();
6457767e78SCong Wang __mall_destroy(head);
65df2735eeSCong Wang rtnl_unlock();
66df2735eeSCong Wang }
67df2735eeSCong Wang
mall_destroy_hw_filter(struct tcf_proto * tp,struct cls_mall_head * head,unsigned long cookie,struct netlink_ext_ack * extack)682447a96fSJiri Pirko static void mall_destroy_hw_filter(struct tcf_proto *tp,
692447a96fSJiri Pirko struct cls_mall_head *head,
70b505b29fSJakub Kicinski unsigned long cookie,
71b505b29fSJakub Kicinski struct netlink_ext_ack *extack)
722447a96fSJiri Pirko {
732447a96fSJiri Pirko struct tc_cls_matchall_offload cls_mall = {};
742447a96fSJiri Pirko struct tcf_block *block = tp->chain->block;
752447a96fSJiri Pirko
76d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
772447a96fSJiri Pirko cls_mall.command = TC_CLSMATCHALL_DESTROY;
782447a96fSJiri Pirko cls_mall.cookie = cookie;
792447a96fSJiri Pirko
8040119211SVlad Buslov tc_setup_cb_destroy(block, tp, TC_SETUP_CLSMATCHALL, &cls_mall, false,
8140119211SVlad Buslov &head->flags, &head->in_hw_count, true);
822447a96fSJiri Pirko }
832447a96fSJiri Pirko
mall_replace_hw_filter(struct tcf_proto * tp,struct cls_mall_head * head,unsigned long cookie,struct netlink_ext_ack * extack)84b87f7936SYotam Gigi static int mall_replace_hw_filter(struct tcf_proto *tp,
85fd62d9f5SYotam Gigi struct cls_mall_head *head,
8602798140SQuentin Monnet unsigned long cookie,
8702798140SQuentin Monnet struct netlink_ext_ack *extack)
88b87f7936SYotam Gigi {
89de4784caSJiri Pirko struct tc_cls_matchall_offload cls_mall = {};
902447a96fSJiri Pirko struct tcf_block *block = tp->chain->block;
912447a96fSJiri Pirko bool skip_sw = tc_skip_sw(head->flags);
92c7d2b2f5SOr Gerlitz int err;
93b87f7936SYotam Gigi
94f00cbf19SPieter Jansen van Vuuren cls_mall.rule = flow_rule_alloc(tcf_exts_num_actions(&head->exts));
95f00cbf19SPieter Jansen van Vuuren if (!cls_mall.rule)
96f00cbf19SPieter Jansen van Vuuren return -ENOMEM;
97f00cbf19SPieter Jansen van Vuuren
98d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
99de4784caSJiri Pirko cls_mall.command = TC_CLSMATCHALL_REPLACE;
100de4784caSJiri Pirko cls_mall.cookie = cookie;
101b87f7936SYotam Gigi
102c2ccf84eSIdo Schimmel err = tc_setup_offload_action(&cls_mall.rule->action, &head->exts,
103c2ccf84eSIdo Schimmel cls_mall.common.extack);
104f00cbf19SPieter Jansen van Vuuren if (err) {
105f00cbf19SPieter Jansen van Vuuren kfree(cls_mall.rule);
106f00cbf19SPieter Jansen van Vuuren mall_destroy_hw_filter(tp, head, cookie, NULL);
107f00cbf19SPieter Jansen van Vuuren
1084c096ea2SIdo Schimmel return skip_sw ? err : 0;
109f00cbf19SPieter Jansen van Vuuren }
110f00cbf19SPieter Jansen van Vuuren
11140119211SVlad Buslov err = tc_setup_cb_add(block, tp, TC_SETUP_CLSMATCHALL, &cls_mall,
11240119211SVlad Buslov skip_sw, &head->flags, &head->in_hw_count, true);
1139c1c0e12SBaowen Zheng tc_cleanup_offload_action(&cls_mall.rule->action);
114f00cbf19SPieter Jansen van Vuuren kfree(cls_mall.rule);
115f00cbf19SPieter Jansen van Vuuren
11640119211SVlad Buslov if (err) {
117b505b29fSJakub Kicinski mall_destroy_hw_filter(tp, head, cookie, NULL);
1182447a96fSJiri Pirko return err;
1192447a96fSJiri Pirko }
120b87f7936SYotam Gigi
1212447a96fSJiri Pirko if (skip_sw && !(head->flags & TCA_CLS_FLAGS_IN_HW))
1222447a96fSJiri Pirko return -EINVAL;
123b87f7936SYotam Gigi
1242447a96fSJiri Pirko return 0;
125b87f7936SYotam Gigi }
126b87f7936SYotam Gigi
mall_destroy(struct tcf_proto * tp,bool rtnl_held,struct netlink_ext_ack * extack)12712db03b6SVlad Buslov static void mall_destroy(struct tcf_proto *tp, bool rtnl_held,
12812db03b6SVlad Buslov struct netlink_ext_ack *extack)
129bf3994d2SJiri Pirko {
130bf3994d2SJiri Pirko struct cls_mall_head *head = rtnl_dereference(tp->root);
131bf3994d2SJiri Pirko
132fd62d9f5SYotam Gigi if (!head)
133763dbf63SWANG Cong return;
134bf3994d2SJiri Pirko
135a51c76b4SHangbin Liu tcf_unbind_filter(tp, &head->res);
136a51c76b4SHangbin Liu
1372447a96fSJiri Pirko if (!tc_skip_hw(head->flags))
138b505b29fSJakub Kicinski mall_destroy_hw_filter(tp, head, (unsigned long) head, extack);
139b87f7936SYotam Gigi
14057767e78SCong Wang if (tcf_exts_get_net(&head->exts))
141aaa908ffSCong Wang tcf_queue_work(&head->rwork, mall_destroy_work);
14257767e78SCong Wang else
14357767e78SCong Wang __mall_destroy(head);
144bf3994d2SJiri Pirko }
145bf3994d2SJiri Pirko
mall_get(struct tcf_proto * tp,u32 handle)1468113c095SWANG Cong static void *mall_get(struct tcf_proto *tp, u32 handle)
147bf3994d2SJiri Pirko {
1480db6f8beSNicolas Dichtel struct cls_mall_head *head = rtnl_dereference(tp->root);
1490db6f8beSNicolas Dichtel
1500db6f8beSNicolas Dichtel if (head && head->handle == handle)
1510db6f8beSNicolas Dichtel return head;
1520db6f8beSNicolas Dichtel
1538113c095SWANG Cong return NULL;
154bf3994d2SJiri Pirko }
155bf3994d2SJiri Pirko
156bf3994d2SJiri Pirko static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
157bf3994d2SJiri Pirko [TCA_MATCHALL_UNSPEC] = { .type = NLA_UNSPEC },
158bf3994d2SJiri Pirko [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 },
1591afa3cc9SDavide Caratti [TCA_MATCHALL_FLAGS] = { .type = NLA_U32 },
160bf3994d2SJiri Pirko };
161bf3994d2SJiri Pirko
mall_change(struct net * net,struct sk_buff * in_skb,struct tcf_proto * tp,unsigned long base,u32 handle,struct nlattr ** tca,void ** arg,u32 flags,struct netlink_ext_ack * extack)162bf3994d2SJiri Pirko static int mall_change(struct net *net, struct sk_buff *in_skb,
163bf3994d2SJiri Pirko struct tcf_proto *tp, unsigned long base,
164bf3994d2SJiri Pirko u32 handle, struct nlattr **tca,
165695176bfSCong Wang void **arg, u32 flags,
16612db03b6SVlad Buslov struct netlink_ext_ack *extack)
167bf3994d2SJiri Pirko {
168bf3994d2SJiri Pirko struct cls_mall_head *head = rtnl_dereference(tp->root);
169bf3994d2SJiri Pirko struct nlattr *tb[TCA_MATCHALL_MAX + 1];
170*b3d0e048SVictor Nogueira bool bound_to_filter = false;
171fd62d9f5SYotam Gigi struct cls_mall_head *new;
172695176bfSCong Wang u32 userflags = 0;
173bf3994d2SJiri Pirko int err;
174bf3994d2SJiri Pirko
175bf3994d2SJiri Pirko if (!tca[TCA_OPTIONS])
176bf3994d2SJiri Pirko return -EINVAL;
177bf3994d2SJiri Pirko
178fd62d9f5SYotam Gigi if (head)
179fd62d9f5SYotam Gigi return -EEXIST;
180bf3994d2SJiri Pirko
1818cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, TCA_MATCHALL_MAX,
1828cb08174SJohannes Berg tca[TCA_OPTIONS], mall_policy, NULL);
183bf3994d2SJiri Pirko if (err < 0)
184bf3994d2SJiri Pirko return err;
185bf3994d2SJiri Pirko
186b87f7936SYotam Gigi if (tb[TCA_MATCHALL_FLAGS]) {
187695176bfSCong Wang userflags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]);
188695176bfSCong Wang if (!tc_flags_valid(userflags))
189b87f7936SYotam Gigi return -EINVAL;
190b87f7936SYotam Gigi }
191b87f7936SYotam Gigi
192fd62d9f5SYotam Gigi new = kzalloc(sizeof(*new), GFP_KERNEL);
193fd62d9f5SYotam Gigi if (!new)
194bf3994d2SJiri Pirko return -ENOBUFS;
195bf3994d2SJiri Pirko
19614215108SCong Wang err = tcf_exts_init(&new->exts, net, TCA_MATCHALL_ACT, 0);
197ec2507d2SYotam Gigi if (err)
198ec2507d2SYotam Gigi goto err_exts_init;
199bf3994d2SJiri Pirko
200bf3994d2SJiri Pirko if (!handle)
201bf3994d2SJiri Pirko handle = 1;
202fd62d9f5SYotam Gigi new->handle = handle;
203695176bfSCong Wang new->flags = userflags;
204f88c19aaSCong Wang new->pf = alloc_percpu(struct tc_matchall_pcnt);
205f88c19aaSCong Wang if (!new->pf) {
206f88c19aaSCong Wang err = -ENOMEM;
207f88c19aaSCong Wang goto err_alloc_percpu;
208f88c19aaSCong Wang }
209bf3994d2SJiri Pirko
210*b3d0e048SVictor Nogueira err = tcf_exts_validate_ex(net, tp, tb, tca[TCA_RATE],
211*b3d0e048SVictor Nogueira &new->exts, flags, new->flags, extack);
212*b3d0e048SVictor Nogueira if (err < 0)
213ec2507d2SYotam Gigi goto err_set_parms;
214bf3994d2SJiri Pirko
215*b3d0e048SVictor Nogueira if (tb[TCA_MATCHALL_CLASSID]) {
216*b3d0e048SVictor Nogueira new->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
217*b3d0e048SVictor Nogueira tcf_bind_filter(tp, &new->res, base);
218*b3d0e048SVictor Nogueira bound_to_filter = true;
219*b3d0e048SVictor Nogueira }
220*b3d0e048SVictor Nogueira
2212447a96fSJiri Pirko if (!tc_skip_hw(new->flags)) {
22202798140SQuentin Monnet err = mall_replace_hw_filter(tp, new, (unsigned long)new,
22302798140SQuentin Monnet extack);
2242447a96fSJiri Pirko if (err)
225ec2507d2SYotam Gigi goto err_replace_hw_filter;
226b87f7936SYotam Gigi }
227b87f7936SYotam Gigi
228c7d2b2f5SOr Gerlitz if (!tc_in_hw(new->flags))
229c7d2b2f5SOr Gerlitz new->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
230c7d2b2f5SOr Gerlitz
2318113c095SWANG Cong *arg = head;
232fd62d9f5SYotam Gigi rcu_assign_pointer(tp->root, new);
233bf3994d2SJiri Pirko return 0;
234bf3994d2SJiri Pirko
235ec2507d2SYotam Gigi err_replace_hw_filter:
236*b3d0e048SVictor Nogueira if (bound_to_filter)
237*b3d0e048SVictor Nogueira tcf_unbind_filter(tp, &new->res);
238ec2507d2SYotam Gigi err_set_parms:
239f88c19aaSCong Wang free_percpu(new->pf);
240f88c19aaSCong Wang err_alloc_percpu:
241e2160156SDavid S. Miller tcf_exts_destroy(&new->exts);
242ec2507d2SYotam Gigi err_exts_init:
243fd62d9f5SYotam Gigi kfree(new);
244bf3994d2SJiri Pirko return err;
245bf3994d2SJiri Pirko }
246bf3994d2SJiri Pirko
mall_delete(struct tcf_proto * tp,void * arg,bool * last,bool rtnl_held,struct netlink_ext_ack * extack)247571acf21SAlexander Aring static int mall_delete(struct tcf_proto *tp, void *arg, bool *last,
24812db03b6SVlad Buslov bool rtnl_held, struct netlink_ext_ack *extack)
249bf3994d2SJiri Pirko {
250f517f271SJiri Pirko struct cls_mall_head *head = rtnl_dereference(tp->root);
251f517f271SJiri Pirko
252f517f271SJiri Pirko head->deleting = true;
253f517f271SJiri Pirko *last = true;
254f517f271SJiri Pirko return 0;
255bf3994d2SJiri Pirko }
256bf3994d2SJiri Pirko
mall_walk(struct tcf_proto * tp,struct tcf_walker * arg,bool rtnl_held)25712db03b6SVlad Buslov static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg,
25812db03b6SVlad Buslov bool rtnl_held)
259bf3994d2SJiri Pirko {
260bf3994d2SJiri Pirko struct cls_mall_head *head = rtnl_dereference(tp->root);
261bf3994d2SJiri Pirko
262bf3994d2SJiri Pirko if (arg->count < arg->skip)
263bf3994d2SJiri Pirko goto skip;
264d66022cdSVlad Buslov
265f517f271SJiri Pirko if (!head || head->deleting)
266d66022cdSVlad Buslov return;
2678113c095SWANG Cong if (arg->fn(tp, head, arg) < 0)
268bf3994d2SJiri Pirko arg->stop = 1;
269bf3994d2SJiri Pirko skip:
270bf3994d2SJiri Pirko arg->count++;
271bf3994d2SJiri Pirko }
272bf3994d2SJiri Pirko
mall_reoffload(struct tcf_proto * tp,bool add,flow_setup_cb_t * cb,void * cb_priv,struct netlink_ext_ack * extack)273a7323311SPablo Neira Ayuso static int mall_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
2740efd1b3aSJohn Hurley void *cb_priv, struct netlink_ext_ack *extack)
2750efd1b3aSJohn Hurley {
2760efd1b3aSJohn Hurley struct cls_mall_head *head = rtnl_dereference(tp->root);
2770efd1b3aSJohn Hurley struct tc_cls_matchall_offload cls_mall = {};
2780efd1b3aSJohn Hurley struct tcf_block *block = tp->chain->block;
2790efd1b3aSJohn Hurley int err;
2800efd1b3aSJohn Hurley
2810efd1b3aSJohn Hurley if (tc_skip_hw(head->flags))
2820efd1b3aSJohn Hurley return 0;
2830efd1b3aSJohn Hurley
284f00cbf19SPieter Jansen van Vuuren cls_mall.rule = flow_rule_alloc(tcf_exts_num_actions(&head->exts));
285f00cbf19SPieter Jansen van Vuuren if (!cls_mall.rule)
286f00cbf19SPieter Jansen van Vuuren return -ENOMEM;
287f00cbf19SPieter Jansen van Vuuren
288d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
2890efd1b3aSJohn Hurley cls_mall.command = add ?
2900efd1b3aSJohn Hurley TC_CLSMATCHALL_REPLACE : TC_CLSMATCHALL_DESTROY;
2910efd1b3aSJohn Hurley cls_mall.cookie = (unsigned long)head;
2920efd1b3aSJohn Hurley
293c2ccf84eSIdo Schimmel err = tc_setup_offload_action(&cls_mall.rule->action, &head->exts,
294c2ccf84eSIdo Schimmel cls_mall.common.extack);
295f00cbf19SPieter Jansen van Vuuren if (err) {
296f00cbf19SPieter Jansen van Vuuren kfree(cls_mall.rule);
2974c096ea2SIdo Schimmel
2984c096ea2SIdo Schimmel return add && tc_skip_sw(head->flags) ? err : 0;
299f00cbf19SPieter Jansen van Vuuren }
300f00cbf19SPieter Jansen van Vuuren
30140119211SVlad Buslov err = tc_setup_cb_reoffload(block, tp, add, cb, TC_SETUP_CLSMATCHALL,
30240119211SVlad Buslov &cls_mall, cb_priv, &head->flags,
30340119211SVlad Buslov &head->in_hw_count);
3049c1c0e12SBaowen Zheng tc_cleanup_offload_action(&cls_mall.rule->action);
305f00cbf19SPieter Jansen van Vuuren kfree(cls_mall.rule);
306f00cbf19SPieter Jansen van Vuuren
3070efd1b3aSJohn Hurley return err;
3080efd1b3aSJohn Hurley }
3090efd1b3aSJohn Hurley
mall_stats_hw_filter(struct tcf_proto * tp,struct cls_mall_head * head,unsigned long cookie)310b7fe4ab8SPieter Jansen van Vuuren static void mall_stats_hw_filter(struct tcf_proto *tp,
311b7fe4ab8SPieter Jansen van Vuuren struct cls_mall_head *head,
312b7fe4ab8SPieter Jansen van Vuuren unsigned long cookie)
313b7fe4ab8SPieter Jansen van Vuuren {
314b7fe4ab8SPieter Jansen van Vuuren struct tc_cls_matchall_offload cls_mall = {};
315b7fe4ab8SPieter Jansen van Vuuren struct tcf_block *block = tp->chain->block;
316b7fe4ab8SPieter Jansen van Vuuren
317d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, NULL);
318b7fe4ab8SPieter Jansen van Vuuren cls_mall.command = TC_CLSMATCHALL_STATS;
319b7fe4ab8SPieter Jansen van Vuuren cls_mall.cookie = cookie;
320b7fe4ab8SPieter Jansen van Vuuren
32140119211SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSMATCHALL, &cls_mall, false, true);
322b7fe4ab8SPieter Jansen van Vuuren
3235246c896SOz Shlomo tcf_exts_hw_stats_update(&head->exts, &cls_mall.stats, cls_mall.use_act_stats);
324b7fe4ab8SPieter Jansen van Vuuren }
325b7fe4ab8SPieter Jansen van Vuuren
mall_dump(struct net * net,struct tcf_proto * tp,void * fh,struct sk_buff * skb,struct tcmsg * t,bool rtnl_held)3268113c095SWANG Cong static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,
32712db03b6SVlad Buslov struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
328bf3994d2SJiri Pirko {
329f88c19aaSCong Wang struct tc_matchall_pcnt gpf = {};
3308113c095SWANG Cong struct cls_mall_head *head = fh;
331bf3994d2SJiri Pirko struct nlattr *nest;
332f88c19aaSCong Wang int cpu;
333bf3994d2SJiri Pirko
334fd62d9f5SYotam Gigi if (!head)
335bf3994d2SJiri Pirko return skb->len;
336bf3994d2SJiri Pirko
337b7fe4ab8SPieter Jansen van Vuuren if (!tc_skip_hw(head->flags))
338b7fe4ab8SPieter Jansen van Vuuren mall_stats_hw_filter(tp, head, (unsigned long)head);
339b7fe4ab8SPieter Jansen van Vuuren
340fd62d9f5SYotam Gigi t->tcm_handle = head->handle;
341bf3994d2SJiri Pirko
342ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
343bf3994d2SJiri Pirko if (!nest)
344bf3994d2SJiri Pirko goto nla_put_failure;
345bf3994d2SJiri Pirko
346fd62d9f5SYotam Gigi if (head->res.classid &&
347fd62d9f5SYotam Gigi nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid))
348bf3994d2SJiri Pirko goto nla_put_failure;
349bf3994d2SJiri Pirko
3507a335adaSOr Gerlitz if (head->flags && nla_put_u32(skb, TCA_MATCHALL_FLAGS, head->flags))
3517a335adaSOr Gerlitz goto nla_put_failure;
3527a335adaSOr Gerlitz
353f88c19aaSCong Wang for_each_possible_cpu(cpu) {
354f88c19aaSCong Wang struct tc_matchall_pcnt *pf = per_cpu_ptr(head->pf, cpu);
355f88c19aaSCong Wang
356f88c19aaSCong Wang gpf.rhit += pf->rhit;
357f88c19aaSCong Wang }
358f88c19aaSCong Wang
359f88c19aaSCong Wang if (nla_put_64bit(skb, TCA_MATCHALL_PCNT,
360f88c19aaSCong Wang sizeof(struct tc_matchall_pcnt),
361f88c19aaSCong Wang &gpf, TCA_MATCHALL_PAD))
362f88c19aaSCong Wang goto nla_put_failure;
363f88c19aaSCong Wang
364fd62d9f5SYotam Gigi if (tcf_exts_dump(skb, &head->exts))
365bf3994d2SJiri Pirko goto nla_put_failure;
366bf3994d2SJiri Pirko
367bf3994d2SJiri Pirko nla_nest_end(skb, nest);
368bf3994d2SJiri Pirko
369fd62d9f5SYotam Gigi if (tcf_exts_dump_stats(skb, &head->exts) < 0)
370bf3994d2SJiri Pirko goto nla_put_failure;
371bf3994d2SJiri Pirko
372bf3994d2SJiri Pirko return skb->len;
373bf3994d2SJiri Pirko
374bf3994d2SJiri Pirko nla_put_failure:
375bf3994d2SJiri Pirko nla_nest_cancel(skb, nest);
376bf3994d2SJiri Pirko return -1;
377bf3994d2SJiri Pirko }
378bf3994d2SJiri Pirko
mall_bind_class(void * fh,u32 classid,unsigned long cl,void * q,unsigned long base)3792e24cd75SCong Wang static void mall_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
3802e24cd75SCong Wang unsigned long base)
38107d79fc7SCong Wang {
38207d79fc7SCong Wang struct cls_mall_head *head = fh;
38307d79fc7SCong Wang
384cc9039a1SZhengchao Shao tc_cls_bind_class(classid, cl, q, &head->res, base);
38507d79fc7SCong Wang }
38607d79fc7SCong Wang
387bf3994d2SJiri Pirko static struct tcf_proto_ops cls_mall_ops __read_mostly = {
388bf3994d2SJiri Pirko .kind = "matchall",
389bf3994d2SJiri Pirko .classify = mall_classify,
390bf3994d2SJiri Pirko .init = mall_init,
391bf3994d2SJiri Pirko .destroy = mall_destroy,
392bf3994d2SJiri Pirko .get = mall_get,
393bf3994d2SJiri Pirko .change = mall_change,
394bf3994d2SJiri Pirko .delete = mall_delete,
395bf3994d2SJiri Pirko .walk = mall_walk,
3960efd1b3aSJohn Hurley .reoffload = mall_reoffload,
397bf3994d2SJiri Pirko .dump = mall_dump,
39807d79fc7SCong Wang .bind_class = mall_bind_class,
399bf3994d2SJiri Pirko .owner = THIS_MODULE,
400bf3994d2SJiri Pirko };
401bf3994d2SJiri Pirko
cls_mall_init(void)402bf3994d2SJiri Pirko static int __init cls_mall_init(void)
403bf3994d2SJiri Pirko {
404bf3994d2SJiri Pirko return register_tcf_proto_ops(&cls_mall_ops);
405bf3994d2SJiri Pirko }
406bf3994d2SJiri Pirko
cls_mall_exit(void)407bf3994d2SJiri Pirko static void __exit cls_mall_exit(void)
408bf3994d2SJiri Pirko {
409bf3994d2SJiri Pirko unregister_tcf_proto_ops(&cls_mall_ops);
410bf3994d2SJiri Pirko }
411bf3994d2SJiri Pirko
412bf3994d2SJiri Pirko module_init(cls_mall_init);
413bf3994d2SJiri Pirko module_exit(cls_mall_exit);
414bf3994d2SJiri Pirko
415bf3994d2SJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
416bf3994d2SJiri Pirko MODULE_DESCRIPTION("Match-all classifier");
417bf3994d2SJiri Pirko MODULE_LICENSE("GPL v2");
418