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 "eswitch.h"
7 
8 static int
9 validate_goto_chain(struct mlx5e_priv *priv,
10 		    struct mlx5e_tc_flow *flow,
11 		    const struct flow_action_entry *act,
12 		    struct netlink_ext_ack *extack)
13 {
14 	bool is_esw = mlx5e_is_eswitch_flow(flow);
15 	bool ft_flow = mlx5e_is_ft_flow(flow);
16 	u32 dest_chain = act->chain_index;
17 	struct mlx5_fs_chains *chains;
18 	struct mlx5_eswitch *esw;
19 	u32 reformat_and_fwd;
20 	u32 max_chain;
21 
22 	esw = priv->mdev->priv.eswitch;
23 	chains = is_esw ? esw_chains(esw) : mlx5e_nic_chains(priv);
24 	max_chain = mlx5_chains_get_chain_range(chains);
25 	reformat_and_fwd = is_esw ?
26 			   MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_and_fwd_to_table) :
27 			   MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, reformat_and_fwd_to_table);
28 
29 	if (ft_flow) {
30 		NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
31 		return -EOPNOTSUPP;
32 	}
33 
34 	if (!mlx5_chains_backwards_supported(chains) &&
35 	    dest_chain <= flow->attr->chain) {
36 		NL_SET_ERR_MSG_MOD(extack, "Goto lower numbered chain isn't supported");
37 		return -EOPNOTSUPP;
38 	}
39 
40 	if (dest_chain > max_chain) {
41 		NL_SET_ERR_MSG_MOD(extack,
42 				   "Requested destination chain is out of supported range");
43 		return -EOPNOTSUPP;
44 	}
45 
46 	if (flow->attr->action & (MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
47 				  MLX5_FLOW_CONTEXT_ACTION_DECAP) &&
48 	    !reformat_and_fwd) {
49 		NL_SET_ERR_MSG_MOD(extack,
50 				   "Goto chain is not allowed if action has reformat or decap");
51 		return -EOPNOTSUPP;
52 	}
53 
54 	return 0;
55 }
56 
57 static bool
58 tc_act_can_offload_goto(struct mlx5e_tc_act_parse_state *parse_state,
59 			const struct flow_action_entry *act,
60 			int act_index)
61 {
62 	struct netlink_ext_ack *extack = parse_state->extack;
63 	struct mlx5e_tc_flow *flow = parse_state->flow;
64 
65 	if (validate_goto_chain(flow->priv, flow, act, extack))
66 		return false;
67 
68 	return true;
69 }
70 
71 static int
72 tc_act_parse_goto(struct mlx5e_tc_act_parse_state *parse_state,
73 		  const struct flow_action_entry *act,
74 		  struct mlx5e_priv *priv,
75 		  struct mlx5_flow_attr *attr)
76 {
77 	attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
78 			MLX5_FLOW_CONTEXT_ACTION_COUNT;
79 	attr->dest_chain = act->chain_index;
80 
81 	return 0;
82 }
83 
84 static int
85 tc_act_post_parse_goto(struct mlx5e_tc_act_parse_state *parse_state,
86 		       struct mlx5e_priv *priv,
87 		       struct mlx5_flow_attr *attr)
88 {
89 	struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
90 	struct netlink_ext_ack *extack = parse_state->extack;
91 	struct mlx5e_tc_flow *flow = parse_state->flow;
92 
93 	if (!attr->dest_chain)
94 		return 0;
95 
96 	if (parse_state->decap) {
97 		/* It can be supported if we'll create a mapping for
98 		 * the tunnel device only (without tunnel), and set
99 		 * this tunnel id with this decap flow.
100 		 *
101 		 * On restore (miss), we'll just set this saved tunnel
102 		 * device.
103 		 */
104 
105 		NL_SET_ERR_MSG_MOD(extack, "Decap with goto isn't supported");
106 		netdev_warn(priv->netdev, "Decap with goto isn't supported");
107 		return -EOPNOTSUPP;
108 	}
109 
110 	if (!mlx5e_is_eswitch_flow(flow) && parse_attr->mirred_ifindex[0]) {
111 		NL_SET_ERR_MSG_MOD(extack, "Mirroring goto chain rules isn't supported");
112 		return -EOPNOTSUPP;
113 	}
114 
115 	return 0;
116 }
117 
118 struct mlx5e_tc_act mlx5e_tc_act_goto = {
119 	.can_offload = tc_act_can_offload_goto,
120 	.parse_action = tc_act_parse_goto,
121 	.post_parse = tc_act_post_parse_goto,
122 };
123