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