1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies. */
3
4 #include <net/netfilter/nf_conntrack.h>
5 #include <net/netfilter/nf_conntrack_core.h>
6 #include <net/netfilter/nf_conntrack_zones.h>
7 #include <net/netfilter/nf_conntrack_labels.h>
8 #include <net/netfilter/nf_conntrack_helper.h>
9 #include <net/netfilter/nf_conntrack_acct.h>
10 #include <uapi/linux/tc_act/tc_pedit.h>
11 #include <net/tc_act/tc_ct.h>
12 #include <net/flow_offload.h>
13 #include <net/netfilter/nf_flow_table.h>
14 #include <linux/workqueue.h>
15 #include <linux/refcount.h>
16 #include <linux/xarray.h>
17
18 #include "lib/fs_chains.h"
19 #include "en/tc_ct.h"
20 #include "en/mod_hdr.h"
21 #include "en/mapping.h"
22 #include "en/tc/post_act.h"
23 #include "en.h"
24 #include "en_tc.h"
25 #include "en_rep.h"
26
27 #define MLX5_CT_ZONE_BITS (mlx5e_tc_attr_to_reg_mappings[ZONE_TO_REG].mlen)
28 #define MLX5_CT_ZONE_MASK GENMASK(MLX5_CT_ZONE_BITS - 1, 0)
29 #define MLX5_CT_STATE_ESTABLISHED_BIT BIT(1)
30 #define MLX5_CT_STATE_TRK_BIT BIT(2)
31 #define MLX5_CT_STATE_NAT_BIT BIT(3)
32 #define MLX5_CT_STATE_REPLY_BIT BIT(4)
33 #define MLX5_CT_STATE_RELATED_BIT BIT(5)
34 #define MLX5_CT_STATE_INVALID_BIT BIT(6)
35
36 #define MLX5_CT_LABELS_BITS (mlx5e_tc_attr_to_reg_mappings[LABELS_TO_REG].mlen)
37 #define MLX5_CT_LABELS_MASK GENMASK(MLX5_CT_LABELS_BITS - 1, 0)
38
39 #define ct_dbg(fmt, args...)\
40 netdev_dbg(ct_priv->netdev, "ct_debug: " fmt "\n", ##args)
41
42 struct mlx5_tc_ct_priv {
43 struct mlx5_core_dev *dev;
44 const struct net_device *netdev;
45 struct mod_hdr_tbl *mod_hdr_tbl;
46 struct xarray tuple_ids;
47 struct rhashtable zone_ht;
48 struct rhashtable ct_tuples_ht;
49 struct rhashtable ct_tuples_nat_ht;
50 struct mlx5_flow_table *ct;
51 struct mlx5_flow_table *ct_nat;
52 struct mlx5e_post_act *post_act;
53 struct mutex control_lock; /* guards parallel adds/dels */
54 struct mapping_ctx *zone_mapping;
55 struct mapping_ctx *labels_mapping;
56 enum mlx5_flow_namespace_type ns_type;
57 struct mlx5_fs_chains *chains;
58 spinlock_t ht_lock; /* protects ft entries */
59 };
60
61 struct mlx5_ct_flow {
62 struct mlx5_flow_attr *pre_ct_attr;
63 struct mlx5_flow_handle *pre_ct_rule;
64 struct mlx5e_post_act_handle *post_act_handle;
65 struct mlx5_ct_ft *ft;
66 u32 chain_mapping;
67 };
68
69 struct mlx5_ct_zone_rule {
70 struct mlx5_flow_handle *rule;
71 struct mlx5e_mod_hdr_handle *mh;
72 struct mlx5_flow_attr *attr;
73 bool nat;
74 };
75
76 struct mlx5_tc_ct_pre {
77 struct mlx5_flow_table *ft;
78 struct mlx5_flow_group *flow_grp;
79 struct mlx5_flow_group *miss_grp;
80 struct mlx5_flow_handle *flow_rule;
81 struct mlx5_flow_handle *miss_rule;
82 struct mlx5_modify_hdr *modify_hdr;
83 };
84
85 struct mlx5_ct_ft {
86 struct rhash_head node;
87 u16 zone;
88 u32 zone_restore_id;
89 refcount_t refcount;
90 struct nf_flowtable *nf_ft;
91 struct mlx5_tc_ct_priv *ct_priv;
92 struct rhashtable ct_entries_ht;
93 struct mlx5_tc_ct_pre pre_ct;
94 struct mlx5_tc_ct_pre pre_ct_nat;
95 };
96
97 struct mlx5_ct_tuple {
98 u16 addr_type;
99 __be16 n_proto;
100 u8 ip_proto;
101 struct {
102 union {
103 __be32 src_v4;
104 struct in6_addr src_v6;
105 };
106 union {
107 __be32 dst_v4;
108 struct in6_addr dst_v6;
109 };
110 } ip;
111 struct {
112 __be16 src;
113 __be16 dst;
114 } port;
115
116 u16 zone;
117 };
118
119 struct mlx5_ct_counter {
120 struct mlx5_fc *counter;
121 refcount_t refcount;
122 bool is_shared;
123 };
124
125 enum {
126 MLX5_CT_ENTRY_FLAG_VALID,
127 };
128
129 struct mlx5_ct_entry {
130 struct rhash_head node;
131 struct rhash_head tuple_node;
132 struct rhash_head tuple_nat_node;
133 struct mlx5_ct_counter *counter;
134 unsigned long cookie;
135 unsigned long restore_cookie;
136 struct mlx5_ct_tuple tuple;
137 struct mlx5_ct_tuple tuple_nat;
138 struct mlx5_ct_zone_rule zone_rules[2];
139
140 struct mlx5_tc_ct_priv *ct_priv;
141 struct work_struct work;
142
143 refcount_t refcnt;
144 unsigned long flags;
145 };
146
147 static void
148 mlx5_tc_ct_entry_destroy_mod_hdr(struct mlx5_tc_ct_priv *ct_priv,
149 struct mlx5_flow_attr *attr,
150 struct mlx5e_mod_hdr_handle *mh);
151
152 static const struct rhashtable_params cts_ht_params = {
153 .head_offset = offsetof(struct mlx5_ct_entry, node),
154 .key_offset = offsetof(struct mlx5_ct_entry, cookie),
155 .key_len = sizeof(((struct mlx5_ct_entry *)0)->cookie),
156 .automatic_shrinking = true,
157 .min_size = 16 * 1024,
158 };
159
160 static const struct rhashtable_params zone_params = {
161 .head_offset = offsetof(struct mlx5_ct_ft, node),
162 .key_offset = offsetof(struct mlx5_ct_ft, zone),
163 .key_len = sizeof(((struct mlx5_ct_ft *)0)->zone),
164 .automatic_shrinking = true,
165 };
166
167 static const struct rhashtable_params tuples_ht_params = {
168 .head_offset = offsetof(struct mlx5_ct_entry, tuple_node),
169 .key_offset = offsetof(struct mlx5_ct_entry, tuple),
170 .key_len = sizeof(((struct mlx5_ct_entry *)0)->tuple),
171 .automatic_shrinking = true,
172 .min_size = 16 * 1024,
173 };
174
175 static const struct rhashtable_params tuples_nat_ht_params = {
176 .head_offset = offsetof(struct mlx5_ct_entry, tuple_nat_node),
177 .key_offset = offsetof(struct mlx5_ct_entry, tuple_nat),
178 .key_len = sizeof(((struct mlx5_ct_entry *)0)->tuple_nat),
179 .automatic_shrinking = true,
180 .min_size = 16 * 1024,
181 };
182
183 static bool
mlx5_tc_ct_entry_has_nat(struct mlx5_ct_entry * entry)184 mlx5_tc_ct_entry_has_nat(struct mlx5_ct_entry *entry)
185 {
186 return !!(entry->tuple_nat_node.next);
187 }
188
189 static int
mlx5_get_label_mapping(struct mlx5_tc_ct_priv * ct_priv,u32 * labels,u32 * id)190 mlx5_get_label_mapping(struct mlx5_tc_ct_priv *ct_priv,
191 u32 *labels, u32 *id)
192 {
193 if (!memchr_inv(labels, 0, sizeof(u32) * 4)) {
194 *id = 0;
195 return 0;
196 }
197
198 if (mapping_add(ct_priv->labels_mapping, labels, id))
199 return -EOPNOTSUPP;
200
201 return 0;
202 }
203
204 static void
mlx5_put_label_mapping(struct mlx5_tc_ct_priv * ct_priv,u32 id)205 mlx5_put_label_mapping(struct mlx5_tc_ct_priv *ct_priv, u32 id)
206 {
207 if (id)
208 mapping_remove(ct_priv->labels_mapping, id);
209 }
210
211 static int
mlx5_tc_ct_rule_to_tuple(struct mlx5_ct_tuple * tuple,struct flow_rule * rule)212 mlx5_tc_ct_rule_to_tuple(struct mlx5_ct_tuple *tuple, struct flow_rule *rule)
213 {
214 struct flow_match_control control;
215 struct flow_match_basic basic;
216
217 flow_rule_match_basic(rule, &basic);
218 flow_rule_match_control(rule, &control);
219
220 tuple->n_proto = basic.key->n_proto;
221 tuple->ip_proto = basic.key->ip_proto;
222 tuple->addr_type = control.key->addr_type;
223
224 if (tuple->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
225 struct flow_match_ipv4_addrs match;
226
227 flow_rule_match_ipv4_addrs(rule, &match);
228 tuple->ip.src_v4 = match.key->src;
229 tuple->ip.dst_v4 = match.key->dst;
230 } else if (tuple->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
231 struct flow_match_ipv6_addrs match;
232
233 flow_rule_match_ipv6_addrs(rule, &match);
234 tuple->ip.src_v6 = match.key->src;
235 tuple->ip.dst_v6 = match.key->dst;
236 } else {
237 return -EOPNOTSUPP;
238 }
239
240 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
241 struct flow_match_ports match;
242
243 flow_rule_match_ports(rule, &match);
244 switch (tuple->ip_proto) {
245 case IPPROTO_TCP:
246 case IPPROTO_UDP:
247 tuple->port.src = match.key->src;
248 tuple->port.dst = match.key->dst;
249 break;
250 default:
251 return -EOPNOTSUPP;
252 }
253 } else {
254 return -EOPNOTSUPP;
255 }
256
257 return 0;
258 }
259
260 static int
mlx5_tc_ct_rule_to_tuple_nat(struct mlx5_ct_tuple * tuple,struct flow_rule * rule)261 mlx5_tc_ct_rule_to_tuple_nat(struct mlx5_ct_tuple *tuple,
262 struct flow_rule *rule)
263 {
264 struct flow_action *flow_action = &rule->action;
265 struct flow_action_entry *act;
266 u32 offset, val, ip6_offset;
267 int i;
268
269 flow_action_for_each(i, act, flow_action) {
270 if (act->id != FLOW_ACTION_MANGLE)
271 continue;
272
273 offset = act->mangle.offset;
274 val = act->mangle.val;
275 switch (act->mangle.htype) {
276 case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
277 if (offset == offsetof(struct iphdr, saddr))
278 tuple->ip.src_v4 = cpu_to_be32(val);
279 else if (offset == offsetof(struct iphdr, daddr))
280 tuple->ip.dst_v4 = cpu_to_be32(val);
281 else
282 return -EOPNOTSUPP;
283 break;
284
285 case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
286 ip6_offset = (offset - offsetof(struct ipv6hdr, saddr));
287 ip6_offset /= 4;
288 if (ip6_offset < 4)
289 tuple->ip.src_v6.s6_addr32[ip6_offset] = cpu_to_be32(val);
290 else if (ip6_offset < 8)
291 tuple->ip.dst_v6.s6_addr32[ip6_offset - 4] = cpu_to_be32(val);
292 else
293 return -EOPNOTSUPP;
294 break;
295
296 case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
297 if (offset == offsetof(struct tcphdr, source))
298 tuple->port.src = cpu_to_be16(val);
299 else if (offset == offsetof(struct tcphdr, dest))
300 tuple->port.dst = cpu_to_be16(val);
301 else
302 return -EOPNOTSUPP;
303 break;
304
305 case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
306 if (offset == offsetof(struct udphdr, source))
307 tuple->port.src = cpu_to_be16(val);
308 else if (offset == offsetof(struct udphdr, dest))
309 tuple->port.dst = cpu_to_be16(val);
310 else
311 return -EOPNOTSUPP;
312 break;
313
314 default:
315 return -EOPNOTSUPP;
316 }
317 }
318
319 return 0;
320 }
321
322 static int
mlx5_tc_ct_set_tuple_match(struct mlx5e_priv * priv,struct mlx5_flow_spec * spec,struct flow_rule * rule)323 mlx5_tc_ct_set_tuple_match(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec,
324 struct flow_rule *rule)
325 {
326 void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
327 outer_headers);
328 void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
329 outer_headers);
330 u16 addr_type = 0;
331 u8 ip_proto = 0;
332
333 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
334 struct flow_match_basic match;
335
336 flow_rule_match_basic(rule, &match);
337
338 mlx5e_tc_set_ethertype(priv->mdev, &match, true, headers_c,
339 headers_v);
340 MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol,
341 match.mask->ip_proto);
342 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
343 match.key->ip_proto);
344
345 ip_proto = match.key->ip_proto;
346 }
347
348 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
349 struct flow_match_control match;
350
351 flow_rule_match_control(rule, &match);
352 addr_type = match.key->addr_type;
353 }
354
355 if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
356 struct flow_match_ipv4_addrs match;
357
358 flow_rule_match_ipv4_addrs(rule, &match);
359 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
360 src_ipv4_src_ipv6.ipv4_layout.ipv4),
361 &match.mask->src, sizeof(match.mask->src));
362 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
363 src_ipv4_src_ipv6.ipv4_layout.ipv4),
364 &match.key->src, sizeof(match.key->src));
365 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
366 dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
367 &match.mask->dst, sizeof(match.mask->dst));
368 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
369 dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
370 &match.key->dst, sizeof(match.key->dst));
371 }
372
373 if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
374 struct flow_match_ipv6_addrs match;
375
376 flow_rule_match_ipv6_addrs(rule, &match);
377 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
378 src_ipv4_src_ipv6.ipv6_layout.ipv6),
379 &match.mask->src, sizeof(match.mask->src));
380 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
381 src_ipv4_src_ipv6.ipv6_layout.ipv6),
382 &match.key->src, sizeof(match.key->src));
383
384 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
385 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
386 &match.mask->dst, sizeof(match.mask->dst));
387 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
388 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
389 &match.key->dst, sizeof(match.key->dst));
390 }
391
392 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
393 struct flow_match_ports match;
394
395 flow_rule_match_ports(rule, &match);
396 switch (ip_proto) {
397 case IPPROTO_TCP:
398 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
399 tcp_sport, ntohs(match.mask->src));
400 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
401 tcp_sport, ntohs(match.key->src));
402
403 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
404 tcp_dport, ntohs(match.mask->dst));
405 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
406 tcp_dport, ntohs(match.key->dst));
407 break;
408
409 case IPPROTO_UDP:
410 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
411 udp_sport, ntohs(match.mask->src));
412 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
413 udp_sport, ntohs(match.key->src));
414
415 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
416 udp_dport, ntohs(match.mask->dst));
417 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
418 udp_dport, ntohs(match.key->dst));
419 break;
420 default:
421 break;
422 }
423 }
424
425 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP)) {
426 struct flow_match_tcp match;
427
428 flow_rule_match_tcp(rule, &match);
429 MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_flags,
430 ntohs(match.mask->flags));
431 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
432 ntohs(match.key->flags));
433 }
434
435 return 0;
436 }
437
438 static void
mlx5_tc_ct_counter_put(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_ct_entry * entry)439 mlx5_tc_ct_counter_put(struct mlx5_tc_ct_priv *ct_priv, struct mlx5_ct_entry *entry)
440 {
441 if (entry->counter->is_shared &&
442 !refcount_dec_and_test(&entry->counter->refcount))
443 return;
444
445 mlx5_fc_destroy(ct_priv->dev, entry->counter->counter);
446 kfree(entry->counter);
447 }
448
449 static void
mlx5_tc_ct_entry_del_rule(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_ct_entry * entry,bool nat)450 mlx5_tc_ct_entry_del_rule(struct mlx5_tc_ct_priv *ct_priv,
451 struct mlx5_ct_entry *entry,
452 bool nat)
453 {
454 struct mlx5_ct_zone_rule *zone_rule = &entry->zone_rules[nat];
455 struct mlx5_flow_attr *attr = zone_rule->attr;
456
457 ct_dbg("Deleting ct entry rule in zone %d", entry->tuple.zone);
458
459 mlx5_tc_rule_delete(netdev_priv(ct_priv->netdev), zone_rule->rule, attr);
460 mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, zone_rule->mh);
461 mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
462 kfree(attr);
463 }
464
465 static void
mlx5_tc_ct_entry_del_rules(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_ct_entry * entry)466 mlx5_tc_ct_entry_del_rules(struct mlx5_tc_ct_priv *ct_priv,
467 struct mlx5_ct_entry *entry)
468 {
469 mlx5_tc_ct_entry_del_rule(ct_priv, entry, true);
470 mlx5_tc_ct_entry_del_rule(ct_priv, entry, false);
471 }
472
473 static struct flow_action_entry *
mlx5_tc_ct_get_ct_metadata_action(struct flow_rule * flow_rule)474 mlx5_tc_ct_get_ct_metadata_action(struct flow_rule *flow_rule)
475 {
476 struct flow_action *flow_action = &flow_rule->action;
477 struct flow_action_entry *act;
478 int i;
479
480 flow_action_for_each(i, act, flow_action) {
481 if (act->id == FLOW_ACTION_CT_METADATA)
482 return act;
483 }
484
485 return NULL;
486 }
487
488 static int
mlx5_tc_ct_entry_set_registers(struct mlx5_tc_ct_priv * ct_priv,struct mlx5e_tc_mod_hdr_acts * mod_acts,u8 ct_state,u32 mark,u32 labels_id,u8 zone_restore_id)489 mlx5_tc_ct_entry_set_registers(struct mlx5_tc_ct_priv *ct_priv,
490 struct mlx5e_tc_mod_hdr_acts *mod_acts,
491 u8 ct_state,
492 u32 mark,
493 u32 labels_id,
494 u8 zone_restore_id)
495 {
496 enum mlx5_flow_namespace_type ns = ct_priv->ns_type;
497 struct mlx5_core_dev *dev = ct_priv->dev;
498 int err;
499
500 err = mlx5e_tc_match_to_reg_set(dev, mod_acts, ns,
501 CTSTATE_TO_REG, ct_state);
502 if (err)
503 return err;
504
505 err = mlx5e_tc_match_to_reg_set(dev, mod_acts, ns,
506 MARK_TO_REG, mark);
507 if (err)
508 return err;
509
510 err = mlx5e_tc_match_to_reg_set(dev, mod_acts, ns,
511 LABELS_TO_REG, labels_id);
512 if (err)
513 return err;
514
515 err = mlx5e_tc_match_to_reg_set(dev, mod_acts, ns,
516 ZONE_RESTORE_TO_REG, zone_restore_id);
517 if (err)
518 return err;
519
520 /* Make another copy of zone id in reg_b for
521 * NIC rx flows since we don't copy reg_c1 to
522 * reg_b upon miss.
523 */
524 if (ns != MLX5_FLOW_NAMESPACE_FDB) {
525 err = mlx5e_tc_match_to_reg_set(dev, mod_acts, ns,
526 NIC_ZONE_RESTORE_TO_REG, zone_restore_id);
527 if (err)
528 return err;
529 }
530 return 0;
531 }
532
533 static int
mlx5_tc_ct_parse_mangle_to_mod_act(struct flow_action_entry * act,char * modact)534 mlx5_tc_ct_parse_mangle_to_mod_act(struct flow_action_entry *act,
535 char *modact)
536 {
537 u32 offset = act->mangle.offset, field;
538
539 switch (act->mangle.htype) {
540 case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
541 MLX5_SET(set_action_in, modact, length, 0);
542 if (offset == offsetof(struct iphdr, saddr))
543 field = MLX5_ACTION_IN_FIELD_OUT_SIPV4;
544 else if (offset == offsetof(struct iphdr, daddr))
545 field = MLX5_ACTION_IN_FIELD_OUT_DIPV4;
546 else
547 return -EOPNOTSUPP;
548 break;
549
550 case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
551 MLX5_SET(set_action_in, modact, length, 0);
552 if (offset == offsetof(struct ipv6hdr, saddr) + 12)
553 field = MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0;
554 else if (offset == offsetof(struct ipv6hdr, saddr) + 8)
555 field = MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32;
556 else if (offset == offsetof(struct ipv6hdr, saddr) + 4)
557 field = MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64;
558 else if (offset == offsetof(struct ipv6hdr, saddr))
559 field = MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96;
560 else if (offset == offsetof(struct ipv6hdr, daddr) + 12)
561 field = MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0;
562 else if (offset == offsetof(struct ipv6hdr, daddr) + 8)
563 field = MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32;
564 else if (offset == offsetof(struct ipv6hdr, daddr) + 4)
565 field = MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64;
566 else if (offset == offsetof(struct ipv6hdr, daddr))
567 field = MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96;
568 else
569 return -EOPNOTSUPP;
570 break;
571
572 case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
573 MLX5_SET(set_action_in, modact, length, 16);
574 if (offset == offsetof(struct tcphdr, source))
575 field = MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT;
576 else if (offset == offsetof(struct tcphdr, dest))
577 field = MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT;
578 else
579 return -EOPNOTSUPP;
580 break;
581
582 case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
583 MLX5_SET(set_action_in, modact, length, 16);
584 if (offset == offsetof(struct udphdr, source))
585 field = MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT;
586 else if (offset == offsetof(struct udphdr, dest))
587 field = MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT;
588 else
589 return -EOPNOTSUPP;
590 break;
591
592 default:
593 return -EOPNOTSUPP;
594 }
595
596 MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
597 MLX5_SET(set_action_in, modact, offset, 0);
598 MLX5_SET(set_action_in, modact, field, field);
599 MLX5_SET(set_action_in, modact, data, act->mangle.val);
600
601 return 0;
602 }
603
604 static int
mlx5_tc_ct_entry_create_nat(struct mlx5_tc_ct_priv * ct_priv,struct flow_rule * flow_rule,struct mlx5e_tc_mod_hdr_acts * mod_acts)605 mlx5_tc_ct_entry_create_nat(struct mlx5_tc_ct_priv *ct_priv,
606 struct flow_rule *flow_rule,
607 struct mlx5e_tc_mod_hdr_acts *mod_acts)
608 {
609 struct flow_action *flow_action = &flow_rule->action;
610 struct mlx5_core_dev *mdev = ct_priv->dev;
611 struct flow_action_entry *act;
612 char *modact;
613 int err, i;
614
615 flow_action_for_each(i, act, flow_action) {
616 switch (act->id) {
617 case FLOW_ACTION_MANGLE: {
618 modact = mlx5e_mod_hdr_alloc(mdev, ct_priv->ns_type, mod_acts);
619 if (IS_ERR(modact))
620 return PTR_ERR(modact);
621
622 err = mlx5_tc_ct_parse_mangle_to_mod_act(act, modact);
623 if (err)
624 return err;
625
626 mod_acts->num_actions++;
627 }
628 break;
629
630 case FLOW_ACTION_CT_METADATA:
631 /* Handled earlier */
632 continue;
633 default:
634 return -EOPNOTSUPP;
635 }
636 }
637
638 return 0;
639 }
640
641 static int
mlx5_tc_ct_entry_create_mod_hdr(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_flow_attr * attr,struct flow_rule * flow_rule,struct mlx5e_mod_hdr_handle ** mh,u8 zone_restore_id,bool nat_table,bool has_nat)642 mlx5_tc_ct_entry_create_mod_hdr(struct mlx5_tc_ct_priv *ct_priv,
643 struct mlx5_flow_attr *attr,
644 struct flow_rule *flow_rule,
645 struct mlx5e_mod_hdr_handle **mh,
646 u8 zone_restore_id, bool nat_table, bool has_nat)
647 {
648 struct mlx5e_tc_mod_hdr_acts mod_acts = {};
649 struct flow_action_entry *meta;
650 u16 ct_state = 0;
651 int err;
652
653 meta = mlx5_tc_ct_get_ct_metadata_action(flow_rule);
654 if (!meta)
655 return -EOPNOTSUPP;
656
657 err = mlx5_get_label_mapping(ct_priv, meta->ct_metadata.labels,
658 &attr->ct_attr.ct_labels_id);
659 if (err)
660 return -EOPNOTSUPP;
661 if (nat_table) {
662 if (has_nat) {
663 err = mlx5_tc_ct_entry_create_nat(ct_priv, flow_rule, &mod_acts);
664 if (err)
665 goto err_mapping;
666 }
667
668 ct_state |= MLX5_CT_STATE_NAT_BIT;
669 }
670
671 ct_state |= MLX5_CT_STATE_ESTABLISHED_BIT | MLX5_CT_STATE_TRK_BIT;
672 ct_state |= meta->ct_metadata.orig_dir ? 0 : MLX5_CT_STATE_REPLY_BIT;
673 err = mlx5_tc_ct_entry_set_registers(ct_priv, &mod_acts,
674 ct_state,
675 meta->ct_metadata.mark,
676 attr->ct_attr.ct_labels_id,
677 zone_restore_id);
678 if (err)
679 goto err_mapping;
680
681 if (nat_table && has_nat) {
682 attr->modify_hdr = mlx5_modify_header_alloc(ct_priv->dev, ct_priv->ns_type,
683 mod_acts.num_actions,
684 mod_acts.actions);
685 if (IS_ERR(attr->modify_hdr)) {
686 err = PTR_ERR(attr->modify_hdr);
687 goto err_mapping;
688 }
689
690 *mh = NULL;
691 } else {
692 *mh = mlx5e_mod_hdr_attach(ct_priv->dev,
693 ct_priv->mod_hdr_tbl,
694 ct_priv->ns_type,
695 &mod_acts);
696 if (IS_ERR(*mh)) {
697 err = PTR_ERR(*mh);
698 goto err_mapping;
699 }
700 attr->modify_hdr = mlx5e_mod_hdr_get(*mh);
701 }
702
703 mlx5e_mod_hdr_dealloc(&mod_acts);
704 return 0;
705
706 err_mapping:
707 mlx5e_mod_hdr_dealloc(&mod_acts);
708 mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
709 return err;
710 }
711
712 static void
mlx5_tc_ct_entry_destroy_mod_hdr(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_flow_attr * attr,struct mlx5e_mod_hdr_handle * mh)713 mlx5_tc_ct_entry_destroy_mod_hdr(struct mlx5_tc_ct_priv *ct_priv,
714 struct mlx5_flow_attr *attr,
715 struct mlx5e_mod_hdr_handle *mh)
716 {
717 if (mh)
718 mlx5e_mod_hdr_detach(ct_priv->dev, ct_priv->mod_hdr_tbl, mh);
719 else
720 mlx5_modify_header_dealloc(ct_priv->dev, attr->modify_hdr);
721 }
722
723 static int
mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv * ct_priv,struct flow_rule * flow_rule,struct mlx5_ct_entry * entry,bool nat,u8 zone_restore_id)724 mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
725 struct flow_rule *flow_rule,
726 struct mlx5_ct_entry *entry,
727 bool nat, u8 zone_restore_id)
728 {
729 struct mlx5_ct_zone_rule *zone_rule = &entry->zone_rules[nat];
730 struct mlx5e_priv *priv = netdev_priv(ct_priv->netdev);
731 struct mlx5_flow_spec *spec = NULL;
732 struct mlx5_flow_attr *attr;
733 int err;
734
735 zone_rule->nat = nat;
736
737 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
738 if (!spec)
739 return -ENOMEM;
740
741 attr = mlx5_alloc_flow_attr(ct_priv->ns_type);
742 if (!attr) {
743 err = -ENOMEM;
744 goto err_attr;
745 }
746
747 err = mlx5_tc_ct_entry_create_mod_hdr(ct_priv, attr, flow_rule,
748 &zone_rule->mh,
749 zone_restore_id,
750 nat,
751 mlx5_tc_ct_entry_has_nat(entry));
752 if (err) {
753 ct_dbg("Failed to create ct entry mod hdr");
754 goto err_mod_hdr;
755 }
756
757 attr->action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
758 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
759 MLX5_FLOW_CONTEXT_ACTION_COUNT;
760 attr->dest_chain = 0;
761 attr->dest_ft = mlx5e_tc_post_act_get_ft(ct_priv->post_act);
762 attr->ft = nat ? ct_priv->ct_nat : ct_priv->ct;
763 attr->outer_match_level = MLX5_MATCH_L4;
764 attr->counter = entry->counter->counter;
765 attr->flags |= MLX5_ESW_ATTR_FLAG_NO_IN_PORT;
766 if (ct_priv->ns_type == MLX5_FLOW_NAMESPACE_FDB)
767 attr->esw_attr->in_mdev = priv->mdev;
768
769 mlx5_tc_ct_set_tuple_match(netdev_priv(ct_priv->netdev), spec, flow_rule);
770 mlx5e_tc_match_to_reg_match(spec, ZONE_TO_REG, entry->tuple.zone, MLX5_CT_ZONE_MASK);
771
772 zone_rule->rule = mlx5_tc_rule_insert(priv, spec, attr);
773 if (IS_ERR(zone_rule->rule)) {
774 err = PTR_ERR(zone_rule->rule);
775 ct_dbg("Failed to add ct entry rule, nat: %d", nat);
776 goto err_rule;
777 }
778
779 zone_rule->attr = attr;
780
781 kvfree(spec);
782 ct_dbg("Offloaded ct entry rule in zone %d", entry->tuple.zone);
783
784 return 0;
785
786 err_rule:
787 mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, zone_rule->mh);
788 mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
789 err_mod_hdr:
790 kfree(attr);
791 err_attr:
792 kvfree(spec);
793 return err;
794 }
795
796 static bool
mlx5_tc_ct_entry_valid(struct mlx5_ct_entry * entry)797 mlx5_tc_ct_entry_valid(struct mlx5_ct_entry *entry)
798 {
799 return test_bit(MLX5_CT_ENTRY_FLAG_VALID, &entry->flags);
800 }
801
802 static struct mlx5_ct_entry *
mlx5_tc_ct_entry_get(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_ct_tuple * tuple)803 mlx5_tc_ct_entry_get(struct mlx5_tc_ct_priv *ct_priv, struct mlx5_ct_tuple *tuple)
804 {
805 struct mlx5_ct_entry *entry;
806
807 entry = rhashtable_lookup_fast(&ct_priv->ct_tuples_ht, tuple,
808 tuples_ht_params);
809 if (entry && mlx5_tc_ct_entry_valid(entry) &&
810 refcount_inc_not_zero(&entry->refcnt)) {
811 return entry;
812 } else if (!entry) {
813 entry = rhashtable_lookup_fast(&ct_priv->ct_tuples_nat_ht,
814 tuple, tuples_nat_ht_params);
815 if (entry && mlx5_tc_ct_entry_valid(entry) &&
816 refcount_inc_not_zero(&entry->refcnt))
817 return entry;
818 }
819
820 return entry ? ERR_PTR(-EINVAL) : NULL;
821 }
822
mlx5_tc_ct_entry_remove_from_tuples(struct mlx5_ct_entry * entry)823 static void mlx5_tc_ct_entry_remove_from_tuples(struct mlx5_ct_entry *entry)
824 {
825 struct mlx5_tc_ct_priv *ct_priv = entry->ct_priv;
826
827 rhashtable_remove_fast(&ct_priv->ct_tuples_nat_ht,
828 &entry->tuple_nat_node,
829 tuples_nat_ht_params);
830 rhashtable_remove_fast(&ct_priv->ct_tuples_ht, &entry->tuple_node,
831 tuples_ht_params);
832 }
833
mlx5_tc_ct_entry_del(struct mlx5_ct_entry * entry)834 static void mlx5_tc_ct_entry_del(struct mlx5_ct_entry *entry)
835 {
836 struct mlx5_tc_ct_priv *ct_priv = entry->ct_priv;
837
838 mlx5_tc_ct_entry_del_rules(ct_priv, entry);
839
840 spin_lock_bh(&ct_priv->ht_lock);
841 mlx5_tc_ct_entry_remove_from_tuples(entry);
842 spin_unlock_bh(&ct_priv->ht_lock);
843
844 mlx5_tc_ct_counter_put(ct_priv, entry);
845 kfree(entry);
846 }
847
848 static void
mlx5_tc_ct_entry_put(struct mlx5_ct_entry * entry)849 mlx5_tc_ct_entry_put(struct mlx5_ct_entry *entry)
850 {
851 if (!refcount_dec_and_test(&entry->refcnt))
852 return;
853
854 mlx5_tc_ct_entry_del(entry);
855 }
856
mlx5_tc_ct_entry_del_work(struct work_struct * work)857 static void mlx5_tc_ct_entry_del_work(struct work_struct *work)
858 {
859 struct mlx5_ct_entry *entry = container_of(work, struct mlx5_ct_entry, work);
860
861 mlx5_tc_ct_entry_del(entry);
862 }
863
864 static void
__mlx5_tc_ct_entry_put(struct mlx5_ct_entry * entry)865 __mlx5_tc_ct_entry_put(struct mlx5_ct_entry *entry)
866 {
867 struct mlx5e_priv *priv;
868
869 if (!refcount_dec_and_test(&entry->refcnt))
870 return;
871
872 priv = netdev_priv(entry->ct_priv->netdev);
873 INIT_WORK(&entry->work, mlx5_tc_ct_entry_del_work);
874 queue_work(priv->wq, &entry->work);
875 }
876
877 static struct mlx5_ct_counter *
mlx5_tc_ct_counter_create(struct mlx5_tc_ct_priv * ct_priv)878 mlx5_tc_ct_counter_create(struct mlx5_tc_ct_priv *ct_priv)
879 {
880 struct mlx5_ct_counter *counter;
881 int ret;
882
883 counter = kzalloc(sizeof(*counter), GFP_KERNEL);
884 if (!counter)
885 return ERR_PTR(-ENOMEM);
886
887 counter->is_shared = false;
888 counter->counter = mlx5_fc_create(ct_priv->dev, true);
889 if (IS_ERR(counter->counter)) {
890 ct_dbg("Failed to create counter for ct entry");
891 ret = PTR_ERR(counter->counter);
892 kfree(counter);
893 return ERR_PTR(ret);
894 }
895
896 return counter;
897 }
898
899 static struct mlx5_ct_counter *
mlx5_tc_ct_shared_counter_get(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_ct_entry * entry)900 mlx5_tc_ct_shared_counter_get(struct mlx5_tc_ct_priv *ct_priv,
901 struct mlx5_ct_entry *entry)
902 {
903 struct mlx5_ct_tuple rev_tuple = entry->tuple;
904 struct mlx5_ct_counter *shared_counter;
905 struct mlx5_ct_entry *rev_entry;
906 __be16 tmp_port;
907
908 /* get the reversed tuple */
909 tmp_port = rev_tuple.port.src;
910 rev_tuple.port.src = rev_tuple.port.dst;
911 rev_tuple.port.dst = tmp_port;
912
913 if (rev_tuple.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
914 __be32 tmp_addr = rev_tuple.ip.src_v4;
915
916 rev_tuple.ip.src_v4 = rev_tuple.ip.dst_v4;
917 rev_tuple.ip.dst_v4 = tmp_addr;
918 } else if (rev_tuple.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
919 struct in6_addr tmp_addr = rev_tuple.ip.src_v6;
920
921 rev_tuple.ip.src_v6 = rev_tuple.ip.dst_v6;
922 rev_tuple.ip.dst_v6 = tmp_addr;
923 } else {
924 return ERR_PTR(-EOPNOTSUPP);
925 }
926
927 /* Use the same counter as the reverse direction */
928 spin_lock_bh(&ct_priv->ht_lock);
929 rev_entry = mlx5_tc_ct_entry_get(ct_priv, &rev_tuple);
930
931 if (IS_ERR(rev_entry)) {
932 spin_unlock_bh(&ct_priv->ht_lock);
933 goto create_counter;
934 }
935
936 if (rev_entry && refcount_inc_not_zero(&rev_entry->counter->refcount)) {
937 ct_dbg("Using shared counter entry=0x%p rev=0x%p", entry, rev_entry);
938 shared_counter = rev_entry->counter;
939 spin_unlock_bh(&ct_priv->ht_lock);
940
941 mlx5_tc_ct_entry_put(rev_entry);
942 return shared_counter;
943 }
944
945 spin_unlock_bh(&ct_priv->ht_lock);
946
947 create_counter:
948
949 shared_counter = mlx5_tc_ct_counter_create(ct_priv);
950 if (IS_ERR(shared_counter))
951 return shared_counter;
952
953 shared_counter->is_shared = true;
954 refcount_set(&shared_counter->refcount, 1);
955 return shared_counter;
956 }
957
958 static int
mlx5_tc_ct_entry_add_rules(struct mlx5_tc_ct_priv * ct_priv,struct flow_rule * flow_rule,struct mlx5_ct_entry * entry,u8 zone_restore_id)959 mlx5_tc_ct_entry_add_rules(struct mlx5_tc_ct_priv *ct_priv,
960 struct flow_rule *flow_rule,
961 struct mlx5_ct_entry *entry,
962 u8 zone_restore_id)
963 {
964 int err;
965
966 if (nf_ct_acct_enabled(dev_net(ct_priv->netdev)))
967 entry->counter = mlx5_tc_ct_counter_create(ct_priv);
968 else
969 entry->counter = mlx5_tc_ct_shared_counter_get(ct_priv, entry);
970
971 if (IS_ERR(entry->counter)) {
972 err = PTR_ERR(entry->counter);
973 return err;
974 }
975
976 err = mlx5_tc_ct_entry_add_rule(ct_priv, flow_rule, entry, false,
977 zone_restore_id);
978 if (err)
979 goto err_orig;
980
981 err = mlx5_tc_ct_entry_add_rule(ct_priv, flow_rule, entry, true,
982 zone_restore_id);
983 if (err)
984 goto err_nat;
985
986 return 0;
987
988 err_nat:
989 mlx5_tc_ct_entry_del_rule(ct_priv, entry, false);
990 err_orig:
991 mlx5_tc_ct_counter_put(ct_priv, entry);
992 return err;
993 }
994
995 static int
mlx5_tc_ct_block_flow_offload_add(struct mlx5_ct_ft * ft,struct flow_cls_offload * flow)996 mlx5_tc_ct_block_flow_offload_add(struct mlx5_ct_ft *ft,
997 struct flow_cls_offload *flow)
998 {
999 struct flow_rule *flow_rule = flow_cls_offload_flow_rule(flow);
1000 struct mlx5_tc_ct_priv *ct_priv = ft->ct_priv;
1001 struct flow_action_entry *meta_action;
1002 unsigned long cookie = flow->cookie;
1003 struct mlx5_ct_entry *entry;
1004 int err;
1005
1006 meta_action = mlx5_tc_ct_get_ct_metadata_action(flow_rule);
1007 if (!meta_action)
1008 return -EOPNOTSUPP;
1009
1010 spin_lock_bh(&ct_priv->ht_lock);
1011 entry = rhashtable_lookup_fast(&ft->ct_entries_ht, &cookie, cts_ht_params);
1012 if (entry && refcount_inc_not_zero(&entry->refcnt)) {
1013 spin_unlock_bh(&ct_priv->ht_lock);
1014 mlx5_tc_ct_entry_put(entry);
1015 return -EEXIST;
1016 }
1017 spin_unlock_bh(&ct_priv->ht_lock);
1018
1019 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1020 if (!entry)
1021 return -ENOMEM;
1022
1023 entry->tuple.zone = ft->zone;
1024 entry->cookie = flow->cookie;
1025 entry->restore_cookie = meta_action->ct_metadata.cookie;
1026 refcount_set(&entry->refcnt, 2);
1027 entry->ct_priv = ct_priv;
1028
1029 err = mlx5_tc_ct_rule_to_tuple(&entry->tuple, flow_rule);
1030 if (err)
1031 goto err_set;
1032
1033 memcpy(&entry->tuple_nat, &entry->tuple, sizeof(entry->tuple));
1034 err = mlx5_tc_ct_rule_to_tuple_nat(&entry->tuple_nat, flow_rule);
1035 if (err)
1036 goto err_set;
1037
1038 spin_lock_bh(&ct_priv->ht_lock);
1039
1040 err = rhashtable_lookup_insert_fast(&ft->ct_entries_ht, &entry->node,
1041 cts_ht_params);
1042 if (err)
1043 goto err_entries;
1044
1045 err = rhashtable_lookup_insert_fast(&ct_priv->ct_tuples_ht,
1046 &entry->tuple_node,
1047 tuples_ht_params);
1048 if (err)
1049 goto err_tuple;
1050
1051 if (memcmp(&entry->tuple, &entry->tuple_nat, sizeof(entry->tuple))) {
1052 err = rhashtable_lookup_insert_fast(&ct_priv->ct_tuples_nat_ht,
1053 &entry->tuple_nat_node,
1054 tuples_nat_ht_params);
1055 if (err)
1056 goto err_tuple_nat;
1057 }
1058 spin_unlock_bh(&ct_priv->ht_lock);
1059
1060 err = mlx5_tc_ct_entry_add_rules(ct_priv, flow_rule, entry,
1061 ft->zone_restore_id);
1062 if (err)
1063 goto err_rules;
1064
1065 set_bit(MLX5_CT_ENTRY_FLAG_VALID, &entry->flags);
1066 mlx5_tc_ct_entry_put(entry); /* this function reference */
1067
1068 return 0;
1069
1070 err_rules:
1071 spin_lock_bh(&ct_priv->ht_lock);
1072 if (mlx5_tc_ct_entry_has_nat(entry))
1073 rhashtable_remove_fast(&ct_priv->ct_tuples_nat_ht,
1074 &entry->tuple_nat_node, tuples_nat_ht_params);
1075 err_tuple_nat:
1076 rhashtable_remove_fast(&ct_priv->ct_tuples_ht,
1077 &entry->tuple_node,
1078 tuples_ht_params);
1079 err_tuple:
1080 rhashtable_remove_fast(&ft->ct_entries_ht,
1081 &entry->node,
1082 cts_ht_params);
1083 err_entries:
1084 spin_unlock_bh(&ct_priv->ht_lock);
1085 err_set:
1086 kfree(entry);
1087 if (err != -EEXIST)
1088 netdev_warn(ct_priv->netdev, "Failed to offload ct entry, err: %d\n", err);
1089 return err;
1090 }
1091
1092 static int
mlx5_tc_ct_block_flow_offload_del(struct mlx5_ct_ft * ft,struct flow_cls_offload * flow)1093 mlx5_tc_ct_block_flow_offload_del(struct mlx5_ct_ft *ft,
1094 struct flow_cls_offload *flow)
1095 {
1096 struct mlx5_tc_ct_priv *ct_priv = ft->ct_priv;
1097 unsigned long cookie = flow->cookie;
1098 struct mlx5_ct_entry *entry;
1099
1100 spin_lock_bh(&ct_priv->ht_lock);
1101 entry = rhashtable_lookup_fast(&ft->ct_entries_ht, &cookie, cts_ht_params);
1102 if (!entry) {
1103 spin_unlock_bh(&ct_priv->ht_lock);
1104 return -ENOENT;
1105 }
1106
1107 if (!mlx5_tc_ct_entry_valid(entry)) {
1108 spin_unlock_bh(&ct_priv->ht_lock);
1109 return -EINVAL;
1110 }
1111
1112 rhashtable_remove_fast(&ft->ct_entries_ht, &entry->node, cts_ht_params);
1113 mlx5_tc_ct_entry_remove_from_tuples(entry);
1114 spin_unlock_bh(&ct_priv->ht_lock);
1115
1116 mlx5_tc_ct_entry_put(entry);
1117
1118 return 0;
1119 }
1120
1121 static int
mlx5_tc_ct_block_flow_offload_stats(struct mlx5_ct_ft * ft,struct flow_cls_offload * f)1122 mlx5_tc_ct_block_flow_offload_stats(struct mlx5_ct_ft *ft,
1123 struct flow_cls_offload *f)
1124 {
1125 struct mlx5_tc_ct_priv *ct_priv = ft->ct_priv;
1126 unsigned long cookie = f->cookie;
1127 struct mlx5_ct_entry *entry;
1128 u64 lastuse, packets, bytes;
1129
1130 spin_lock_bh(&ct_priv->ht_lock);
1131 entry = rhashtable_lookup_fast(&ft->ct_entries_ht, &cookie, cts_ht_params);
1132 if (!entry) {
1133 spin_unlock_bh(&ct_priv->ht_lock);
1134 return -ENOENT;
1135 }
1136
1137 if (!mlx5_tc_ct_entry_valid(entry) || !refcount_inc_not_zero(&entry->refcnt)) {
1138 spin_unlock_bh(&ct_priv->ht_lock);
1139 return -EINVAL;
1140 }
1141
1142 spin_unlock_bh(&ct_priv->ht_lock);
1143
1144 mlx5_fc_query_cached(entry->counter->counter, &bytes, &packets, &lastuse);
1145 flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
1146 FLOW_ACTION_HW_STATS_DELAYED);
1147
1148 mlx5_tc_ct_entry_put(entry);
1149 return 0;
1150 }
1151
1152 static int
mlx5_tc_ct_block_flow_offload(enum tc_setup_type type,void * type_data,void * cb_priv)1153 mlx5_tc_ct_block_flow_offload(enum tc_setup_type type, void *type_data,
1154 void *cb_priv)
1155 {
1156 struct flow_cls_offload *f = type_data;
1157 struct mlx5_ct_ft *ft = cb_priv;
1158
1159 if (type != TC_SETUP_CLSFLOWER)
1160 return -EOPNOTSUPP;
1161
1162 switch (f->command) {
1163 case FLOW_CLS_REPLACE:
1164 return mlx5_tc_ct_block_flow_offload_add(ft, f);
1165 case FLOW_CLS_DESTROY:
1166 return mlx5_tc_ct_block_flow_offload_del(ft, f);
1167 case FLOW_CLS_STATS:
1168 return mlx5_tc_ct_block_flow_offload_stats(ft, f);
1169 default:
1170 break;
1171 }
1172
1173 return -EOPNOTSUPP;
1174 }
1175
1176 static bool
mlx5_tc_ct_skb_to_tuple(struct sk_buff * skb,struct mlx5_ct_tuple * tuple,u16 zone)1177 mlx5_tc_ct_skb_to_tuple(struct sk_buff *skb, struct mlx5_ct_tuple *tuple,
1178 u16 zone)
1179 {
1180 struct flow_keys flow_keys;
1181
1182 skb_reset_network_header(skb);
1183 skb_flow_dissect_flow_keys(skb, &flow_keys, 0);
1184
1185 tuple->zone = zone;
1186
1187 if (flow_keys.basic.ip_proto != IPPROTO_TCP &&
1188 flow_keys.basic.ip_proto != IPPROTO_UDP)
1189 return false;
1190
1191 tuple->port.src = flow_keys.ports.src;
1192 tuple->port.dst = flow_keys.ports.dst;
1193 tuple->n_proto = flow_keys.basic.n_proto;
1194 tuple->ip_proto = flow_keys.basic.ip_proto;
1195
1196 switch (flow_keys.basic.n_proto) {
1197 case htons(ETH_P_IP):
1198 tuple->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1199 tuple->ip.src_v4 = flow_keys.addrs.v4addrs.src;
1200 tuple->ip.dst_v4 = flow_keys.addrs.v4addrs.dst;
1201 break;
1202
1203 case htons(ETH_P_IPV6):
1204 tuple->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1205 tuple->ip.src_v6 = flow_keys.addrs.v6addrs.src;
1206 tuple->ip.dst_v6 = flow_keys.addrs.v6addrs.dst;
1207 break;
1208 default:
1209 goto out;
1210 }
1211
1212 return true;
1213
1214 out:
1215 return false;
1216 }
1217
mlx5_tc_ct_add_no_trk_match(struct mlx5_flow_spec * spec)1218 int mlx5_tc_ct_add_no_trk_match(struct mlx5_flow_spec *spec)
1219 {
1220 u32 ctstate = 0, ctstate_mask = 0;
1221
1222 mlx5e_tc_match_to_reg_get_match(spec, CTSTATE_TO_REG,
1223 &ctstate, &ctstate_mask);
1224
1225 if ((ctstate & ctstate_mask) == MLX5_CT_STATE_TRK_BIT)
1226 return -EOPNOTSUPP;
1227
1228 ctstate_mask |= MLX5_CT_STATE_TRK_BIT;
1229 mlx5e_tc_match_to_reg_match(spec, CTSTATE_TO_REG,
1230 ctstate, ctstate_mask);
1231
1232 return 0;
1233 }
1234
mlx5_tc_ct_match_del(struct mlx5_tc_ct_priv * priv,struct mlx5_ct_attr * ct_attr)1235 void mlx5_tc_ct_match_del(struct mlx5_tc_ct_priv *priv, struct mlx5_ct_attr *ct_attr)
1236 {
1237 if (!priv || !ct_attr->ct_labels_id)
1238 return;
1239
1240 mlx5_put_label_mapping(priv, ct_attr->ct_labels_id);
1241 }
1242
1243 int
mlx5_tc_ct_match_add(struct mlx5_tc_ct_priv * priv,struct mlx5_flow_spec * spec,struct flow_cls_offload * f,struct mlx5_ct_attr * ct_attr,struct netlink_ext_ack * extack)1244 mlx5_tc_ct_match_add(struct mlx5_tc_ct_priv *priv,
1245 struct mlx5_flow_spec *spec,
1246 struct flow_cls_offload *f,
1247 struct mlx5_ct_attr *ct_attr,
1248 struct netlink_ext_ack *extack)
1249 {
1250 bool trk, est, untrk, unest, new, rpl, unrpl, rel, unrel, inv, uninv;
1251 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
1252 struct flow_dissector_key_ct *mask, *key;
1253 u32 ctstate = 0, ctstate_mask = 0;
1254 u16 ct_state_on, ct_state_off;
1255 u16 ct_state, ct_state_mask;
1256 struct flow_match_ct match;
1257 u32 ct_labels[4];
1258
1259 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CT))
1260 return 0;
1261
1262 if (!priv) {
1263 NL_SET_ERR_MSG_MOD(extack,
1264 "offload of ct matching isn't available");
1265 return -EOPNOTSUPP;
1266 }
1267
1268 flow_rule_match_ct(rule, &match);
1269
1270 key = match.key;
1271 mask = match.mask;
1272
1273 ct_state = key->ct_state;
1274 ct_state_mask = mask->ct_state;
1275
1276 if (ct_state_mask & ~(TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
1277 TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED |
1278 TCA_FLOWER_KEY_CT_FLAGS_NEW |
1279 TCA_FLOWER_KEY_CT_FLAGS_REPLY |
1280 TCA_FLOWER_KEY_CT_FLAGS_RELATED |
1281 TCA_FLOWER_KEY_CT_FLAGS_INVALID)) {
1282 NL_SET_ERR_MSG_MOD(extack,
1283 "only ct_state trk, est, new and rpl are supported for offload");
1284 return -EOPNOTSUPP;
1285 }
1286
1287 ct_state_on = ct_state & ct_state_mask;
1288 ct_state_off = (ct_state & ct_state_mask) ^ ct_state_mask;
1289 trk = ct_state_on & TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
1290 new = ct_state_on & TCA_FLOWER_KEY_CT_FLAGS_NEW;
1291 est = ct_state_on & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED;
1292 rpl = ct_state_on & TCA_FLOWER_KEY_CT_FLAGS_REPLY;
1293 rel = ct_state_on & TCA_FLOWER_KEY_CT_FLAGS_RELATED;
1294 inv = ct_state_on & TCA_FLOWER_KEY_CT_FLAGS_INVALID;
1295 untrk = ct_state_off & TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
1296 unest = ct_state_off & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED;
1297 unrpl = ct_state_off & TCA_FLOWER_KEY_CT_FLAGS_REPLY;
1298 unrel = ct_state_off & TCA_FLOWER_KEY_CT_FLAGS_RELATED;
1299 uninv = ct_state_off & TCA_FLOWER_KEY_CT_FLAGS_INVALID;
1300
1301 ctstate |= trk ? MLX5_CT_STATE_TRK_BIT : 0;
1302 ctstate |= est ? MLX5_CT_STATE_ESTABLISHED_BIT : 0;
1303 ctstate |= rpl ? MLX5_CT_STATE_REPLY_BIT : 0;
1304 ctstate_mask |= (untrk || trk) ? MLX5_CT_STATE_TRK_BIT : 0;
1305 ctstate_mask |= (unest || est) ? MLX5_CT_STATE_ESTABLISHED_BIT : 0;
1306 ctstate_mask |= (unrpl || rpl) ? MLX5_CT_STATE_REPLY_BIT : 0;
1307 ctstate_mask |= unrel ? MLX5_CT_STATE_RELATED_BIT : 0;
1308 ctstate_mask |= uninv ? MLX5_CT_STATE_INVALID_BIT : 0;
1309
1310 if (rel) {
1311 NL_SET_ERR_MSG_MOD(extack,
1312 "matching on ct_state +rel isn't supported");
1313 return -EOPNOTSUPP;
1314 }
1315
1316 if (inv) {
1317 NL_SET_ERR_MSG_MOD(extack,
1318 "matching on ct_state +inv isn't supported");
1319 return -EOPNOTSUPP;
1320 }
1321
1322 if (new) {
1323 NL_SET_ERR_MSG_MOD(extack,
1324 "matching on ct_state +new isn't supported");
1325 return -EOPNOTSUPP;
1326 }
1327
1328 if (mask->ct_zone)
1329 mlx5e_tc_match_to_reg_match(spec, ZONE_TO_REG,
1330 key->ct_zone, MLX5_CT_ZONE_MASK);
1331 if (ctstate_mask)
1332 mlx5e_tc_match_to_reg_match(spec, CTSTATE_TO_REG,
1333 ctstate, ctstate_mask);
1334 if (mask->ct_mark)
1335 mlx5e_tc_match_to_reg_match(spec, MARK_TO_REG,
1336 key->ct_mark, mask->ct_mark);
1337 if (mask->ct_labels[0] || mask->ct_labels[1] || mask->ct_labels[2] ||
1338 mask->ct_labels[3]) {
1339 ct_labels[0] = key->ct_labels[0] & mask->ct_labels[0];
1340 ct_labels[1] = key->ct_labels[1] & mask->ct_labels[1];
1341 ct_labels[2] = key->ct_labels[2] & mask->ct_labels[2];
1342 ct_labels[3] = key->ct_labels[3] & mask->ct_labels[3];
1343 if (mlx5_get_label_mapping(priv, ct_labels, &ct_attr->ct_labels_id))
1344 return -EOPNOTSUPP;
1345 mlx5e_tc_match_to_reg_match(spec, LABELS_TO_REG, ct_attr->ct_labels_id,
1346 MLX5_CT_LABELS_MASK);
1347 }
1348
1349 return 0;
1350 }
1351
1352 int
mlx5_tc_ct_parse_action(struct mlx5_tc_ct_priv * priv,struct mlx5_flow_attr * attr,struct mlx5e_tc_mod_hdr_acts * mod_acts,const struct flow_action_entry * act,struct netlink_ext_ack * extack)1353 mlx5_tc_ct_parse_action(struct mlx5_tc_ct_priv *priv,
1354 struct mlx5_flow_attr *attr,
1355 struct mlx5e_tc_mod_hdr_acts *mod_acts,
1356 const struct flow_action_entry *act,
1357 struct netlink_ext_ack *extack)
1358 {
1359 bool clear_action = act->ct.action & TCA_CT_ACT_CLEAR;
1360 int err;
1361
1362 if (!priv) {
1363 NL_SET_ERR_MSG_MOD(extack,
1364 "offload of ct action isn't available");
1365 return -EOPNOTSUPP;
1366 }
1367
1368 attr->ct_attr.zone = act->ct.zone;
1369 attr->ct_attr.ct_action = act->ct.action;
1370 attr->ct_attr.nf_ft = act->ct.flow_table;
1371
1372 if (!clear_action)
1373 goto out;
1374
1375 err = mlx5_tc_ct_entry_set_registers(priv, mod_acts, 0, 0, 0, 0);
1376 if (err) {
1377 NL_SET_ERR_MSG_MOD(extack, "Failed to set registers for ct clear");
1378 return err;
1379 }
1380 attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1381
1382 out:
1383 return 0;
1384 }
1385
tc_ct_pre_ct_add_rules(struct mlx5_ct_ft * ct_ft,struct mlx5_tc_ct_pre * pre_ct,bool nat)1386 static int tc_ct_pre_ct_add_rules(struct mlx5_ct_ft *ct_ft,
1387 struct mlx5_tc_ct_pre *pre_ct,
1388 bool nat)
1389 {
1390 struct mlx5_tc_ct_priv *ct_priv = ct_ft->ct_priv;
1391 struct mlx5e_tc_mod_hdr_acts pre_mod_acts = {};
1392 struct mlx5_core_dev *dev = ct_priv->dev;
1393 struct mlx5_flow_table *ft = pre_ct->ft;
1394 struct mlx5_flow_destination dest = {};
1395 struct mlx5_flow_act flow_act = {};
1396 struct mlx5_modify_hdr *mod_hdr;
1397 struct mlx5_flow_handle *rule;
1398 struct mlx5_flow_spec *spec;
1399 u32 ctstate;
1400 u16 zone;
1401 int err;
1402
1403 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1404 if (!spec)
1405 return -ENOMEM;
1406
1407 zone = ct_ft->zone & MLX5_CT_ZONE_MASK;
1408 err = mlx5e_tc_match_to_reg_set(dev, &pre_mod_acts, ct_priv->ns_type,
1409 ZONE_TO_REG, zone);
1410 if (err) {
1411 ct_dbg("Failed to set zone register mapping");
1412 goto err_mapping;
1413 }
1414
1415 mod_hdr = mlx5_modify_header_alloc(dev, ct_priv->ns_type,
1416 pre_mod_acts.num_actions,
1417 pre_mod_acts.actions);
1418
1419 if (IS_ERR(mod_hdr)) {
1420 err = PTR_ERR(mod_hdr);
1421 ct_dbg("Failed to create pre ct mod hdr");
1422 goto err_mapping;
1423 }
1424 pre_ct->modify_hdr = mod_hdr;
1425
1426 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1427 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1428 flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
1429 flow_act.modify_hdr = mod_hdr;
1430 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1431
1432 /* add flow rule */
1433 mlx5e_tc_match_to_reg_match(spec, ZONE_TO_REG,
1434 zone, MLX5_CT_ZONE_MASK);
1435 ctstate = MLX5_CT_STATE_TRK_BIT;
1436 if (nat)
1437 ctstate |= MLX5_CT_STATE_NAT_BIT;
1438 mlx5e_tc_match_to_reg_match(spec, CTSTATE_TO_REG, ctstate, ctstate);
1439
1440 dest.ft = mlx5e_tc_post_act_get_ft(ct_priv->post_act);
1441 rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
1442 if (IS_ERR(rule)) {
1443 err = PTR_ERR(rule);
1444 ct_dbg("Failed to add pre ct flow rule zone %d", zone);
1445 goto err_flow_rule;
1446 }
1447 pre_ct->flow_rule = rule;
1448
1449 /* add miss rule */
1450 dest.ft = nat ? ct_priv->ct_nat : ct_priv->ct;
1451 rule = mlx5_add_flow_rules(ft, NULL, &flow_act, &dest, 1);
1452 if (IS_ERR(rule)) {
1453 err = PTR_ERR(rule);
1454 ct_dbg("Failed to add pre ct miss rule zone %d", zone);
1455 goto err_miss_rule;
1456 }
1457 pre_ct->miss_rule = rule;
1458
1459 mlx5e_mod_hdr_dealloc(&pre_mod_acts);
1460 kvfree(spec);
1461 return 0;
1462
1463 err_miss_rule:
1464 mlx5_del_flow_rules(pre_ct->flow_rule);
1465 err_flow_rule:
1466 mlx5_modify_header_dealloc(dev, pre_ct->modify_hdr);
1467 err_mapping:
1468 mlx5e_mod_hdr_dealloc(&pre_mod_acts);
1469 kvfree(spec);
1470 return err;
1471 }
1472
1473 static void
tc_ct_pre_ct_del_rules(struct mlx5_ct_ft * ct_ft,struct mlx5_tc_ct_pre * pre_ct)1474 tc_ct_pre_ct_del_rules(struct mlx5_ct_ft *ct_ft,
1475 struct mlx5_tc_ct_pre *pre_ct)
1476 {
1477 struct mlx5_tc_ct_priv *ct_priv = ct_ft->ct_priv;
1478 struct mlx5_core_dev *dev = ct_priv->dev;
1479
1480 mlx5_del_flow_rules(pre_ct->flow_rule);
1481 mlx5_del_flow_rules(pre_ct->miss_rule);
1482 mlx5_modify_header_dealloc(dev, pre_ct->modify_hdr);
1483 }
1484
1485 static int
mlx5_tc_ct_alloc_pre_ct(struct mlx5_ct_ft * ct_ft,struct mlx5_tc_ct_pre * pre_ct,bool nat)1486 mlx5_tc_ct_alloc_pre_ct(struct mlx5_ct_ft *ct_ft,
1487 struct mlx5_tc_ct_pre *pre_ct,
1488 bool nat)
1489 {
1490 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1491 struct mlx5_tc_ct_priv *ct_priv = ct_ft->ct_priv;
1492 struct mlx5_core_dev *dev = ct_priv->dev;
1493 struct mlx5_flow_table_attr ft_attr = {};
1494 struct mlx5_flow_namespace *ns;
1495 struct mlx5_flow_table *ft;
1496 struct mlx5_flow_group *g;
1497 u32 metadata_reg_c_2_mask;
1498 u32 *flow_group_in;
1499 void *misc;
1500 int err;
1501
1502 ns = mlx5_get_flow_namespace(dev, ct_priv->ns_type);
1503 if (!ns) {
1504 err = -EOPNOTSUPP;
1505 ct_dbg("Failed to get flow namespace");
1506 return err;
1507 }
1508
1509 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1510 if (!flow_group_in)
1511 return -ENOMEM;
1512
1513 ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
1514 ft_attr.prio = ct_priv->ns_type == MLX5_FLOW_NAMESPACE_FDB ?
1515 FDB_TC_OFFLOAD : MLX5E_TC_PRIO;
1516 ft_attr.max_fte = 2;
1517 ft_attr.level = 1;
1518 ft = mlx5_create_flow_table(ns, &ft_attr);
1519 if (IS_ERR(ft)) {
1520 err = PTR_ERR(ft);
1521 ct_dbg("Failed to create pre ct table");
1522 goto out_free;
1523 }
1524 pre_ct->ft = ft;
1525
1526 /* create flow group */
1527 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1528 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
1529 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1530 MLX5_MATCH_MISC_PARAMETERS_2);
1531
1532 misc = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
1533 match_criteria.misc_parameters_2);
1534
1535 metadata_reg_c_2_mask = MLX5_CT_ZONE_MASK;
1536 metadata_reg_c_2_mask |= (MLX5_CT_STATE_TRK_BIT << 16);
1537 if (nat)
1538 metadata_reg_c_2_mask |= (MLX5_CT_STATE_NAT_BIT << 16);
1539
1540 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_2,
1541 metadata_reg_c_2_mask);
1542
1543 g = mlx5_create_flow_group(ft, flow_group_in);
1544 if (IS_ERR(g)) {
1545 err = PTR_ERR(g);
1546 ct_dbg("Failed to create pre ct group");
1547 goto err_flow_grp;
1548 }
1549 pre_ct->flow_grp = g;
1550
1551 /* create miss group */
1552 memset(flow_group_in, 0, inlen);
1553 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
1554 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
1555 g = mlx5_create_flow_group(ft, flow_group_in);
1556 if (IS_ERR(g)) {
1557 err = PTR_ERR(g);
1558 ct_dbg("Failed to create pre ct miss group");
1559 goto err_miss_grp;
1560 }
1561 pre_ct->miss_grp = g;
1562
1563 err = tc_ct_pre_ct_add_rules(ct_ft, pre_ct, nat);
1564 if (err)
1565 goto err_add_rules;
1566
1567 kvfree(flow_group_in);
1568 return 0;
1569
1570 err_add_rules:
1571 mlx5_destroy_flow_group(pre_ct->miss_grp);
1572 err_miss_grp:
1573 mlx5_destroy_flow_group(pre_ct->flow_grp);
1574 err_flow_grp:
1575 mlx5_destroy_flow_table(ft);
1576 out_free:
1577 kvfree(flow_group_in);
1578 return err;
1579 }
1580
1581 static void
mlx5_tc_ct_free_pre_ct(struct mlx5_ct_ft * ct_ft,struct mlx5_tc_ct_pre * pre_ct)1582 mlx5_tc_ct_free_pre_ct(struct mlx5_ct_ft *ct_ft,
1583 struct mlx5_tc_ct_pre *pre_ct)
1584 {
1585 tc_ct_pre_ct_del_rules(ct_ft, pre_ct);
1586 mlx5_destroy_flow_group(pre_ct->miss_grp);
1587 mlx5_destroy_flow_group(pre_ct->flow_grp);
1588 mlx5_destroy_flow_table(pre_ct->ft);
1589 }
1590
1591 static int
mlx5_tc_ct_alloc_pre_ct_tables(struct mlx5_ct_ft * ft)1592 mlx5_tc_ct_alloc_pre_ct_tables(struct mlx5_ct_ft *ft)
1593 {
1594 int err;
1595
1596 err = mlx5_tc_ct_alloc_pre_ct(ft, &ft->pre_ct, false);
1597 if (err)
1598 return err;
1599
1600 err = mlx5_tc_ct_alloc_pre_ct(ft, &ft->pre_ct_nat, true);
1601 if (err)
1602 goto err_pre_ct_nat;
1603
1604 return 0;
1605
1606 err_pre_ct_nat:
1607 mlx5_tc_ct_free_pre_ct(ft, &ft->pre_ct);
1608 return err;
1609 }
1610
1611 static void
mlx5_tc_ct_free_pre_ct_tables(struct mlx5_ct_ft * ft)1612 mlx5_tc_ct_free_pre_ct_tables(struct mlx5_ct_ft *ft)
1613 {
1614 mlx5_tc_ct_free_pre_ct(ft, &ft->pre_ct_nat);
1615 mlx5_tc_ct_free_pre_ct(ft, &ft->pre_ct);
1616 }
1617
1618 /* To avoid false lock dependency warning set the ct_entries_ht lock
1619 * class different than the lock class of the ht being used when deleting
1620 * last flow from a group and then deleting a group, we get into del_sw_flow_group()
1621 * which call rhashtable_destroy on fg->ftes_hash which will take ht->mutex but
1622 * it's different than the ht->mutex here.
1623 */
1624 static struct lock_class_key ct_entries_ht_lock_key;
1625
1626 static struct mlx5_ct_ft *
mlx5_tc_ct_add_ft_cb(struct mlx5_tc_ct_priv * ct_priv,u16 zone,struct nf_flowtable * nf_ft)1627 mlx5_tc_ct_add_ft_cb(struct mlx5_tc_ct_priv *ct_priv, u16 zone,
1628 struct nf_flowtable *nf_ft)
1629 {
1630 struct mlx5_ct_ft *ft;
1631 int err;
1632
1633 ft = rhashtable_lookup_fast(&ct_priv->zone_ht, &zone, zone_params);
1634 if (ft) {
1635 refcount_inc(&ft->refcount);
1636 return ft;
1637 }
1638
1639 ft = kzalloc(sizeof(*ft), GFP_KERNEL);
1640 if (!ft)
1641 return ERR_PTR(-ENOMEM);
1642
1643 err = mapping_add(ct_priv->zone_mapping, &zone, &ft->zone_restore_id);
1644 if (err)
1645 goto err_mapping;
1646
1647 ft->zone = zone;
1648 ft->nf_ft = nf_ft;
1649 ft->ct_priv = ct_priv;
1650 refcount_set(&ft->refcount, 1);
1651
1652 err = mlx5_tc_ct_alloc_pre_ct_tables(ft);
1653 if (err)
1654 goto err_alloc_pre_ct;
1655
1656 err = rhashtable_init(&ft->ct_entries_ht, &cts_ht_params);
1657 if (err)
1658 goto err_init;
1659
1660 lockdep_set_class(&ft->ct_entries_ht.mutex, &ct_entries_ht_lock_key);
1661
1662 err = rhashtable_insert_fast(&ct_priv->zone_ht, &ft->node,
1663 zone_params);
1664 if (err)
1665 goto err_insert;
1666
1667 err = nf_flow_table_offload_add_cb(ft->nf_ft,
1668 mlx5_tc_ct_block_flow_offload, ft);
1669 if (err)
1670 goto err_add_cb;
1671
1672 return ft;
1673
1674 err_add_cb:
1675 rhashtable_remove_fast(&ct_priv->zone_ht, &ft->node, zone_params);
1676 err_insert:
1677 rhashtable_destroy(&ft->ct_entries_ht);
1678 err_init:
1679 mlx5_tc_ct_free_pre_ct_tables(ft);
1680 err_alloc_pre_ct:
1681 mapping_remove(ct_priv->zone_mapping, ft->zone_restore_id);
1682 err_mapping:
1683 kfree(ft);
1684 return ERR_PTR(err);
1685 }
1686
1687 static void
mlx5_tc_ct_flush_ft_entry(void * ptr,void * arg)1688 mlx5_tc_ct_flush_ft_entry(void *ptr, void *arg)
1689 {
1690 struct mlx5_ct_entry *entry = ptr;
1691
1692 mlx5_tc_ct_entry_put(entry);
1693 }
1694
1695 static void
mlx5_tc_ct_del_ft_cb(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_ct_ft * ft)1696 mlx5_tc_ct_del_ft_cb(struct mlx5_tc_ct_priv *ct_priv, struct mlx5_ct_ft *ft)
1697 {
1698 struct mlx5e_priv *priv;
1699
1700 if (!refcount_dec_and_test(&ft->refcount))
1701 return;
1702
1703 nf_flow_table_offload_del_cb(ft->nf_ft,
1704 mlx5_tc_ct_block_flow_offload, ft);
1705 rhashtable_remove_fast(&ct_priv->zone_ht, &ft->node, zone_params);
1706 rhashtable_free_and_destroy(&ft->ct_entries_ht,
1707 mlx5_tc_ct_flush_ft_entry,
1708 ct_priv);
1709 priv = netdev_priv(ct_priv->netdev);
1710 flush_workqueue(priv->wq);
1711 mlx5_tc_ct_free_pre_ct_tables(ft);
1712 mapping_remove(ct_priv->zone_mapping, ft->zone_restore_id);
1713 kfree(ft);
1714 }
1715
1716 /* We translate the tc filter with CT action to the following HW model:
1717 *
1718 * +---------------------+
1719 * + ft prio (tc chain) +
1720 * + original match +
1721 * +---------------------+
1722 * | set chain miss mapping
1723 * | set fte_id
1724 * | set tunnel_id
1725 * | do decap
1726 * v
1727 * +---------------------+
1728 * + pre_ct/pre_ct_nat + if matches +-------------------------+
1729 * + zone+nat match +---------------->+ post_act (see below) +
1730 * +---------------------+ set zone +-------------------------+
1731 * | set zone
1732 * v
1733 * +--------------------+
1734 * + CT (nat or no nat) +
1735 * + tuple + zone match +
1736 * +--------------------+
1737 * | set mark
1738 * | set labels_id
1739 * | set established
1740 * | set zone_restore
1741 * | do nat (if needed)
1742 * v
1743 * +--------------+
1744 * + post_act + original filter actions
1745 * + fte_id match +------------------------>
1746 * +--------------+
1747 */
1748 static struct mlx5_flow_handle *
__mlx5_tc_ct_flow_offload(struct mlx5_tc_ct_priv * ct_priv,struct mlx5e_tc_flow * flow,struct mlx5_flow_spec * orig_spec,struct mlx5_flow_attr * attr)1749 __mlx5_tc_ct_flow_offload(struct mlx5_tc_ct_priv *ct_priv,
1750 struct mlx5e_tc_flow *flow,
1751 struct mlx5_flow_spec *orig_spec,
1752 struct mlx5_flow_attr *attr)
1753 {
1754 bool nat = attr->ct_attr.ct_action & TCA_CT_ACT_NAT;
1755 struct mlx5e_priv *priv = netdev_priv(ct_priv->netdev);
1756 struct mlx5e_tc_mod_hdr_acts pre_mod_acts = {};
1757 u32 attr_sz = ns_to_attr_sz(ct_priv->ns_type);
1758 struct mlx5e_post_act_handle *handle;
1759 struct mlx5_flow_attr *pre_ct_attr;
1760 struct mlx5_modify_hdr *mod_hdr;
1761 struct mlx5_ct_flow *ct_flow;
1762 int chain_mapping = 0, err;
1763 struct mlx5_ct_ft *ft;
1764
1765 ct_flow = kzalloc(sizeof(*ct_flow), GFP_KERNEL);
1766 if (!ct_flow) {
1767 kfree(ct_flow);
1768 return ERR_PTR(-ENOMEM);
1769 }
1770
1771 /* Register for CT established events */
1772 ft = mlx5_tc_ct_add_ft_cb(ct_priv, attr->ct_attr.zone,
1773 attr->ct_attr.nf_ft);
1774 if (IS_ERR(ft)) {
1775 err = PTR_ERR(ft);
1776 ct_dbg("Failed to register to ft callback");
1777 goto err_ft;
1778 }
1779 ct_flow->ft = ft;
1780
1781 handle = mlx5e_tc_post_act_add(ct_priv->post_act, attr);
1782 if (IS_ERR(handle)) {
1783 err = PTR_ERR(handle);
1784 ct_dbg("Failed to allocate post action handle");
1785 goto err_post_act_handle;
1786 }
1787 ct_flow->post_act_handle = handle;
1788
1789 /* Base flow attributes of both rules on original rule attribute */
1790 ct_flow->pre_ct_attr = mlx5_alloc_flow_attr(ct_priv->ns_type);
1791 if (!ct_flow->pre_ct_attr) {
1792 err = -ENOMEM;
1793 goto err_alloc_pre;
1794 }
1795
1796 pre_ct_attr = ct_flow->pre_ct_attr;
1797 memcpy(pre_ct_attr, attr, attr_sz);
1798
1799 /* Modify the original rule's action to fwd and modify, leave decap */
1800 pre_ct_attr->action = attr->action & MLX5_FLOW_CONTEXT_ACTION_DECAP;
1801 pre_ct_attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1802 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1803
1804 /* Write chain miss tag for miss in ct table as we
1805 * don't go though all prios of this chain as normal tc rules
1806 * miss.
1807 */
1808 err = mlx5_chains_get_chain_mapping(ct_priv->chains, attr->chain,
1809 &chain_mapping);
1810 if (err) {
1811 ct_dbg("Failed to get chain register mapping for chain");
1812 goto err_get_chain;
1813 }
1814 ct_flow->chain_mapping = chain_mapping;
1815
1816 err = mlx5e_tc_match_to_reg_set(priv->mdev, &pre_mod_acts, ct_priv->ns_type,
1817 CHAIN_TO_REG, chain_mapping);
1818 if (err) {
1819 ct_dbg("Failed to set chain register mapping");
1820 goto err_mapping;
1821 }
1822
1823 err = mlx5e_tc_post_act_set_handle(priv->mdev, handle, &pre_mod_acts);
1824 if (err) {
1825 ct_dbg("Failed to set post action handle");
1826 goto err_mapping;
1827 }
1828
1829 /* If original flow is decap, we do it before going into ct table
1830 * so add a rewrite for the tunnel match_id.
1831 */
1832 if ((pre_ct_attr->action & MLX5_FLOW_CONTEXT_ACTION_DECAP) &&
1833 attr->chain == 0) {
1834 u32 tun_id = mlx5e_tc_get_flow_tun_id(flow);
1835
1836 err = mlx5e_tc_match_to_reg_set(priv->mdev, &pre_mod_acts,
1837 ct_priv->ns_type,
1838 TUNNEL_TO_REG,
1839 tun_id);
1840 if (err) {
1841 ct_dbg("Failed to set tunnel register mapping");
1842 goto err_mapping;
1843 }
1844 }
1845
1846 mod_hdr = mlx5_modify_header_alloc(priv->mdev, ct_priv->ns_type,
1847 pre_mod_acts.num_actions,
1848 pre_mod_acts.actions);
1849 if (IS_ERR(mod_hdr)) {
1850 err = PTR_ERR(mod_hdr);
1851 ct_dbg("Failed to create pre ct mod hdr");
1852 goto err_mapping;
1853 }
1854 pre_ct_attr->modify_hdr = mod_hdr;
1855
1856 /* Change original rule point to ct table */
1857 pre_ct_attr->dest_chain = 0;
1858 pre_ct_attr->dest_ft = nat ? ft->pre_ct_nat.ft : ft->pre_ct.ft;
1859 ct_flow->pre_ct_rule = mlx5_tc_rule_insert(priv, orig_spec,
1860 pre_ct_attr);
1861 if (IS_ERR(ct_flow->pre_ct_rule)) {
1862 err = PTR_ERR(ct_flow->pre_ct_rule);
1863 ct_dbg("Failed to add pre ct rule");
1864 goto err_insert_orig;
1865 }
1866
1867 attr->ct_attr.ct_flow = ct_flow;
1868 mlx5e_mod_hdr_dealloc(&pre_mod_acts);
1869
1870 return ct_flow->pre_ct_rule;
1871
1872 err_insert_orig:
1873 mlx5_modify_header_dealloc(priv->mdev, pre_ct_attr->modify_hdr);
1874 err_mapping:
1875 mlx5e_mod_hdr_dealloc(&pre_mod_acts);
1876 mlx5_chains_put_chain_mapping(ct_priv->chains, ct_flow->chain_mapping);
1877 err_get_chain:
1878 kfree(ct_flow->pre_ct_attr);
1879 err_alloc_pre:
1880 mlx5e_tc_post_act_del(ct_priv->post_act, handle);
1881 err_post_act_handle:
1882 mlx5_tc_ct_del_ft_cb(ct_priv, ft);
1883 err_ft:
1884 kfree(ct_flow);
1885 netdev_warn(priv->netdev, "Failed to offload ct flow, err %d\n", err);
1886 return ERR_PTR(err);
1887 }
1888
1889 static struct mlx5_flow_handle *
__mlx5_tc_ct_flow_offload_clear(struct mlx5_tc_ct_priv * ct_priv,struct mlx5_flow_spec * orig_spec,struct mlx5_flow_attr * attr,struct mlx5e_tc_mod_hdr_acts * mod_acts)1890 __mlx5_tc_ct_flow_offload_clear(struct mlx5_tc_ct_priv *ct_priv,
1891 struct mlx5_flow_spec *orig_spec,
1892 struct mlx5_flow_attr *attr,
1893 struct mlx5e_tc_mod_hdr_acts *mod_acts)
1894 {
1895 struct mlx5e_priv *priv = netdev_priv(ct_priv->netdev);
1896 u32 attr_sz = ns_to_attr_sz(ct_priv->ns_type);
1897 struct mlx5_flow_attr *pre_ct_attr;
1898 struct mlx5_modify_hdr *mod_hdr;
1899 struct mlx5_flow_handle *rule;
1900 struct mlx5_ct_flow *ct_flow;
1901 int err;
1902
1903 ct_flow = kzalloc(sizeof(*ct_flow), GFP_KERNEL);
1904 if (!ct_flow)
1905 return ERR_PTR(-ENOMEM);
1906
1907 /* Base esw attributes on original rule attribute */
1908 pre_ct_attr = mlx5_alloc_flow_attr(ct_priv->ns_type);
1909 if (!pre_ct_attr) {
1910 err = -ENOMEM;
1911 goto err_attr;
1912 }
1913
1914 memcpy(pre_ct_attr, attr, attr_sz);
1915
1916 mod_hdr = mlx5_modify_header_alloc(priv->mdev, ct_priv->ns_type,
1917 mod_acts->num_actions,
1918 mod_acts->actions);
1919 if (IS_ERR(mod_hdr)) {
1920 err = PTR_ERR(mod_hdr);
1921 ct_dbg("Failed to add create ct clear mod hdr");
1922 goto err_mod_hdr;
1923 }
1924
1925 pre_ct_attr->modify_hdr = mod_hdr;
1926
1927 rule = mlx5_tc_rule_insert(priv, orig_spec, pre_ct_attr);
1928 if (IS_ERR(rule)) {
1929 err = PTR_ERR(rule);
1930 ct_dbg("Failed to add ct clear rule");
1931 goto err_insert;
1932 }
1933
1934 attr->ct_attr.ct_flow = ct_flow;
1935 ct_flow->pre_ct_attr = pre_ct_attr;
1936 ct_flow->pre_ct_rule = rule;
1937 return rule;
1938
1939 err_insert:
1940 mlx5_modify_header_dealloc(priv->mdev, mod_hdr);
1941 err_mod_hdr:
1942 netdev_warn(priv->netdev,
1943 "Failed to offload ct clear flow, err %d\n", err);
1944 kfree(pre_ct_attr);
1945 err_attr:
1946 kfree(ct_flow);
1947
1948 return ERR_PTR(err);
1949 }
1950
1951 struct mlx5_flow_handle *
mlx5_tc_ct_flow_offload(struct mlx5_tc_ct_priv * priv,struct mlx5e_tc_flow * flow,struct mlx5_flow_spec * spec,struct mlx5_flow_attr * attr,struct mlx5e_tc_mod_hdr_acts * mod_hdr_acts)1952 mlx5_tc_ct_flow_offload(struct mlx5_tc_ct_priv *priv,
1953 struct mlx5e_tc_flow *flow,
1954 struct mlx5_flow_spec *spec,
1955 struct mlx5_flow_attr *attr,
1956 struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts)
1957 {
1958 bool clear_action = attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR;
1959 struct mlx5_flow_handle *rule;
1960
1961 if (!priv)
1962 return ERR_PTR(-EOPNOTSUPP);
1963
1964 mutex_lock(&priv->control_lock);
1965
1966 if (clear_action)
1967 rule = __mlx5_tc_ct_flow_offload_clear(priv, spec, attr, mod_hdr_acts);
1968 else
1969 rule = __mlx5_tc_ct_flow_offload(priv, flow, spec, attr);
1970 mutex_unlock(&priv->control_lock);
1971
1972 return rule;
1973 }
1974
1975 static void
__mlx5_tc_ct_delete_flow(struct mlx5_tc_ct_priv * ct_priv,struct mlx5e_tc_flow * flow,struct mlx5_ct_flow * ct_flow)1976 __mlx5_tc_ct_delete_flow(struct mlx5_tc_ct_priv *ct_priv,
1977 struct mlx5e_tc_flow *flow,
1978 struct mlx5_ct_flow *ct_flow)
1979 {
1980 struct mlx5_flow_attr *pre_ct_attr = ct_flow->pre_ct_attr;
1981 struct mlx5e_priv *priv = netdev_priv(ct_priv->netdev);
1982
1983 mlx5_tc_rule_delete(priv, ct_flow->pre_ct_rule,
1984 pre_ct_attr);
1985 mlx5_modify_header_dealloc(priv->mdev, pre_ct_attr->modify_hdr);
1986
1987 if (ct_flow->post_act_handle) {
1988 mlx5_chains_put_chain_mapping(ct_priv->chains, ct_flow->chain_mapping);
1989 mlx5e_tc_post_act_del(ct_priv->post_act, ct_flow->post_act_handle);
1990 mlx5_tc_ct_del_ft_cb(ct_priv, ct_flow->ft);
1991 }
1992
1993 kfree(ct_flow->pre_ct_attr);
1994 kfree(ct_flow);
1995 }
1996
1997 void
mlx5_tc_ct_delete_flow(struct mlx5_tc_ct_priv * priv,struct mlx5e_tc_flow * flow,struct mlx5_flow_attr * attr)1998 mlx5_tc_ct_delete_flow(struct mlx5_tc_ct_priv *priv,
1999 struct mlx5e_tc_flow *flow,
2000 struct mlx5_flow_attr *attr)
2001 {
2002 struct mlx5_ct_flow *ct_flow = attr->ct_attr.ct_flow;
2003
2004 /* We are called on error to clean up stuff from parsing
2005 * but we don't have anything for now
2006 */
2007 if (!ct_flow)
2008 return;
2009
2010 mutex_lock(&priv->control_lock);
2011 __mlx5_tc_ct_delete_flow(priv, flow, ct_flow);
2012 mutex_unlock(&priv->control_lock);
2013 }
2014
2015 static int
mlx5_tc_ct_init_check_esw_support(struct mlx5_eswitch * esw,const char ** err_msg)2016 mlx5_tc_ct_init_check_esw_support(struct mlx5_eswitch *esw,
2017 const char **err_msg)
2018 {
2019 if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1)) {
2020 /* vlan workaround should be avoided for multi chain rules.
2021 * This is just a sanity check as pop vlan action should
2022 * be supported by any FW that supports ignore_flow_level
2023 */
2024
2025 *err_msg = "firmware vlan actions support is missing";
2026 return -EOPNOTSUPP;
2027 }
2028
2029 if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev,
2030 fdb_modify_header_fwd_to_table)) {
2031 /* CT always writes to registers which are mod header actions.
2032 * Therefore, mod header and goto is required
2033 */
2034
2035 *err_msg = "firmware fwd and modify support is missing";
2036 return -EOPNOTSUPP;
2037 }
2038
2039 if (!mlx5_eswitch_reg_c1_loopback_enabled(esw)) {
2040 *err_msg = "register loopback isn't supported";
2041 return -EOPNOTSUPP;
2042 }
2043
2044 return 0;
2045 }
2046
2047 static int
mlx5_tc_ct_init_check_support(struct mlx5e_priv * priv,enum mlx5_flow_namespace_type ns_type,struct mlx5e_post_act * post_act,const char ** err_msg)2048 mlx5_tc_ct_init_check_support(struct mlx5e_priv *priv,
2049 enum mlx5_flow_namespace_type ns_type,
2050 struct mlx5e_post_act *post_act,
2051 const char **err_msg)
2052 {
2053 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
2054
2055 #if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
2056 /* cannot restore chain ID on HW miss */
2057
2058 *err_msg = "tc skb extension missing";
2059 return -EOPNOTSUPP;
2060 #endif
2061 if (IS_ERR_OR_NULL(post_act)) {
2062 *err_msg = "tc ct offload not supported, post action is missing";
2063 return -EOPNOTSUPP;
2064 }
2065
2066 if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
2067 return mlx5_tc_ct_init_check_esw_support(esw, err_msg);
2068 return 0;
2069 }
2070
2071 #define INIT_ERR_PREFIX "tc ct offload init failed"
2072
2073 struct mlx5_tc_ct_priv *
mlx5_tc_ct_init(struct mlx5e_priv * priv,struct mlx5_fs_chains * chains,struct mod_hdr_tbl * mod_hdr,enum mlx5_flow_namespace_type ns_type,struct mlx5e_post_act * post_act)2074 mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
2075 struct mod_hdr_tbl *mod_hdr,
2076 enum mlx5_flow_namespace_type ns_type,
2077 struct mlx5e_post_act *post_act)
2078 {
2079 struct mlx5_tc_ct_priv *ct_priv;
2080 struct mlx5_core_dev *dev;
2081 const char *msg;
2082 u64 mapping_id;
2083 int err;
2084
2085 dev = priv->mdev;
2086 err = mlx5_tc_ct_init_check_support(priv, ns_type, post_act, &msg);
2087 if (err) {
2088 mlx5_core_warn(dev, "tc ct offload not supported, %s\n", msg);
2089 goto err_support;
2090 }
2091
2092 ct_priv = kzalloc(sizeof(*ct_priv), GFP_KERNEL);
2093 if (!ct_priv)
2094 goto err_alloc;
2095
2096 mapping_id = mlx5_query_nic_system_image_guid(dev);
2097
2098 ct_priv->zone_mapping = mapping_create_for_id(mapping_id, MAPPING_TYPE_ZONE,
2099 sizeof(u16), 0, true);
2100 if (IS_ERR(ct_priv->zone_mapping)) {
2101 err = PTR_ERR(ct_priv->zone_mapping);
2102 goto err_mapping_zone;
2103 }
2104
2105 ct_priv->labels_mapping = mapping_create_for_id(mapping_id, MAPPING_TYPE_LABELS,
2106 sizeof(u32) * 4, 0, true);
2107 if (IS_ERR(ct_priv->labels_mapping)) {
2108 err = PTR_ERR(ct_priv->labels_mapping);
2109 goto err_mapping_labels;
2110 }
2111
2112 spin_lock_init(&ct_priv->ht_lock);
2113 ct_priv->ns_type = ns_type;
2114 ct_priv->chains = chains;
2115 ct_priv->netdev = priv->netdev;
2116 ct_priv->dev = priv->mdev;
2117 ct_priv->mod_hdr_tbl = mod_hdr;
2118 ct_priv->ct = mlx5_chains_create_global_table(chains);
2119 if (IS_ERR(ct_priv->ct)) {
2120 err = PTR_ERR(ct_priv->ct);
2121 mlx5_core_warn(dev,
2122 "%s, failed to create ct table err: %d\n",
2123 INIT_ERR_PREFIX, err);
2124 goto err_ct_tbl;
2125 }
2126
2127 ct_priv->ct_nat = mlx5_chains_create_global_table(chains);
2128 if (IS_ERR(ct_priv->ct_nat)) {
2129 err = PTR_ERR(ct_priv->ct_nat);
2130 mlx5_core_warn(dev,
2131 "%s, failed to create ct nat table err: %d\n",
2132 INIT_ERR_PREFIX, err);
2133 goto err_ct_nat_tbl;
2134 }
2135
2136 ct_priv->post_act = post_act;
2137 mutex_init(&ct_priv->control_lock);
2138 rhashtable_init(&ct_priv->zone_ht, &zone_params);
2139 rhashtable_init(&ct_priv->ct_tuples_ht, &tuples_ht_params);
2140 rhashtable_init(&ct_priv->ct_tuples_nat_ht, &tuples_nat_ht_params);
2141
2142 return ct_priv;
2143
2144 err_ct_nat_tbl:
2145 mlx5_chains_destroy_global_table(chains, ct_priv->ct);
2146 err_ct_tbl:
2147 mapping_destroy(ct_priv->labels_mapping);
2148 err_mapping_labels:
2149 mapping_destroy(ct_priv->zone_mapping);
2150 err_mapping_zone:
2151 kfree(ct_priv);
2152 err_alloc:
2153 err_support:
2154
2155 return NULL;
2156 }
2157
2158 void
mlx5_tc_ct_clean(struct mlx5_tc_ct_priv * ct_priv)2159 mlx5_tc_ct_clean(struct mlx5_tc_ct_priv *ct_priv)
2160 {
2161 struct mlx5_fs_chains *chains;
2162
2163 if (!ct_priv)
2164 return;
2165
2166 chains = ct_priv->chains;
2167
2168 mlx5_chains_destroy_global_table(chains, ct_priv->ct_nat);
2169 mlx5_chains_destroy_global_table(chains, ct_priv->ct);
2170 mapping_destroy(ct_priv->zone_mapping);
2171 mapping_destroy(ct_priv->labels_mapping);
2172
2173 rhashtable_destroy(&ct_priv->ct_tuples_ht);
2174 rhashtable_destroy(&ct_priv->ct_tuples_nat_ht);
2175 rhashtable_destroy(&ct_priv->zone_ht);
2176 mutex_destroy(&ct_priv->control_lock);
2177 kfree(ct_priv);
2178 }
2179
2180 bool
mlx5e_tc_ct_restore_flow(struct mlx5_tc_ct_priv * ct_priv,struct sk_buff * skb,u8 zone_restore_id)2181 mlx5e_tc_ct_restore_flow(struct mlx5_tc_ct_priv *ct_priv,
2182 struct sk_buff *skb, u8 zone_restore_id)
2183 {
2184 struct mlx5_ct_tuple tuple = {};
2185 struct mlx5_ct_entry *entry;
2186 u16 zone;
2187
2188 if (!ct_priv || !zone_restore_id)
2189 return true;
2190
2191 if (mapping_find(ct_priv->zone_mapping, zone_restore_id, &zone))
2192 return false;
2193
2194 if (!mlx5_tc_ct_skb_to_tuple(skb, &tuple, zone))
2195 return false;
2196
2197 spin_lock(&ct_priv->ht_lock);
2198
2199 entry = mlx5_tc_ct_entry_get(ct_priv, &tuple);
2200 if (!entry) {
2201 spin_unlock(&ct_priv->ht_lock);
2202 return false;
2203 }
2204
2205 if (IS_ERR(entry)) {
2206 spin_unlock(&ct_priv->ht_lock);
2207 return false;
2208 }
2209 spin_unlock(&ct_priv->ht_lock);
2210
2211 tcf_ct_flow_table_restore_skb(skb, entry->restore_cookie);
2212 __mlx5_tc_ct_entry_put(entry);
2213
2214 return true;
2215 }
2216