167d62ee7SRoi Dayan // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
267d62ee7SRoi Dayan // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
367d62ee7SRoi Dayan 
467d62ee7SRoi Dayan #include "act.h"
567d62ee7SRoi Dayan #include "en/tc_priv.h"
667d62ee7SRoi Dayan #include "eswitch.h"
767d62ee7SRoi Dayan 
867d62ee7SRoi Dayan static int
validate_goto_chain(struct mlx5e_priv * priv,struct mlx5e_tc_flow * flow,struct mlx5_flow_attr * attr,const struct flow_action_entry * act,struct netlink_ext_ack * extack)967d62ee7SRoi Dayan validate_goto_chain(struct mlx5e_priv *priv,
1067d62ee7SRoi Dayan 		    struct mlx5e_tc_flow *flow,
118be9686dSRoi Dayan 		    struct mlx5_flow_attr *attr,
1267d62ee7SRoi Dayan 		    const struct flow_action_entry *act,
1367d62ee7SRoi Dayan 		    struct netlink_ext_ack *extack)
1467d62ee7SRoi Dayan {
15f52f2faeSLama Kayal 	struct mlx5e_tc_table *tc = mlx5e_fs_get_tc(priv->fs);
1667d62ee7SRoi Dayan 	bool is_esw = mlx5e_is_eswitch_flow(flow);
1767d62ee7SRoi Dayan 	bool ft_flow = mlx5e_is_ft_flow(flow);
1867d62ee7SRoi Dayan 	u32 dest_chain = act->chain_index;
1967d62ee7SRoi Dayan 	struct mlx5_fs_chains *chains;
2067d62ee7SRoi Dayan 	struct mlx5_eswitch *esw;
2167d62ee7SRoi Dayan 	u32 reformat_and_fwd;
2267d62ee7SRoi Dayan 	u32 max_chain;
2367d62ee7SRoi Dayan 
2467d62ee7SRoi Dayan 	esw = priv->mdev->priv.eswitch;
25f52f2faeSLama Kayal 	chains = is_esw ? esw_chains(esw) : mlx5e_nic_chains(tc);
2667d62ee7SRoi Dayan 	max_chain = mlx5_chains_get_chain_range(chains);
2767d62ee7SRoi Dayan 	reformat_and_fwd = is_esw ?
2867d62ee7SRoi Dayan 			   MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_and_fwd_to_table) :
2967d62ee7SRoi Dayan 			   MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, reformat_and_fwd_to_table);
3067d62ee7SRoi Dayan 
3167d62ee7SRoi Dayan 	if (ft_flow) {
3267d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
3367d62ee7SRoi Dayan 		return -EOPNOTSUPP;
3467d62ee7SRoi Dayan 	}
3567d62ee7SRoi Dayan 
3667d62ee7SRoi Dayan 	if (!mlx5_chains_backwards_supported(chains) &&
378be9686dSRoi Dayan 	    dest_chain <= attr->chain) {
3867d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Goto lower numbered chain isn't supported");
3967d62ee7SRoi Dayan 		return -EOPNOTSUPP;
4067d62ee7SRoi Dayan 	}
4167d62ee7SRoi Dayan 
4267d62ee7SRoi Dayan 	if (dest_chain > max_chain) {
4367d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack,
4467d62ee7SRoi Dayan 				   "Requested destination chain is out of supported range");
4567d62ee7SRoi Dayan 		return -EOPNOTSUPP;
4667d62ee7SRoi Dayan 	}
4767d62ee7SRoi Dayan 
488be9686dSRoi Dayan 	if (attr->action & (MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
4967d62ee7SRoi Dayan 			    MLX5_FLOW_CONTEXT_ACTION_DECAP) &&
5067d62ee7SRoi Dayan 	    !reformat_and_fwd) {
5167d62ee7SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack,
5267d62ee7SRoi Dayan 				   "Goto chain is not allowed if action has reformat or decap");
5367d62ee7SRoi Dayan 		return -EOPNOTSUPP;
5467d62ee7SRoi Dayan 	}
5567d62ee7SRoi Dayan 
5667d62ee7SRoi Dayan 	return 0;
5767d62ee7SRoi Dayan }
5867d62ee7SRoi Dayan 
5967d62ee7SRoi Dayan static bool
tc_act_can_offload_goto(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,int act_index,struct mlx5_flow_attr * attr)6067d62ee7SRoi Dayan tc_act_can_offload_goto(struct mlx5e_tc_act_parse_state *parse_state,
6167d62ee7SRoi Dayan 			const struct flow_action_entry *act,
628be9686dSRoi Dayan 			int act_index,
638be9686dSRoi Dayan 			struct mlx5_flow_attr *attr)
6467d62ee7SRoi Dayan {
6567d62ee7SRoi Dayan 	struct netlink_ext_ack *extack = parse_state->extack;
6667d62ee7SRoi Dayan 	struct mlx5e_tc_flow *flow = parse_state->flow;
6767d62ee7SRoi Dayan 
688be9686dSRoi Dayan 	if (validate_goto_chain(flow->priv, flow, attr, act, extack))
6967d62ee7SRoi Dayan 		return false;
7067d62ee7SRoi Dayan 
7167d62ee7SRoi Dayan 	return true;
7267d62ee7SRoi Dayan }
7367d62ee7SRoi Dayan 
7467d62ee7SRoi Dayan static int
tc_act_parse_goto(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)7567d62ee7SRoi Dayan tc_act_parse_goto(struct mlx5e_tc_act_parse_state *parse_state,
7667d62ee7SRoi Dayan 		  const struct flow_action_entry *act,
7767d62ee7SRoi Dayan 		  struct mlx5e_priv *priv,
7867d62ee7SRoi Dayan 		  struct mlx5_flow_attr *attr)
7967d62ee7SRoi Dayan {
802a829fe2SRoi Dayan 	attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
8167d62ee7SRoi Dayan 	attr->dest_chain = act->chain_index;
8267d62ee7SRoi Dayan 
8367d62ee7SRoi Dayan 	return 0;
8467d62ee7SRoi Dayan }
8567d62ee7SRoi Dayan 
8635bb5242SRoi Dayan static int
tc_act_post_parse_goto(struct mlx5e_tc_act_parse_state * parse_state,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)8735bb5242SRoi Dayan tc_act_post_parse_goto(struct mlx5e_tc_act_parse_state *parse_state,
8835bb5242SRoi Dayan 		       struct mlx5e_priv *priv,
8935bb5242SRoi Dayan 		       struct mlx5_flow_attr *attr)
9035bb5242SRoi Dayan {
9135bb5242SRoi Dayan 	struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
9235bb5242SRoi Dayan 	struct netlink_ext_ack *extack = parse_state->extack;
9335bb5242SRoi Dayan 	struct mlx5e_tc_flow *flow = parse_state->flow;
9435bb5242SRoi Dayan 
9535bb5242SRoi Dayan 	if (!attr->dest_chain)
9635bb5242SRoi Dayan 		return 0;
9735bb5242SRoi Dayan 
9835bb5242SRoi Dayan 	if (parse_state->decap) {
9935bb5242SRoi Dayan 		/* It can be supported if we'll create a mapping for
10035bb5242SRoi Dayan 		 * the tunnel device only (without tunnel), and set
10135bb5242SRoi Dayan 		 * this tunnel id with this decap flow.
10235bb5242SRoi Dayan 		 *
10335bb5242SRoi Dayan 		 * On restore (miss), we'll just set this saved tunnel
10435bb5242SRoi Dayan 		 * device.
10535bb5242SRoi Dayan 		 */
10635bb5242SRoi Dayan 
10735bb5242SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Decap with goto isn't supported");
10835bb5242SRoi Dayan 		netdev_warn(priv->netdev, "Decap with goto isn't supported");
10935bb5242SRoi Dayan 		return -EOPNOTSUPP;
11035bb5242SRoi Dayan 	}
11135bb5242SRoi Dayan 
11235bb5242SRoi Dayan 	if (!mlx5e_is_eswitch_flow(flow) && parse_attr->mirred_ifindex[0]) {
11335bb5242SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Mirroring goto chain rules isn't supported");
11435bb5242SRoi Dayan 		return -EOPNOTSUPP;
11535bb5242SRoi Dayan 	}
11635bb5242SRoi Dayan 
11735bb5242SRoi Dayan 	return 0;
11835bb5242SRoi Dayan }
11935bb5242SRoi Dayan 
12067d62ee7SRoi Dayan struct mlx5e_tc_act mlx5e_tc_act_goto = {
12167d62ee7SRoi Dayan 	.can_offload = tc_act_can_offload_goto,
12267d62ee7SRoi Dayan 	.parse_action = tc_act_parse_goto,
12335bb5242SRoi Dayan 	.post_parse = tc_act_post_parse_goto,
124*d3f6b0dfSOz Shlomo 	.is_terminating_action = true,
12567d62ee7SRoi Dayan };
126