1*67d62ee7SRoi Dayan // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2*67d62ee7SRoi Dayan // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3*67d62ee7SRoi Dayan 
4*67d62ee7SRoi Dayan #include "act.h"
5*67d62ee7SRoi Dayan #include "en/tc_priv.h"
6*67d62ee7SRoi Dayan #include "eswitch.h"
7*67d62ee7SRoi Dayan 
8*67d62ee7SRoi Dayan static int
9*67d62ee7SRoi Dayan validate_goto_chain(struct mlx5e_priv *priv,
10*67d62ee7SRoi Dayan 		    struct mlx5e_tc_flow *flow,
11*67d62ee7SRoi Dayan 		    const struct flow_action_entry *act,
12*67d62ee7SRoi Dayan 		    struct netlink_ext_ack *extack)
13*67d62ee7SRoi Dayan {
14*67d62ee7SRoi Dayan 	bool is_esw = mlx5e_is_eswitch_flow(flow);
15*67d62ee7SRoi Dayan 	bool ft_flow = mlx5e_is_ft_flow(flow);
16*67d62ee7SRoi Dayan 	u32 dest_chain = act->chain_index;
17*67d62ee7SRoi Dayan 	struct mlx5_fs_chains *chains;
18*67d62ee7SRoi Dayan 	struct mlx5_eswitch *esw;
19*67d62ee7SRoi Dayan 	u32 reformat_and_fwd;
20*67d62ee7SRoi Dayan 	u32 max_chain;
21*67d62ee7SRoi Dayan 
22*67d62ee7SRoi Dayan 	esw = priv->mdev->priv.eswitch;
23*67d62ee7SRoi Dayan 	chains = is_esw ? esw_chains(esw) : mlx5e_nic_chains(priv);
24*67d62ee7SRoi Dayan 	max_chain = mlx5_chains_get_chain_range(chains);
25*67d62ee7SRoi Dayan 	reformat_and_fwd = is_esw ?
26*67d62ee7SRoi Dayan 			   MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_and_fwd_to_table) :
27*67d62ee7SRoi Dayan 			   MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, reformat_and_fwd_to_table);
28*67d62ee7SRoi Dayan 
29*67d62ee7SRoi Dayan 	if (ft_flow) {
30*67d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
31*67d62ee7SRoi Dayan 		return -EOPNOTSUPP;
32*67d62ee7SRoi Dayan 	}
33*67d62ee7SRoi Dayan 
34*67d62ee7SRoi Dayan 	if (!mlx5_chains_backwards_supported(chains) &&
35*67d62ee7SRoi Dayan 	    dest_chain <= flow->attr->chain) {
36*67d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Goto lower numbered chain isn't supported");
37*67d62ee7SRoi Dayan 		return -EOPNOTSUPP;
38*67d62ee7SRoi Dayan 	}
39*67d62ee7SRoi Dayan 
40*67d62ee7SRoi Dayan 	if (dest_chain > max_chain) {
41*67d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack,
42*67d62ee7SRoi Dayan 				   "Requested destination chain is out of supported range");
43*67d62ee7SRoi Dayan 		return -EOPNOTSUPP;
44*67d62ee7SRoi Dayan 	}
45*67d62ee7SRoi Dayan 
46*67d62ee7SRoi Dayan 	if (flow->attr->action & (MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
47*67d62ee7SRoi Dayan 				  MLX5_FLOW_CONTEXT_ACTION_DECAP) &&
48*67d62ee7SRoi Dayan 	    !reformat_and_fwd) {
49*67d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack,
50*67d62ee7SRoi Dayan 				   "Goto chain is not allowed if action has reformat or decap");
51*67d62ee7SRoi Dayan 		return -EOPNOTSUPP;
52*67d62ee7SRoi Dayan 	}
53*67d62ee7SRoi Dayan 
54*67d62ee7SRoi Dayan 	return 0;
55*67d62ee7SRoi Dayan }
56*67d62ee7SRoi Dayan 
57*67d62ee7SRoi Dayan static bool
58*67d62ee7SRoi Dayan tc_act_can_offload_goto(struct mlx5e_tc_act_parse_state *parse_state,
59*67d62ee7SRoi Dayan 			const struct flow_action_entry *act,
60*67d62ee7SRoi Dayan 			int act_index)
61*67d62ee7SRoi Dayan {
62*67d62ee7SRoi Dayan 	struct netlink_ext_ack *extack = parse_state->extack;
63*67d62ee7SRoi Dayan 	struct mlx5e_tc_flow *flow = parse_state->flow;
64*67d62ee7SRoi Dayan 
65*67d62ee7SRoi Dayan 	if (validate_goto_chain(flow->priv, flow, act, extack))
66*67d62ee7SRoi Dayan 		return false;
67*67d62ee7SRoi Dayan 
68*67d62ee7SRoi Dayan 	return true;
69*67d62ee7SRoi Dayan }
70*67d62ee7SRoi Dayan 
71*67d62ee7SRoi Dayan static int
72*67d62ee7SRoi Dayan tc_act_parse_goto(struct mlx5e_tc_act_parse_state *parse_state,
73*67d62ee7SRoi Dayan 		  const struct flow_action_entry *act,
74*67d62ee7SRoi Dayan 		  struct mlx5e_priv *priv,
75*67d62ee7SRoi Dayan 		  struct mlx5_flow_attr *attr)
76*67d62ee7SRoi Dayan {
77*67d62ee7SRoi Dayan 	attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
78*67d62ee7SRoi Dayan 			MLX5_FLOW_CONTEXT_ACTION_COUNT;
79*67d62ee7SRoi Dayan 	attr->dest_chain = act->chain_index;
80*67d62ee7SRoi Dayan 
81*67d62ee7SRoi Dayan 	return 0;
82*67d62ee7SRoi Dayan }
83*67d62ee7SRoi Dayan 
84*67d62ee7SRoi Dayan struct mlx5e_tc_act mlx5e_tc_act_goto = {
85*67d62ee7SRoi Dayan 	.can_offload = tc_act_can_offload_goto,
86*67d62ee7SRoi Dayan 	.parse_action = tc_act_parse_goto,
87*67d62ee7SRoi Dayan };
88