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
tc_act_can_offload_ct(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,int act_index,struct mlx5_flow_attr * attr)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
tc_act_parse_ct(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)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
tc_act_post_parse_ct(struct mlx5e_tc_act_parse_state * parse_state,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)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
tc_act_is_multi_table_act_ct(struct mlx5e_priv * priv,const struct flow_action_entry * act,struct mlx5_flow_attr * attr)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