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