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