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