]> git.ipfire.org Git - thirdparty/linux.git/blame - drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
net/mlx5: Add creation flags when adding new flow table
[thirdparty/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
CommitLineData
e8f887ac
AV
1/*
2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
e3a2b7ed
AV
33#include <net/flow_dissector.h>
34#include <net/pkt_cls.h>
35#include <net/tc_act/tc_gact.h>
12185a9f 36#include <net/tc_act/tc_skbedit.h>
e8f887ac
AV
37#include <linux/mlx5/fs.h>
38#include <linux/mlx5/device.h>
39#include <linux/rhashtable.h>
03a9d11e
OG
40#include <net/switchdev.h>
41#include <net/tc_act/tc_mirred.h>
776b12b6 42#include <net/tc_act/tc_vlan.h>
e8f887ac
AV
43#include "en.h"
44#include "en_tc.h"
03a9d11e 45#include "eswitch.h"
e8f887ac
AV
46
47struct mlx5e_tc_flow {
48 struct rhash_head node;
49 u64 cookie;
74491de9 50 struct mlx5_flow_handle *rule;
776b12b6 51 struct mlx5_esw_flow_attr *attr;
e8f887ac
AV
52};
53
acff797c
MG
54#define MLX5E_TC_TABLE_NUM_ENTRIES 1024
55#define MLX5E_TC_TABLE_NUM_GROUPS 4
e8f887ac 56
74491de9
MB
57static struct mlx5_flow_handle *
58mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
59 struct mlx5_flow_spec *spec,
60 u32 action, u32 flow_tag)
e8f887ac 61{
aad7e08d
AV
62 struct mlx5_core_dev *dev = priv->mdev;
63 struct mlx5_flow_destination dest = { 0 };
64 struct mlx5_fc *counter = NULL;
74491de9 65 struct mlx5_flow_handle *rule;
e8f887ac
AV
66 bool table_created = false;
67
aad7e08d
AV
68 if (action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
69 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
70 dest.ft = priv->fs.vlan.ft.t;
55130287 71 } else if (action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
aad7e08d
AV
72 counter = mlx5_fc_create(dev, true);
73 if (IS_ERR(counter))
74 return ERR_CAST(counter);
75
76 dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
77 dest.counter = counter;
78 }
79
acff797c
MG
80 if (IS_ERR_OR_NULL(priv->fs.tc.t)) {
81 priv->fs.tc.t =
82 mlx5_create_auto_grouped_flow_table(priv->fs.ns,
83 MLX5E_TC_PRIO,
84 MLX5E_TC_TABLE_NUM_ENTRIES,
85 MLX5E_TC_TABLE_NUM_GROUPS,
c9f1b073 86 0, 0);
acff797c 87 if (IS_ERR(priv->fs.tc.t)) {
e8f887ac
AV
88 netdev_err(priv->netdev,
89 "Failed to create tc offload table\n");
aad7e08d
AV
90 rule = ERR_CAST(priv->fs.tc.t);
91 goto err_create_ft;
e8f887ac
AV
92 }
93
94 table_created = true;
95 }
96
c5bb1730 97 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
74491de9
MB
98 rule = mlx5_add_flow_rules(priv->fs.tc.t, spec,
99 action, flow_tag,
100 &dest, 1);
aad7e08d
AV
101
102 if (IS_ERR(rule))
103 goto err_add_rule;
104
105 return rule;
e8f887ac 106
aad7e08d
AV
107err_add_rule:
108 if (table_created) {
acff797c
MG
109 mlx5_destroy_flow_table(priv->fs.tc.t);
110 priv->fs.tc.t = NULL;
e8f887ac 111 }
aad7e08d
AV
112err_create_ft:
113 mlx5_fc_destroy(dev, counter);
e8f887ac
AV
114
115 return rule;
116}
117
74491de9
MB
118static struct mlx5_flow_handle *
119mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
120 struct mlx5_flow_spec *spec,
121 struct mlx5_esw_flow_attr *attr)
adb4c123
OG
122{
123 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
8b32580d
OG
124 int err;
125
126 err = mlx5_eswitch_add_vlan_action(esw, attr);
127 if (err)
128 return ERR_PTR(err);
adb4c123 129
776b12b6 130 return mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
adb4c123
OG
131}
132
e8f887ac 133static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
74491de9 134 struct mlx5_flow_handle *rule,
8b32580d 135 struct mlx5_esw_flow_attr *attr)
e8f887ac 136{
8b32580d 137 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
aad7e08d
AV
138 struct mlx5_fc *counter = NULL;
139
140 counter = mlx5_flow_rule_counter(rule);
141
8b32580d
OG
142 if (esw && esw->mode == SRIOV_OFFLOADS)
143 mlx5_eswitch_del_vlan_action(esw, attr);
144
74491de9 145 mlx5_del_flow_rules(rule);
e8f887ac 146
aad7e08d
AV
147 mlx5_fc_destroy(priv->mdev, counter);
148
5c40348c 149 if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) {
acff797c
MG
150 mlx5_destroy_flow_table(priv->fs.tc.t);
151 priv->fs.tc.t = NULL;
e8f887ac
AV
152 }
153}
154
c5bb1730 155static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec,
e3a2b7ed
AV
156 struct tc_cls_flower_offload *f)
157{
c5bb1730
MG
158 void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
159 outer_headers);
160 void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
161 outer_headers);
e3a2b7ed
AV
162 u16 addr_type = 0;
163 u8 ip_proto = 0;
164
165 if (f->dissector->used_keys &
166 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
167 BIT(FLOW_DISSECTOR_KEY_BASIC) |
168 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
095b6cfd 169 BIT(FLOW_DISSECTOR_KEY_VLAN) |
e3a2b7ed
AV
170 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
171 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
172 BIT(FLOW_DISSECTOR_KEY_PORTS))) {
173 netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
174 f->dissector->used_keys);
175 return -EOPNOTSUPP;
176 }
177
178 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
179 struct flow_dissector_key_control *key =
180 skb_flow_dissector_target(f->dissector,
1dbd0d37 181 FLOW_DISSECTOR_KEY_CONTROL,
e3a2b7ed
AV
182 f->key);
183 addr_type = key->addr_type;
184 }
185
186 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
187 struct flow_dissector_key_basic *key =
188 skb_flow_dissector_target(f->dissector,
189 FLOW_DISSECTOR_KEY_BASIC,
190 f->key);
191 struct flow_dissector_key_basic *mask =
192 skb_flow_dissector_target(f->dissector,
193 FLOW_DISSECTOR_KEY_BASIC,
194 f->mask);
195 ip_proto = key->ip_proto;
196
197 MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype,
198 ntohs(mask->n_proto));
199 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
200 ntohs(key->n_proto));
201
202 MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol,
203 mask->ip_proto);
204 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
205 key->ip_proto);
206 }
207
208 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
209 struct flow_dissector_key_eth_addrs *key =
210 skb_flow_dissector_target(f->dissector,
211 FLOW_DISSECTOR_KEY_ETH_ADDRS,
212 f->key);
213 struct flow_dissector_key_eth_addrs *mask =
214 skb_flow_dissector_target(f->dissector,
215 FLOW_DISSECTOR_KEY_ETH_ADDRS,
216 f->mask);
217
218 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
219 dmac_47_16),
220 mask->dst);
221 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
222 dmac_47_16),
223 key->dst);
224
225 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
226 smac_47_16),
227 mask->src);
228 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
229 smac_47_16),
230 key->src);
231 }
232
095b6cfd
OG
233 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
234 struct flow_dissector_key_vlan *key =
235 skb_flow_dissector_target(f->dissector,
236 FLOW_DISSECTOR_KEY_VLAN,
237 f->key);
238 struct flow_dissector_key_vlan *mask =
239 skb_flow_dissector_target(f->dissector,
240 FLOW_DISSECTOR_KEY_VLAN,
241 f->mask);
242 if (mask->vlan_id) {
243 MLX5_SET(fte_match_set_lyr_2_4, headers_c, vlan_tag, 1);
244 MLX5_SET(fte_match_set_lyr_2_4, headers_v, vlan_tag, 1);
245
246 MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id);
247 MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id);
248 }
249 }
250
e3a2b7ed
AV
251 if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
252 struct flow_dissector_key_ipv4_addrs *key =
253 skb_flow_dissector_target(f->dissector,
254 FLOW_DISSECTOR_KEY_IPV4_ADDRS,
255 f->key);
256 struct flow_dissector_key_ipv4_addrs *mask =
257 skb_flow_dissector_target(f->dissector,
258 FLOW_DISSECTOR_KEY_IPV4_ADDRS,
259 f->mask);
260
261 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
262 src_ipv4_src_ipv6.ipv4_layout.ipv4),
263 &mask->src, sizeof(mask->src));
264 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
265 src_ipv4_src_ipv6.ipv4_layout.ipv4),
266 &key->src, sizeof(key->src));
267 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
268 dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
269 &mask->dst, sizeof(mask->dst));
270 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
271 dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
272 &key->dst, sizeof(key->dst));
273 }
274
275 if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
276 struct flow_dissector_key_ipv6_addrs *key =
277 skb_flow_dissector_target(f->dissector,
278 FLOW_DISSECTOR_KEY_IPV6_ADDRS,
279 f->key);
280 struct flow_dissector_key_ipv6_addrs *mask =
281 skb_flow_dissector_target(f->dissector,
282 FLOW_DISSECTOR_KEY_IPV6_ADDRS,
283 f->mask);
284
285 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
286 src_ipv4_src_ipv6.ipv6_layout.ipv6),
287 &mask->src, sizeof(mask->src));
288 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
289 src_ipv4_src_ipv6.ipv6_layout.ipv6),
290 &key->src, sizeof(key->src));
291
292 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
293 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
294 &mask->dst, sizeof(mask->dst));
295 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
296 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
297 &key->dst, sizeof(key->dst));
298 }
299
300 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
301 struct flow_dissector_key_ports *key =
302 skb_flow_dissector_target(f->dissector,
303 FLOW_DISSECTOR_KEY_PORTS,
304 f->key);
305 struct flow_dissector_key_ports *mask =
306 skb_flow_dissector_target(f->dissector,
307 FLOW_DISSECTOR_KEY_PORTS,
308 f->mask);
309 switch (ip_proto) {
310 case IPPROTO_TCP:
311 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
312 tcp_sport, ntohs(mask->src));
313 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
314 tcp_sport, ntohs(key->src));
315
316 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
317 tcp_dport, ntohs(mask->dst));
318 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
319 tcp_dport, ntohs(key->dst));
320 break;
321
322 case IPPROTO_UDP:
323 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
324 udp_sport, ntohs(mask->src));
325 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
326 udp_sport, ntohs(key->src));
327
328 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
329 udp_dport, ntohs(mask->dst));
330 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
331 udp_dport, ntohs(key->dst));
332 break;
333 default:
334 netdev_err(priv->netdev,
335 "Only UDP and TCP transport are supported\n");
336 return -EINVAL;
337 }
338 }
339
340 return 0;
341}
342
5c40348c
OG
343static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
344 u32 *action, u32 *flow_tag)
e3a2b7ed
AV
345{
346 const struct tc_action *a;
22dc13c8 347 LIST_HEAD(actions);
e3a2b7ed
AV
348
349 if (tc_no_actions(exts))
350 return -EINVAL;
351
352 *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
353 *action = 0;
354
22dc13c8
WC
355 tcf_exts_to_list(exts, &actions);
356 list_for_each_entry(a, &actions, list) {
e3a2b7ed
AV
357 /* Only support a single action per rule */
358 if (*action)
359 return -EINVAL;
360
361 if (is_tcf_gact_shot(a)) {
362 *action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
aad7e08d
AV
363 if (MLX5_CAP_FLOWTABLE(priv->mdev,
364 flow_table_properties_nic_receive.flow_counter))
365 *action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
e3a2b7ed
AV
366 continue;
367 }
368
369 if (is_tcf_skbedit_mark(a)) {
370 u32 mark = tcf_skbedit_mark(a);
371
372 if (mark & ~MLX5E_TC_FLOW_ID_MASK) {
373 netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n",
374 mark);
375 return -EINVAL;
376 }
377
378 *flow_tag = mark;
379 *action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
380 continue;
381 }
382
383 return -EINVAL;
384 }
385
386 return 0;
387}
388
03a9d11e 389static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
776b12b6 390 struct mlx5_esw_flow_attr *attr)
03a9d11e
OG
391{
392 const struct tc_action *a;
22dc13c8 393 LIST_HEAD(actions);
03a9d11e
OG
394
395 if (tc_no_actions(exts))
396 return -EINVAL;
397
776b12b6
OG
398 memset(attr, 0, sizeof(*attr));
399 attr->in_rep = priv->ppriv;
03a9d11e 400
22dc13c8
WC
401 tcf_exts_to_list(exts, &actions);
402 list_for_each_entry(a, &actions, list) {
03a9d11e 403 if (is_tcf_gact_shot(a)) {
8b32580d
OG
404 attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP |
405 MLX5_FLOW_CONTEXT_ACTION_COUNT;
03a9d11e
OG
406 continue;
407 }
408
5724b8b5 409 if (is_tcf_mirred_egress_redirect(a)) {
03a9d11e
OG
410 int ifindex = tcf_mirred_ifindex(a);
411 struct net_device *out_dev;
412 struct mlx5e_priv *out_priv;
03a9d11e
OG
413
414 out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex);
415
416 if (!switchdev_port_same_parent_id(priv->netdev, out_dev)) {
417 pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
418 priv->netdev->name, out_dev->name);
419 return -EINVAL;
420 }
421
e37a79e5
MB
422 attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
423 MLX5_FLOW_CONTEXT_ACTION_COUNT;
03a9d11e 424 out_priv = netdev_priv(out_dev);
776b12b6 425 attr->out_rep = out_priv->ppriv;
03a9d11e
OG
426 continue;
427 }
428
8b32580d
OG
429 if (is_tcf_vlan(a)) {
430 if (tcf_vlan_action(a) == VLAN_F_POP) {
431 attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
432 } else if (tcf_vlan_action(a) == VLAN_F_PUSH) {
433 if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q))
434 return -EOPNOTSUPP;
435
436 attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
437 attr->vlan = tcf_vlan_push_vid(a);
438 }
439 continue;
440 }
441
03a9d11e
OG
442 return -EINVAL;
443 }
444 return 0;
445}
446
e3a2b7ed
AV
447int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
448 struct tc_cls_flower_offload *f)
449{
acff797c 450 struct mlx5e_tc_table *tc = &priv->fs.tc;
e3a2b7ed 451 int err = 0;
776b12b6
OG
452 bool fdb_flow = false;
453 u32 flow_tag, action;
e3a2b7ed 454 struct mlx5e_tc_flow *flow;
c5bb1730 455 struct mlx5_flow_spec *spec;
74491de9 456 struct mlx5_flow_handle *old = NULL;
d0debb76 457 struct mlx5_esw_flow_attr *old_attr = NULL;
adb4c123 458 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
e3a2b7ed 459
776b12b6
OG
460 if (esw && esw->mode == SRIOV_OFFLOADS)
461 fdb_flow = true;
462
e3a2b7ed
AV
463 flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
464 tc->ht_params);
776b12b6 465 if (flow) {
e3a2b7ed 466 old = flow->rule;
8b32580d 467 old_attr = flow->attr;
776b12b6
OG
468 } else {
469 if (fdb_flow)
470 flow = kzalloc(sizeof(*flow) + sizeof(struct mlx5_esw_flow_attr),
471 GFP_KERNEL);
472 else
473 flow = kzalloc(sizeof(*flow), GFP_KERNEL);
474 }
e3a2b7ed 475
c5bb1730
MG
476 spec = mlx5_vzalloc(sizeof(*spec));
477 if (!spec || !flow) {
e3a2b7ed
AV
478 err = -ENOMEM;
479 goto err_free;
480 }
481
482 flow->cookie = f->cookie;
483
c5bb1730 484 err = parse_cls_flower(priv, spec, f);
e3a2b7ed
AV
485 if (err < 0)
486 goto err_free;
487
776b12b6
OG
488 if (fdb_flow) {
489 flow->attr = (struct mlx5_esw_flow_attr *)(flow + 1);
490 err = parse_tc_fdb_actions(priv, f->exts, flow->attr);
adb4c123
OG
491 if (err < 0)
492 goto err_free;
776b12b6 493 flow->rule = mlx5e_tc_add_fdb_flow(priv, spec, flow->attr);
adb4c123
OG
494 } else {
495 err = parse_tc_nic_actions(priv, f->exts, &action, &flow_tag);
496 if (err < 0)
497 goto err_free;
498 flow->rule = mlx5e_tc_add_nic_flow(priv, spec, action, flow_tag);
499 }
e3a2b7ed 500
e3a2b7ed
AV
501 if (IS_ERR(flow->rule)) {
502 err = PTR_ERR(flow->rule);
5c40348c 503 goto err_free;
e3a2b7ed
AV
504 }
505
5c40348c
OG
506 err = rhashtable_insert_fast(&tc->ht, &flow->node,
507 tc->ht_params);
508 if (err)
509 goto err_del_rule;
510
e3a2b7ed 511 if (old)
8b32580d 512 mlx5e_tc_del_flow(priv, old, old_attr);
e3a2b7ed
AV
513
514 goto out;
515
5c40348c 516err_del_rule:
74491de9 517 mlx5_del_flow_rules(flow->rule);
e3a2b7ed
AV
518
519err_free:
520 if (!old)
521 kfree(flow);
522out:
c5bb1730 523 kvfree(spec);
e3a2b7ed
AV
524 return err;
525}
526
527int mlx5e_delete_flower(struct mlx5e_priv *priv,
528 struct tc_cls_flower_offload *f)
529{
530 struct mlx5e_tc_flow *flow;
acff797c 531 struct mlx5e_tc_table *tc = &priv->fs.tc;
e3a2b7ed
AV
532
533 flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
534 tc->ht_params);
535 if (!flow)
536 return -EINVAL;
537
538 rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
539
8b32580d 540 mlx5e_tc_del_flow(priv, flow->rule, flow->attr);
e3a2b7ed
AV
541
542 kfree(flow);
543
544 return 0;
545}
546
aad7e08d
AV
547int mlx5e_stats_flower(struct mlx5e_priv *priv,
548 struct tc_cls_flower_offload *f)
549{
550 struct mlx5e_tc_table *tc = &priv->fs.tc;
551 struct mlx5e_tc_flow *flow;
552 struct tc_action *a;
553 struct mlx5_fc *counter;
22dc13c8 554 LIST_HEAD(actions);
aad7e08d
AV
555 u64 bytes;
556 u64 packets;
557 u64 lastuse;
558
559 flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
560 tc->ht_params);
561 if (!flow)
562 return -EINVAL;
563
564 counter = mlx5_flow_rule_counter(flow->rule);
565 if (!counter)
566 return 0;
567
568 mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
569
22dc13c8
WC
570 tcf_exts_to_list(f->exts, &actions);
571 list_for_each_entry(a, &actions, list)
aad7e08d
AV
572 tcf_action_stats_update(a, bytes, packets, lastuse);
573
574 return 0;
575}
576
e8f887ac
AV
577static const struct rhashtable_params mlx5e_tc_flow_ht_params = {
578 .head_offset = offsetof(struct mlx5e_tc_flow, node),
579 .key_offset = offsetof(struct mlx5e_tc_flow, cookie),
580 .key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie),
581 .automatic_shrinking = true,
582};
583
584int mlx5e_tc_init(struct mlx5e_priv *priv)
585{
acff797c 586 struct mlx5e_tc_table *tc = &priv->fs.tc;
e8f887ac
AV
587
588 tc->ht_params = mlx5e_tc_flow_ht_params;
589 return rhashtable_init(&tc->ht, &tc->ht_params);
590}
591
592static void _mlx5e_tc_del_flow(void *ptr, void *arg)
593{
594 struct mlx5e_tc_flow *flow = ptr;
595 struct mlx5e_priv *priv = arg;
596
8b32580d 597 mlx5e_tc_del_flow(priv, flow->rule, flow->attr);
e8f887ac
AV
598 kfree(flow);
599}
600
601void mlx5e_tc_cleanup(struct mlx5e_priv *priv)
602{
acff797c 603 struct mlx5e_tc_table *tc = &priv->fs.tc;
e8f887ac
AV
604
605 rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv);
606
acff797c
MG
607 if (!IS_ERR_OR_NULL(tc->t)) {
608 mlx5_destroy_flow_table(tc->t);
609 tc->t = NULL;
e8f887ac
AV
610 }
611}