hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/sched/cls_matchall.c
....@@ -1,17 +1,14 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * net/sched/cls_matchll.c Match-all classifier
34 *
45 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License as published by
8
- * the Free Software Foundation; either version 2 of the License, or
9
- * (at your option) any later version.
106 */
117
128 #include <linux/kernel.h>
139 #include <linux/init.h>
1410 #include <linux/module.h>
11
+#include <linux/percpu.h>
1512
1613 #include <net/sch_generic.h>
1714 #include <net/pkt_cls.h>
....@@ -22,7 +19,9 @@
2219 u32 handle;
2320 u32 flags;
2421 unsigned int in_hw_count;
22
+ struct tc_matchall_pcnt __percpu *pf;
2523 struct rcu_work rwork;
24
+ bool deleting;
2625 };
2726
2827 static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
....@@ -30,10 +29,14 @@
3029 {
3130 struct cls_mall_head *head = rcu_dereference_bh(tp->root);
3231
32
+ if (unlikely(!head))
33
+ return -1;
34
+
3335 if (tc_skip_sw(head->flags))
3436 return -1;
3537
3638 *res = head->res;
39
+ __this_cpu_inc(head->pf->rhit);
3740 return tcf_exts_exec(skb, &head->exts, res);
3841 }
3942
....@@ -46,6 +49,7 @@
4649 {
4750 tcf_exts_destroy(&head->exts);
4851 tcf_exts_put_net(&head->exts);
52
+ free_percpu(head->pf);
4953 kfree(head);
5054 }
5155
....@@ -71,8 +75,8 @@
7175 cls_mall.command = TC_CLSMATCHALL_DESTROY;
7276 cls_mall.cookie = cookie;
7377
74
- tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL, &cls_mall, false);
75
- tcf_block_offload_dec(block, &head->flags);
78
+ tc_setup_cb_destroy(block, tp, TC_SETUP_CLSMATCHALL, &cls_mall, false,
79
+ &head->flags, &head->in_hw_count, true);
7680 }
7781
7882 static int mall_replace_hw_filter(struct tcf_proto *tp,
....@@ -85,19 +89,34 @@
8589 bool skip_sw = tc_skip_sw(head->flags);
8690 int err;
8791
92
+ cls_mall.rule = flow_rule_alloc(tcf_exts_num_actions(&head->exts));
93
+ if (!cls_mall.rule)
94
+ return -ENOMEM;
95
+
8896 tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
8997 cls_mall.command = TC_CLSMATCHALL_REPLACE;
90
- cls_mall.exts = &head->exts;
9198 cls_mall.cookie = cookie;
9299
93
- err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL,
94
- &cls_mall, skip_sw);
95
- if (err < 0) {
100
+ err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts);
101
+ if (err) {
102
+ kfree(cls_mall.rule);
103
+ mall_destroy_hw_filter(tp, head, cookie, NULL);
104
+ if (skip_sw)
105
+ NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action");
106
+ else
107
+ err = 0;
108
+
109
+ return err;
110
+ }
111
+
112
+ err = tc_setup_cb_add(block, tp, TC_SETUP_CLSMATCHALL, &cls_mall,
113
+ skip_sw, &head->flags, &head->in_hw_count, true);
114
+ tc_cleanup_flow_action(&cls_mall.rule->action);
115
+ kfree(cls_mall.rule);
116
+
117
+ if (err) {
96118 mall_destroy_hw_filter(tp, head, cookie, NULL);
97119 return err;
98
- } else if (err > 0) {
99
- head->in_hw_count = err;
100
- tcf_block_offload_inc(block, &head->flags);
101120 }
102121
103122 if (skip_sw && !(head->flags & TCA_CLS_FLAGS_IN_HW))
....@@ -106,7 +125,8 @@
106125 return 0;
107126 }
108127
109
-static void mall_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
128
+static void mall_destroy(struct tcf_proto *tp, bool rtnl_held,
129
+ struct netlink_ext_ack *extack)
110130 {
111131 struct cls_mall_head *head = rtnl_dereference(tp->root);
112132
....@@ -148,7 +168,8 @@
148168 {
149169 int err;
150170
151
- err = tcf_exts_validate(net, tp, tb, est, &head->exts, ovr, extack);
171
+ err = tcf_exts_validate(net, tp, tb, est, &head->exts, ovr, true,
172
+ extack);
152173 if (err < 0)
153174 return err;
154175
....@@ -162,7 +183,8 @@
162183 static int mall_change(struct net *net, struct sk_buff *in_skb,
163184 struct tcf_proto *tp, unsigned long base,
164185 u32 handle, struct nlattr **tca,
165
- void **arg, bool ovr, struct netlink_ext_ack *extack)
186
+ void **arg, bool ovr, bool rtnl_held,
187
+ struct netlink_ext_ack *extack)
166188 {
167189 struct cls_mall_head *head = rtnl_dereference(tp->root);
168190 struct nlattr *tb[TCA_MATCHALL_MAX + 1];
....@@ -176,8 +198,8 @@
176198 if (head)
177199 return -EEXIST;
178200
179
- err = nla_parse_nested(tb, TCA_MATCHALL_MAX, tca[TCA_OPTIONS],
180
- mall_policy, NULL);
201
+ err = nla_parse_nested_deprecated(tb, TCA_MATCHALL_MAX,
202
+ tca[TCA_OPTIONS], mall_policy, NULL);
181203 if (err < 0)
182204 return err;
183205
....@@ -191,7 +213,7 @@
191213 if (!new)
192214 return -ENOBUFS;
193215
194
- err = tcf_exts_init(&new->exts, TCA_MATCHALL_ACT, 0);
216
+ err = tcf_exts_init(&new->exts, net, TCA_MATCHALL_ACT, 0);
195217 if (err)
196218 goto err_exts_init;
197219
....@@ -199,6 +221,11 @@
199221 handle = 1;
200222 new->handle = handle;
201223 new->flags = flags;
224
+ new->pf = alloc_percpu(struct tc_matchall_pcnt);
225
+ if (!new->pf) {
226
+ err = -ENOMEM;
227
+ goto err_alloc_percpu;
228
+ }
202229
203230 err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr,
204231 extack);
....@@ -221,6 +248,8 @@
221248
222249 err_replace_hw_filter:
223250 err_set_parms:
251
+ free_percpu(new->pf);
252
+err_alloc_percpu:
224253 tcf_exts_destroy(&new->exts);
225254 err_exts_init:
226255 kfree(new);
....@@ -228,24 +257,32 @@
228257 }
229258
230259 static int mall_delete(struct tcf_proto *tp, void *arg, bool *last,
231
- struct netlink_ext_ack *extack)
260
+ bool rtnl_held, struct netlink_ext_ack *extack)
232261 {
233
- return -EOPNOTSUPP;
262
+ struct cls_mall_head *head = rtnl_dereference(tp->root);
263
+
264
+ head->deleting = true;
265
+ *last = true;
266
+ return 0;
234267 }
235268
236
-static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
269
+static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg,
270
+ bool rtnl_held)
237271 {
238272 struct cls_mall_head *head = rtnl_dereference(tp->root);
239273
240274 if (arg->count < arg->skip)
241275 goto skip;
276
+
277
+ if (!head || head->deleting)
278
+ return;
242279 if (arg->fn(tp, head, arg) < 0)
243280 arg->stop = 1;
244281 skip:
245282 arg->count++;
246283 }
247284
248
-static int mall_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
285
+static int mall_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
249286 void *cb_priv, struct netlink_ext_ack *extack)
250287 {
251288 struct cls_mall_head *head = rtnl_dereference(tp->root);
....@@ -256,36 +293,74 @@
256293 if (tc_skip_hw(head->flags))
257294 return 0;
258295
296
+ cls_mall.rule = flow_rule_alloc(tcf_exts_num_actions(&head->exts));
297
+ if (!cls_mall.rule)
298
+ return -ENOMEM;
299
+
259300 tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
260301 cls_mall.command = add ?
261302 TC_CLSMATCHALL_REPLACE : TC_CLSMATCHALL_DESTROY;
262
- cls_mall.exts = &head->exts;
263303 cls_mall.cookie = (unsigned long)head;
264304
265
- err = cb(TC_SETUP_CLSMATCHALL, &cls_mall, cb_priv);
305
+ err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts);
266306 if (err) {
267
- if (add && tc_skip_sw(head->flags))
307
+ kfree(cls_mall.rule);
308
+ if (add && tc_skip_sw(head->flags)) {
309
+ NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action");
268310 return err;
311
+ }
269312 return 0;
270313 }
271314
272
- tc_cls_offload_cnt_update(block, &head->in_hw_count, &head->flags, add);
315
+ err = tc_setup_cb_reoffload(block, tp, add, cb, TC_SETUP_CLSMATCHALL,
316
+ &cls_mall, cb_priv, &head->flags,
317
+ &head->in_hw_count);
318
+ tc_cleanup_flow_action(&cls_mall.rule->action);
319
+ kfree(cls_mall.rule);
320
+
321
+ if (err)
322
+ return err;
273323
274324 return 0;
275325 }
276326
277
-static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,
278
- struct sk_buff *skb, struct tcmsg *t)
327
+static void mall_stats_hw_filter(struct tcf_proto *tp,
328
+ struct cls_mall_head *head,
329
+ unsigned long cookie)
279330 {
331
+ struct tc_cls_matchall_offload cls_mall = {};
332
+ struct tcf_block *block = tp->chain->block;
333
+
334
+ tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, NULL);
335
+ cls_mall.command = TC_CLSMATCHALL_STATS;
336
+ cls_mall.cookie = cookie;
337
+
338
+ tc_setup_cb_call(block, TC_SETUP_CLSMATCHALL, &cls_mall, false, true);
339
+
340
+ tcf_exts_stats_update(&head->exts, cls_mall.stats.bytes,
341
+ cls_mall.stats.pkts, cls_mall.stats.drops,
342
+ cls_mall.stats.lastused,
343
+ cls_mall.stats.used_hw_stats,
344
+ cls_mall.stats.used_hw_stats_valid);
345
+}
346
+
347
+static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,
348
+ struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
349
+{
350
+ struct tc_matchall_pcnt gpf = {};
280351 struct cls_mall_head *head = fh;
281352 struct nlattr *nest;
353
+ int cpu;
282354
283355 if (!head)
284356 return skb->len;
285357
358
+ if (!tc_skip_hw(head->flags))
359
+ mall_stats_hw_filter(tp, head, (unsigned long)head);
360
+
286361 t->tcm_handle = head->handle;
287362
288
- nest = nla_nest_start(skb, TCA_OPTIONS);
363
+ nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
289364 if (!nest)
290365 goto nla_put_failure;
291366
....@@ -296,6 +371,17 @@
296371 if (head->flags && nla_put_u32(skb, TCA_MATCHALL_FLAGS, head->flags))
297372 goto nla_put_failure;
298373
374
+ for_each_possible_cpu(cpu) {
375
+ struct tc_matchall_pcnt *pf = per_cpu_ptr(head->pf, cpu);
376
+
377
+ gpf.rhit += pf->rhit;
378
+ }
379
+
380
+ if (nla_put_64bit(skb, TCA_MATCHALL_PCNT,
381
+ sizeof(struct tc_matchall_pcnt),
382
+ &gpf, TCA_MATCHALL_PAD))
383
+ goto nla_put_failure;
384
+
299385 if (tcf_exts_dump(skb, &head->exts))
300386 goto nla_put_failure;
301387