spectrum_acl_flex_actions.c (9028B)
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 3 4#include "spectrum_acl_flex_actions.h" 5#include "core_acl_flex_actions.h" 6#include "spectrum_span.h" 7 8static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, 9 char *enc_actions, bool is_first, bool ca) 10{ 11 struct mlxsw_sp *mlxsw_sp = priv; 12 char pefa_pl[MLXSW_REG_PEFA_LEN]; 13 u32 kvdl_index; 14 int err; 15 16 /* The first action set of a TCAM entry is stored directly in TCAM, 17 * not KVD linear area. 18 */ 19 if (is_first) 20 return 0; 21 22 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, 23 1, &kvdl_index); 24 if (err) 25 return err; 26 mlxsw_reg_pefa_pack(pefa_pl, kvdl_index, ca, enc_actions); 27 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl); 28 if (err) 29 goto err_pefa_write; 30 *p_kvdl_index = kvdl_index; 31 return 0; 32 33err_pefa_write: 34 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, 35 1, kvdl_index); 36 return err; 37} 38 39static int mlxsw_sp1_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, 40 char *enc_actions, bool is_first) 41{ 42 return mlxsw_sp_act_kvdl_set_add(priv, p_kvdl_index, enc_actions, 43 is_first, false); 44} 45 46static int mlxsw_sp2_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, 47 char *enc_actions, bool is_first) 48{ 49 return mlxsw_sp_act_kvdl_set_add(priv, p_kvdl_index, enc_actions, 50 is_first, true); 51} 52 53static void mlxsw_sp_act_kvdl_set_del(void *priv, u32 kvdl_index, 54 bool is_first) 55{ 56 struct mlxsw_sp *mlxsw_sp = priv; 57 58 if (is_first) 59 return; 60 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, 61 1, kvdl_index); 62} 63 64static int mlxsw_sp1_act_kvdl_set_activity_get(void *priv, u32 kvdl_index, 65 bool *activity) 66{ 67 return -EOPNOTSUPP; 68} 69 70static int mlxsw_sp2_act_kvdl_set_activity_get(void *priv, u32 kvdl_index, 71 bool *activity) 72{ 73 struct mlxsw_sp *mlxsw_sp = priv; 74 char pefa_pl[MLXSW_REG_PEFA_LEN]; 75 int err; 76 77 mlxsw_reg_pefa_pack(pefa_pl, kvdl_index, true, NULL); 78 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl); 79 if (err) 80 return err; 81 mlxsw_reg_pefa_unpack(pefa_pl, activity); 82 return 0; 83} 84 85static int mlxsw_sp_act_kvdl_fwd_entry_add(void *priv, u32 *p_kvdl_index, 86 u16 local_port) 87{ 88 struct mlxsw_sp *mlxsw_sp = priv; 89 char ppbs_pl[MLXSW_REG_PPBS_LEN]; 90 u32 kvdl_index; 91 int err; 92 93 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS, 94 1, &kvdl_index); 95 if (err) 96 return err; 97 mlxsw_reg_ppbs_pack(ppbs_pl, kvdl_index, local_port); 98 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppbs), ppbs_pl); 99 if (err) 100 goto err_ppbs_write; 101 *p_kvdl_index = kvdl_index; 102 return 0; 103 104err_ppbs_write: 105 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS, 106 1, kvdl_index); 107 return err; 108} 109 110static void mlxsw_sp_act_kvdl_fwd_entry_del(void *priv, u32 kvdl_index) 111{ 112 struct mlxsw_sp *mlxsw_sp = priv; 113 114 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS, 115 1, kvdl_index); 116} 117 118static int 119mlxsw_sp_act_counter_index_get(void *priv, unsigned int *p_counter_index) 120{ 121 struct mlxsw_sp *mlxsw_sp = priv; 122 123 return mlxsw_sp_flow_counter_alloc(mlxsw_sp, p_counter_index); 124} 125 126static void 127mlxsw_sp_act_counter_index_put(void *priv, unsigned int counter_index) 128{ 129 struct mlxsw_sp *mlxsw_sp = priv; 130 131 mlxsw_sp_flow_counter_free(mlxsw_sp, counter_index); 132} 133 134static int 135mlxsw_sp_act_mirror_add(void *priv, u16 local_in_port, 136 const struct net_device *out_dev, 137 bool ingress, int *p_span_id) 138{ 139 struct mlxsw_sp_span_agent_parms agent_parms = {}; 140 struct mlxsw_sp_port *mlxsw_sp_port; 141 struct mlxsw_sp *mlxsw_sp = priv; 142 int err; 143 144 agent_parms.to_dev = out_dev; 145 err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, &agent_parms); 146 if (err) 147 return err; 148 149 mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; 150 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); 151 if (err) 152 goto err_analyzed_port_get; 153 154 return 0; 155 156err_analyzed_port_get: 157 mlxsw_sp_span_agent_put(mlxsw_sp, *p_span_id); 158 return err; 159} 160 161static void 162mlxsw_sp_act_mirror_del(void *priv, u16 local_in_port, int span_id, bool ingress) 163{ 164 struct mlxsw_sp_port *mlxsw_sp_port; 165 struct mlxsw_sp *mlxsw_sp = priv; 166 167 mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; 168 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); 169 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 170} 171 172static int mlxsw_sp_act_policer_add(void *priv, u64 rate_bytes_ps, u32 burst, 173 u16 *p_policer_index, 174 struct netlink_ext_ack *extack) 175{ 176 struct mlxsw_sp_policer_params params; 177 struct mlxsw_sp *mlxsw_sp = priv; 178 179 params.rate = rate_bytes_ps; 180 params.burst = burst; 181 params.bytes = true; 182 return mlxsw_sp_policer_add(mlxsw_sp, 183 MLXSW_SP_POLICER_TYPE_SINGLE_RATE, 184 ¶ms, extack, p_policer_index); 185} 186 187static void mlxsw_sp_act_policer_del(void *priv, u16 policer_index) 188{ 189 struct mlxsw_sp *mlxsw_sp = priv; 190 191 mlxsw_sp_policer_del(mlxsw_sp, MLXSW_SP_POLICER_TYPE_SINGLE_RATE, 192 policer_index); 193} 194 195static int mlxsw_sp1_act_sampler_add(void *priv, u16 local_port, 196 struct psample_group *psample_group, 197 u32 rate, u32 trunc_size, bool truncate, 198 bool ingress, int *p_span_id, 199 struct netlink_ext_ack *extack) 200{ 201 NL_SET_ERR_MSG_MOD(extack, "Sampling action is not supported on Spectrum-1"); 202 return -EOPNOTSUPP; 203} 204 205static void mlxsw_sp1_act_sampler_del(void *priv, u16 local_port, int span_id, 206 bool ingress) 207{ 208 WARN_ON_ONCE(1); 209} 210 211const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { 212 .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, 213 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 214 .kvdl_set_activity_get = mlxsw_sp1_act_kvdl_set_activity_get, 215 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 216 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 217 .counter_index_get = mlxsw_sp_act_counter_index_get, 218 .counter_index_put = mlxsw_sp_act_counter_index_put, 219 .mirror_add = mlxsw_sp_act_mirror_add, 220 .mirror_del = mlxsw_sp_act_mirror_del, 221 .policer_add = mlxsw_sp_act_policer_add, 222 .policer_del = mlxsw_sp_act_policer_del, 223 .sampler_add = mlxsw_sp1_act_sampler_add, 224 .sampler_del = mlxsw_sp1_act_sampler_del, 225}; 226 227static int mlxsw_sp2_act_sampler_add(void *priv, u16 local_port, 228 struct psample_group *psample_group, 229 u32 rate, u32 trunc_size, bool truncate, 230 bool ingress, int *p_span_id, 231 struct netlink_ext_ack *extack) 232{ 233 struct mlxsw_sp_span_agent_parms agent_parms = { 234 .session_id = MLXSW_SP_SPAN_SESSION_ID_SAMPLING, 235 }; 236 struct mlxsw_sp_sample_trigger trigger = { 237 .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 238 }; 239 struct mlxsw_sp_sample_params params; 240 struct mlxsw_sp_port *mlxsw_sp_port; 241 struct mlxsw_sp *mlxsw_sp = priv; 242 int err; 243 244 params.psample_group = psample_group; 245 params.trunc_size = trunc_size; 246 params.rate = rate; 247 params.truncate = truncate; 248 err = mlxsw_sp_sample_trigger_params_set(mlxsw_sp, &trigger, ¶ms, 249 extack); 250 if (err) 251 return err; 252 253 err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, &agent_parms); 254 if (err) { 255 NL_SET_ERR_MSG_MOD(extack, "Failed to get SPAN agent"); 256 goto err_span_agent_get; 257 } 258 259 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 260 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); 261 if (err) { 262 NL_SET_ERR_MSG_MOD(extack, "Failed to get analyzed port"); 263 goto err_analyzed_port_get; 264 } 265 266 return 0; 267 268err_analyzed_port_get: 269 mlxsw_sp_span_agent_put(mlxsw_sp, *p_span_id); 270err_span_agent_get: 271 mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 272 return err; 273} 274 275static void mlxsw_sp2_act_sampler_del(void *priv, u16 local_port, int span_id, 276 bool ingress) 277{ 278 struct mlxsw_sp_sample_trigger trigger = { 279 .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 280 }; 281 struct mlxsw_sp_port *mlxsw_sp_port; 282 struct mlxsw_sp *mlxsw_sp = priv; 283 284 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 285 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); 286 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 287 mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 288} 289 290const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { 291 .kvdl_set_add = mlxsw_sp2_act_kvdl_set_add, 292 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 293 .kvdl_set_activity_get = mlxsw_sp2_act_kvdl_set_activity_get, 294 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 295 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 296 .counter_index_get = mlxsw_sp_act_counter_index_get, 297 .counter_index_put = mlxsw_sp_act_counter_index_put, 298 .mirror_add = mlxsw_sp_act_mirror_add, 299 .mirror_del = mlxsw_sp_act_mirror_del, 300 .policer_add = mlxsw_sp_act_policer_add, 301 .policer_del = mlxsw_sp_act_policer_del, 302 .sampler_add = mlxsw_sp2_act_sampler_add, 303 .sampler_del = mlxsw_sp2_act_sampler_del, 304 .dummy_first_set = true, 305}; 306 307int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) 308{ 309 mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, 310 ACL_ACTIONS_PER_SET), 311 mlxsw_sp->afa_ops, mlxsw_sp); 312 return PTR_ERR_OR_ZERO(mlxsw_sp->afa); 313} 314 315void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) 316{ 317 mlxsw_afa_destroy(mlxsw_sp->afa); 318}