xref: /openbmc/linux/net/sched/cls_matchall.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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