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