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 "fs_core.h" 7 8static bool police_act_validate_control(enum flow_action_id act_id, 9 struct netlink_ext_ack *extack) 10{ 11 if (act_id != FLOW_ACTION_PIPE && 12 act_id != FLOW_ACTION_ACCEPT && 13 act_id != FLOW_ACTION_JUMP && 14 act_id != FLOW_ACTION_DROP) { 15 NL_SET_ERR_MSG_MOD(extack, 16 "Offload not supported when conform-exceed action is not pipe, ok, jump or drop"); 17 return false; 18 } 19 20 return true; 21} 22 23static int police_act_validate(const struct flow_action_entry *act, 24 struct netlink_ext_ack *extack) 25{ 26 if (!police_act_validate_control(act->police.exceed.act_id, extack) || 27 !police_act_validate_control(act->police.notexceed.act_id, extack)) 28 return -EOPNOTSUPP; 29 30 if (act->police.peakrate_bytes_ps || 31 act->police.avrate || act->police.overhead) { 32 NL_SET_ERR_MSG_MOD(extack, 33 "Offload not supported when peakrate/avrate/overhead is configured"); 34 return -EOPNOTSUPP; 35 } 36 37 return 0; 38} 39 40static bool 41tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state, 42 const struct flow_action_entry *act, 43 int act_index, 44 struct mlx5_flow_attr *attr) 45{ 46 int err; 47 48 err = police_act_validate(act, parse_state->extack); 49 if (err) 50 return false; 51 52 return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev); 53} 54 55static int 56fill_meter_params_from_act(const struct flow_action_entry *act, 57 struct mlx5e_flow_meter_params *params) 58{ 59 params->index = act->hw_index; 60 if (act->police.rate_bytes_ps) { 61 params->mode = MLX5_RATE_LIMIT_BPS; 62 /* change rate to bits per second */ 63 params->rate = act->police.rate_bytes_ps << 3; 64 params->burst = act->police.burst; 65 } else if (act->police.rate_pkt_ps) { 66 params->mode = MLX5_RATE_LIMIT_PPS; 67 params->rate = act->police.rate_pkt_ps; 68 params->burst = act->police.burst_pkt; 69 } else if (act->police.mtu) { 70 params->mtu = act->police.mtu; 71 } else { 72 return -EOPNOTSUPP; 73 } 74 75 return 0; 76} 77 78static int 79tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state, 80 const struct flow_action_entry *act, 81 struct mlx5e_priv *priv, 82 struct mlx5_flow_attr *attr) 83{ 84 enum mlx5_flow_namespace_type ns = mlx5e_get_flow_namespace(parse_state->flow); 85 struct mlx5e_flow_meter_params *params = &attr->meter_attr.params; 86 int err; 87 88 err = fill_meter_params_from_act(act, params); 89 if (err) 90 return err; 91 92 if (params->mtu) { 93 if (!(mlx5_fs_get_capabilities(priv->mdev, ns) & 94 MLX5_FLOW_STEERING_CAP_MATCH_RANGES)) 95 return -EOPNOTSUPP; 96 97 attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 98 attr->flags |= MLX5_ATTR_FLAG_MTU; 99 } else { 100 attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO; 101 attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER; 102 } 103 104 return 0; 105} 106 107static bool 108tc_act_is_multi_table_act_police(struct mlx5e_priv *priv, 109 const struct flow_action_entry *act, 110 struct mlx5_flow_attr *attr) 111{ 112 return true; 113} 114 115static int 116tc_act_police_offload(struct mlx5e_priv *priv, 117 struct flow_offload_action *fl_act, 118 struct flow_action_entry *act) 119{ 120 struct mlx5e_flow_meter_params params = {}; 121 struct mlx5e_flow_meter_handle *meter; 122 int err = 0; 123 124 err = police_act_validate(act, fl_act->extack); 125 if (err) 126 return err; 127 128 err = fill_meter_params_from_act(act, ¶ms); 129 if (err) 130 return err; 131 132 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms); 133 if (IS_ERR(meter) && PTR_ERR(meter) == -ENOENT) { 134 meter = mlx5e_tc_meter_replace(priv->mdev, ¶ms); 135 } else if (!IS_ERR(meter)) { 136 err = mlx5e_tc_meter_update(meter, ¶ms); 137 mlx5e_tc_meter_put(meter); 138 } 139 140 if (IS_ERR(meter)) { 141 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter"); 142 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index); 143 err = PTR_ERR(meter); 144 } 145 146 return err; 147} 148 149static int 150tc_act_police_destroy(struct mlx5e_priv *priv, 151 struct flow_offload_action *fl_act) 152{ 153 struct mlx5e_flow_meter_params params = {}; 154 struct mlx5e_flow_meter_handle *meter; 155 156 params.index = fl_act->index; 157 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms); 158 if (IS_ERR(meter)) { 159 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter"); 160 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index); 161 return PTR_ERR(meter); 162 } 163 /* first put for the get and second for cleanup */ 164 mlx5e_tc_meter_put(meter); 165 mlx5e_tc_meter_put(meter); 166 return 0; 167} 168 169static int 170tc_act_police_stats(struct mlx5e_priv *priv, 171 struct flow_offload_action *fl_act) 172{ 173 struct mlx5e_flow_meter_params params = {}; 174 struct mlx5e_flow_meter_handle *meter; 175 u64 bytes, packets, drops, lastuse; 176 177 params.index = fl_act->index; 178 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms); 179 if (IS_ERR(meter)) { 180 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter"); 181 return PTR_ERR(meter); 182 } 183 184 mlx5e_tc_meter_get_stats(meter, &bytes, &packets, &drops, &lastuse); 185 flow_stats_update(&fl_act->stats, bytes, packets, drops, lastuse, 186 FLOW_ACTION_HW_STATS_DELAYED); 187 mlx5e_tc_meter_put(meter); 188 return 0; 189} 190 191static bool 192tc_act_police_get_branch_ctrl(const struct flow_action_entry *act, 193 struct mlx5e_tc_act_branch_ctrl *cond_true, 194 struct mlx5e_tc_act_branch_ctrl *cond_false) 195{ 196 cond_true->act_id = act->police.notexceed.act_id; 197 cond_true->extval = act->police.notexceed.extval; 198 199 cond_false->act_id = act->police.exceed.act_id; 200 cond_false->extval = act->police.exceed.extval; 201 return true; 202} 203 204struct mlx5e_tc_act mlx5e_tc_act_police = { 205 .can_offload = tc_act_can_offload_police, 206 .parse_action = tc_act_parse_police, 207 .is_multi_table_act = tc_act_is_multi_table_act_police, 208 .offload_action = tc_act_police_offload, 209 .destroy_action = tc_act_police_destroy, 210 .stats_action = tc_act_police_stats, 211 .get_branch_ctrl = tc_act_police_get_branch_ctrl, 212}; 213