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 8static int 9validate_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 59static bool 60tc_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 74static int 75tc_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 86static int 87tc_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 120struct 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