1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 #include "act.h"
5 #include "en/tc_priv.h"
6 #include "en/tc_ct.h"
7 
8 static bool
9 tc_act_can_offload_ct(struct mlx5e_tc_act_parse_state *parse_state,
10 		      const struct flow_action_entry *act,
11 		      int act_index,
12 		      struct mlx5_flow_attr *attr)
13 {
14 	bool clear_action = act->ct.action & TCA_CT_ACT_CLEAR;
15 	struct netlink_ext_ack *extack = parse_state->extack;
16 
17 	if (parse_state->ct && !clear_action) {
18 		NL_SET_ERR_MSG_MOD(extack, "Multiple CT actions are not supported");
19 		return false;
20 	}
21 
22 	return true;
23 }
24 
25 static int
26 tc_act_parse_ct(struct mlx5e_tc_act_parse_state *parse_state,
27 		const struct flow_action_entry *act,
28 		struct mlx5e_priv *priv,
29 		struct mlx5_flow_attr *attr)
30 {
31 	bool clear_action = act->ct.action & TCA_CT_ACT_CLEAR;
32 	int err;
33 
34 	/* It's redundant to do ct clear more than once. */
35 	if (clear_action && parse_state->ct_clear)
36 		return 0;
37 
38 	err = mlx5_tc_ct_parse_action(parse_state->ct_priv, attr,
39 				      &attr->parse_attr->mod_hdr_acts,
40 				      act, parse_state->extack);
41 	if (err)
42 		return err;
43 
44 
45 	if (mlx5e_is_eswitch_flow(parse_state->flow))
46 		attr->esw_attr->split_count = attr->esw_attr->out_count;
47 
48 	if (clear_action) {
49 		parse_state->ct_clear = true;
50 	} else {
51 		attr->flags |= MLX5_ATTR_FLAG_CT;
52 		flow_flag_set(parse_state->flow, CT);
53 		parse_state->ct = true;
54 	}
55 
56 	return 0;
57 }
58 
59 static int
60 tc_act_post_parse_ct(struct mlx5e_tc_act_parse_state *parse_state,
61 		     struct mlx5e_priv *priv,
62 		     struct mlx5_flow_attr *attr)
63 {
64 	struct mlx5e_tc_mod_hdr_acts *mod_acts = &attr->parse_attr->mod_hdr_acts;
65 	int err;
66 
67 	/* If ct action exist, we can ignore previous ct_clear actions */
68 	if (parse_state->ct)
69 		return 0;
70 
71 	if (parse_state->ct_clear) {
72 		err = mlx5_tc_ct_set_ct_clear_regs(parse_state->ct_priv, mod_acts);
73 		if (err) {
74 			NL_SET_ERR_MSG_MOD(parse_state->extack,
75 					   "Failed to set registers for ct clear");
76 			return err;
77 		}
78 		attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
79 
80 		/* Prevent handling of additional, redundant clear actions */
81 		parse_state->ct_clear = false;
82 	}
83 
84 	return 0;
85 }
86 
87 static bool
88 tc_act_is_multi_table_act_ct(struct mlx5e_priv *priv,
89 			     const struct flow_action_entry *act,
90 			     struct mlx5_flow_attr *attr)
91 {
92 	if (act->ct.action & TCA_CT_ACT_CLEAR)
93 		return false;
94 
95 	return true;
96 }
97 
98 struct mlx5e_tc_act mlx5e_tc_act_ct = {
99 	.can_offload = tc_act_can_offload_ct,
100 	.parse_action = tc_act_parse_ct,
101 	.is_multi_table_act = tc_act_is_multi_table_act_ct,
102 	.post_parse = tc_act_post_parse_ct,
103 };
104 
105