1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/types.h> 6 #include <linux/slab.h> 7 #include <linux/errno.h> 8 #include <linux/rhashtable.h> 9 #include <linux/list.h> 10 #include <linux/idr.h> 11 #include <linux/refcount.h> 12 #include <net/flow_offload.h> 13 14 #include "item.h" 15 #include "trap.h" 16 #include "core_acl_flex_actions.h" 17 18 enum mlxsw_afa_set_type { 19 MLXSW_AFA_SET_TYPE_NEXT, 20 MLXSW_AFA_SET_TYPE_GOTO, 21 }; 22 23 /* afa_set_type 24 * Type of the record at the end of the action set. 25 */ 26 MLXSW_ITEM32(afa, set, type, 0xA0, 28, 4); 27 28 /* afa_set_next_action_set_ptr 29 * A pointer to the next action set in the KVD Centralized database. 30 */ 31 MLXSW_ITEM32(afa, set, next_action_set_ptr, 0xA4, 0, 24); 32 33 /* afa_set_goto_g 34 * group - When set, the binding is of an ACL group. When cleared, 35 * the binding is of an ACL. 36 * Must be set to 1 for Spectrum. 37 */ 38 MLXSW_ITEM32(afa, set, goto_g, 0xA4, 29, 1); 39 40 enum mlxsw_afa_set_goto_binding_cmd { 41 /* continue go the next binding point */ 42 MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE, 43 /* jump to the next binding point no return */ 44 MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP, 45 /* terminate the acl binding */ 46 MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM = 4, 47 }; 48 49 /* afa_set_goto_binding_cmd */ 50 MLXSW_ITEM32(afa, set, goto_binding_cmd, 0xA4, 24, 3); 51 52 /* afa_set_goto_next_binding 53 * ACL/ACL group identifier. If the g bit is set, this field should hold 54 * the acl_group_id, else it should hold the acl_id. 55 */ 56 MLXSW_ITEM32(afa, set, goto_next_binding, 0xA4, 0, 16); 57 58 /* afa_all_action_type 59 * Action Type. 60 */ 61 MLXSW_ITEM32(afa, all, action_type, 0x00, 24, 6); 62 63 struct mlxsw_afa { 64 unsigned int max_acts_per_set; 65 const struct mlxsw_afa_ops *ops; 66 void *ops_priv; 67 struct rhashtable set_ht; 68 struct rhashtable fwd_entry_ht; 69 struct rhashtable cookie_ht; 70 struct rhashtable policer_ht; 71 struct idr cookie_idr; 72 struct list_head policer_list; 73 }; 74 75 #define MLXSW_AFA_SET_LEN 0xA8 76 77 struct mlxsw_afa_set_ht_key { 78 char enc_actions[MLXSW_AFA_SET_LEN]; /* Encoded set */ 79 bool is_first; 80 }; 81 82 /* Set structure holds one action set record. It contains up to three 83 * actions (depends on size of particular actions). The set is either 84 * put directly to a rule, or it is stored in KVD linear area. 85 * To prevent duplicate entries in KVD linear area, a hashtable is 86 * used to track sets that were previously inserted and may be shared. 87 */ 88 89 struct mlxsw_afa_set { 90 struct rhash_head ht_node; 91 struct mlxsw_afa_set_ht_key ht_key; 92 u32 kvdl_index; 93 u8 shared:1, /* Inserted in hashtable (doesn't mean that 94 * kvdl_index is valid). 95 */ 96 has_trap:1, 97 has_police:1; 98 refcount_t ref_count; 99 struct mlxsw_afa_set *next; /* Pointer to the next set. */ 100 struct mlxsw_afa_set *prev; /* Pointer to the previous set, 101 * note that set may have multiple 102 * sets from multiple blocks 103 * pointing at it. This is only 104 * usable until commit. 105 */ 106 }; 107 108 static const struct rhashtable_params mlxsw_afa_set_ht_params = { 109 .key_len = sizeof(struct mlxsw_afa_set_ht_key), 110 .key_offset = offsetof(struct mlxsw_afa_set, ht_key), 111 .head_offset = offsetof(struct mlxsw_afa_set, ht_node), 112 .automatic_shrinking = true, 113 }; 114 115 struct mlxsw_afa_fwd_entry_ht_key { 116 u16 local_port; 117 }; 118 119 struct mlxsw_afa_fwd_entry { 120 struct rhash_head ht_node; 121 struct mlxsw_afa_fwd_entry_ht_key ht_key; 122 u32 kvdl_index; 123 refcount_t ref_count; 124 }; 125 126 static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = { 127 .key_len = sizeof(struct mlxsw_afa_fwd_entry_ht_key), 128 .key_offset = offsetof(struct mlxsw_afa_fwd_entry, ht_key), 129 .head_offset = offsetof(struct mlxsw_afa_fwd_entry, ht_node), 130 .automatic_shrinking = true, 131 }; 132 133 struct mlxsw_afa_cookie { 134 struct rhash_head ht_node; 135 refcount_t ref_count; 136 struct rcu_head rcu; 137 u32 cookie_index; 138 struct flow_action_cookie fa_cookie; 139 }; 140 mlxsw_afa_cookie_hash(const struct flow_action_cookie * fa_cookie,u32 seed)141 static u32 mlxsw_afa_cookie_hash(const struct flow_action_cookie *fa_cookie, 142 u32 seed) 143 { 144 return jhash2((u32 *) fa_cookie->cookie, 145 fa_cookie->cookie_len / sizeof(u32), seed); 146 } 147 mlxsw_afa_cookie_key_hashfn(const void * data,u32 len,u32 seed)148 static u32 mlxsw_afa_cookie_key_hashfn(const void *data, u32 len, u32 seed) 149 { 150 const struct flow_action_cookie *fa_cookie = data; 151 152 return mlxsw_afa_cookie_hash(fa_cookie, seed); 153 } 154 mlxsw_afa_cookie_obj_hashfn(const void * data,u32 len,u32 seed)155 static u32 mlxsw_afa_cookie_obj_hashfn(const void *data, u32 len, u32 seed) 156 { 157 const struct mlxsw_afa_cookie *cookie = data; 158 159 return mlxsw_afa_cookie_hash(&cookie->fa_cookie, seed); 160 } 161 mlxsw_afa_cookie_obj_cmpfn(struct rhashtable_compare_arg * arg,const void * obj)162 static int mlxsw_afa_cookie_obj_cmpfn(struct rhashtable_compare_arg *arg, 163 const void *obj) 164 { 165 const struct flow_action_cookie *fa_cookie = arg->key; 166 const struct mlxsw_afa_cookie *cookie = obj; 167 168 if (cookie->fa_cookie.cookie_len == fa_cookie->cookie_len) 169 return memcmp(cookie->fa_cookie.cookie, fa_cookie->cookie, 170 fa_cookie->cookie_len); 171 return 1; 172 } 173 174 static const struct rhashtable_params mlxsw_afa_cookie_ht_params = { 175 .head_offset = offsetof(struct mlxsw_afa_cookie, ht_node), 176 .hashfn = mlxsw_afa_cookie_key_hashfn, 177 .obj_hashfn = mlxsw_afa_cookie_obj_hashfn, 178 .obj_cmpfn = mlxsw_afa_cookie_obj_cmpfn, 179 .automatic_shrinking = true, 180 }; 181 182 struct mlxsw_afa_policer { 183 struct rhash_head ht_node; 184 struct list_head list; /* Member of policer_list */ 185 refcount_t ref_count; 186 u32 fa_index; 187 u16 policer_index; 188 }; 189 190 static const struct rhashtable_params mlxsw_afa_policer_ht_params = { 191 .key_len = sizeof(u32), 192 .key_offset = offsetof(struct mlxsw_afa_policer, fa_index), 193 .head_offset = offsetof(struct mlxsw_afa_policer, ht_node), 194 .automatic_shrinking = true, 195 }; 196 mlxsw_afa_create(unsigned int max_acts_per_set,const struct mlxsw_afa_ops * ops,void * ops_priv)197 struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set, 198 const struct mlxsw_afa_ops *ops, 199 void *ops_priv) 200 { 201 struct mlxsw_afa *mlxsw_afa; 202 int err; 203 204 mlxsw_afa = kzalloc(sizeof(*mlxsw_afa), GFP_KERNEL); 205 if (!mlxsw_afa) 206 return ERR_PTR(-ENOMEM); 207 err = rhashtable_init(&mlxsw_afa->set_ht, &mlxsw_afa_set_ht_params); 208 if (err) 209 goto err_set_rhashtable_init; 210 err = rhashtable_init(&mlxsw_afa->fwd_entry_ht, 211 &mlxsw_afa_fwd_entry_ht_params); 212 if (err) 213 goto err_fwd_entry_rhashtable_init; 214 err = rhashtable_init(&mlxsw_afa->cookie_ht, 215 &mlxsw_afa_cookie_ht_params); 216 if (err) 217 goto err_cookie_rhashtable_init; 218 err = rhashtable_init(&mlxsw_afa->policer_ht, 219 &mlxsw_afa_policer_ht_params); 220 if (err) 221 goto err_policer_rhashtable_init; 222 idr_init(&mlxsw_afa->cookie_idr); 223 INIT_LIST_HEAD(&mlxsw_afa->policer_list); 224 mlxsw_afa->max_acts_per_set = max_acts_per_set; 225 mlxsw_afa->ops = ops; 226 mlxsw_afa->ops_priv = ops_priv; 227 return mlxsw_afa; 228 229 err_policer_rhashtable_init: 230 rhashtable_destroy(&mlxsw_afa->cookie_ht); 231 err_cookie_rhashtable_init: 232 rhashtable_destroy(&mlxsw_afa->fwd_entry_ht); 233 err_fwd_entry_rhashtable_init: 234 rhashtable_destroy(&mlxsw_afa->set_ht); 235 err_set_rhashtable_init: 236 kfree(mlxsw_afa); 237 return ERR_PTR(err); 238 } 239 EXPORT_SYMBOL(mlxsw_afa_create); 240 mlxsw_afa_destroy(struct mlxsw_afa * mlxsw_afa)241 void mlxsw_afa_destroy(struct mlxsw_afa *mlxsw_afa) 242 { 243 WARN_ON(!list_empty(&mlxsw_afa->policer_list)); 244 WARN_ON(!idr_is_empty(&mlxsw_afa->cookie_idr)); 245 idr_destroy(&mlxsw_afa->cookie_idr); 246 rhashtable_destroy(&mlxsw_afa->policer_ht); 247 rhashtable_destroy(&mlxsw_afa->cookie_ht); 248 rhashtable_destroy(&mlxsw_afa->fwd_entry_ht); 249 rhashtable_destroy(&mlxsw_afa->set_ht); 250 kfree(mlxsw_afa); 251 } 252 EXPORT_SYMBOL(mlxsw_afa_destroy); 253 mlxsw_afa_set_goto_set(struct mlxsw_afa_set * set,enum mlxsw_afa_set_goto_binding_cmd cmd,u16 group_id)254 static void mlxsw_afa_set_goto_set(struct mlxsw_afa_set *set, 255 enum mlxsw_afa_set_goto_binding_cmd cmd, 256 u16 group_id) 257 { 258 char *actions = set->ht_key.enc_actions; 259 260 mlxsw_afa_set_type_set(actions, MLXSW_AFA_SET_TYPE_GOTO); 261 mlxsw_afa_set_goto_g_set(actions, true); 262 mlxsw_afa_set_goto_binding_cmd_set(actions, cmd); 263 mlxsw_afa_set_goto_next_binding_set(actions, group_id); 264 } 265 mlxsw_afa_set_next_set(struct mlxsw_afa_set * set,u32 next_set_kvdl_index)266 static void mlxsw_afa_set_next_set(struct mlxsw_afa_set *set, 267 u32 next_set_kvdl_index) 268 { 269 char *actions = set->ht_key.enc_actions; 270 271 mlxsw_afa_set_type_set(actions, MLXSW_AFA_SET_TYPE_NEXT); 272 mlxsw_afa_set_next_action_set_ptr_set(actions, next_set_kvdl_index); 273 } 274 mlxsw_afa_set_create(bool is_first)275 static struct mlxsw_afa_set *mlxsw_afa_set_create(bool is_first) 276 { 277 struct mlxsw_afa_set *set; 278 279 set = kzalloc(sizeof(*set), GFP_KERNEL); 280 if (!set) 281 return NULL; 282 /* Need to initialize the set to pass by default */ 283 mlxsw_afa_set_goto_set(set, MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0); 284 set->ht_key.is_first = is_first; 285 refcount_set(&set->ref_count, 1); 286 return set; 287 } 288 mlxsw_afa_set_destroy(struct mlxsw_afa_set * set)289 static void mlxsw_afa_set_destroy(struct mlxsw_afa_set *set) 290 { 291 kfree(set); 292 } 293 mlxsw_afa_set_share(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_set * set)294 static int mlxsw_afa_set_share(struct mlxsw_afa *mlxsw_afa, 295 struct mlxsw_afa_set *set) 296 { 297 int err; 298 299 err = rhashtable_insert_fast(&mlxsw_afa->set_ht, &set->ht_node, 300 mlxsw_afa_set_ht_params); 301 if (err) 302 return err; 303 err = mlxsw_afa->ops->kvdl_set_add(mlxsw_afa->ops_priv, 304 &set->kvdl_index, 305 set->ht_key.enc_actions, 306 set->ht_key.is_first); 307 if (err) 308 goto err_kvdl_set_add; 309 set->shared = true; 310 set->prev = NULL; 311 return 0; 312 313 err_kvdl_set_add: 314 rhashtable_remove_fast(&mlxsw_afa->set_ht, &set->ht_node, 315 mlxsw_afa_set_ht_params); 316 return err; 317 } 318 mlxsw_afa_set_unshare(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_set * set)319 static void mlxsw_afa_set_unshare(struct mlxsw_afa *mlxsw_afa, 320 struct mlxsw_afa_set *set) 321 { 322 mlxsw_afa->ops->kvdl_set_del(mlxsw_afa->ops_priv, 323 set->kvdl_index, 324 set->ht_key.is_first); 325 rhashtable_remove_fast(&mlxsw_afa->set_ht, &set->ht_node, 326 mlxsw_afa_set_ht_params); 327 set->shared = false; 328 } 329 mlxsw_afa_set_put(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_set * set)330 static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa, 331 struct mlxsw_afa_set *set) 332 { 333 if (!refcount_dec_and_test(&set->ref_count)) 334 return; 335 if (set->shared) 336 mlxsw_afa_set_unshare(mlxsw_afa, set); 337 mlxsw_afa_set_destroy(set); 338 } 339 mlxsw_afa_set_get(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_set * orig_set)340 static struct mlxsw_afa_set *mlxsw_afa_set_get(struct mlxsw_afa *mlxsw_afa, 341 struct mlxsw_afa_set *orig_set) 342 { 343 struct mlxsw_afa_set *set; 344 int err; 345 346 /* There is a hashtable of sets maintained. If a set with the exact 347 * same encoding exists, we reuse it. Otherwise, the current set 348 * is shared by making it available to others using the hash table. 349 */ 350 set = rhashtable_lookup_fast(&mlxsw_afa->set_ht, &orig_set->ht_key, 351 mlxsw_afa_set_ht_params); 352 if (set) { 353 refcount_inc(&set->ref_count); 354 mlxsw_afa_set_put(mlxsw_afa, orig_set); 355 } else { 356 set = orig_set; 357 err = mlxsw_afa_set_share(mlxsw_afa, set); 358 if (err) 359 return ERR_PTR(err); 360 } 361 return set; 362 } 363 364 /* Block structure holds a list of action sets. One action block 365 * represents one chain of actions executed upon match of a rule. 366 */ 367 368 struct mlxsw_afa_block { 369 struct mlxsw_afa *afa; 370 bool finished; 371 struct mlxsw_afa_set *first_set; 372 struct mlxsw_afa_set *cur_set; 373 unsigned int cur_act_index; /* In current set. */ 374 struct list_head resource_list; /* List of resources held by actions 375 * in this block. 376 */ 377 }; 378 379 struct mlxsw_afa_resource { 380 struct list_head list; 381 void (*destructor)(struct mlxsw_afa_block *block, 382 struct mlxsw_afa_resource *resource); 383 }; 384 mlxsw_afa_resource_add(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)385 static void mlxsw_afa_resource_add(struct mlxsw_afa_block *block, 386 struct mlxsw_afa_resource *resource) 387 { 388 list_add(&resource->list, &block->resource_list); 389 } 390 mlxsw_afa_resource_del(struct mlxsw_afa_resource * resource)391 static void mlxsw_afa_resource_del(struct mlxsw_afa_resource *resource) 392 { 393 list_del(&resource->list); 394 } 395 mlxsw_afa_resources_destroy(struct mlxsw_afa_block * block)396 static void mlxsw_afa_resources_destroy(struct mlxsw_afa_block *block) 397 { 398 struct mlxsw_afa_resource *resource, *tmp; 399 400 list_for_each_entry_safe(resource, tmp, &block->resource_list, list) { 401 resource->destructor(block, resource); 402 } 403 } 404 mlxsw_afa_block_create(struct mlxsw_afa * mlxsw_afa)405 struct mlxsw_afa_block *mlxsw_afa_block_create(struct mlxsw_afa *mlxsw_afa) 406 { 407 struct mlxsw_afa_block *block; 408 409 block = kzalloc(sizeof(*block), GFP_KERNEL); 410 if (!block) 411 return ERR_PTR(-ENOMEM); 412 INIT_LIST_HEAD(&block->resource_list); 413 block->afa = mlxsw_afa; 414 415 /* At least one action set is always present, so just create it here */ 416 block->first_set = mlxsw_afa_set_create(true); 417 if (!block->first_set) 418 goto err_first_set_create; 419 420 /* In case user instructs to have dummy first set, we leave it 421 * empty here and create another, real, set right away. 422 */ 423 if (mlxsw_afa->ops->dummy_first_set) { 424 block->cur_set = mlxsw_afa_set_create(false); 425 if (!block->cur_set) 426 goto err_second_set_create; 427 block->cur_set->prev = block->first_set; 428 block->first_set->next = block->cur_set; 429 } else { 430 block->cur_set = block->first_set; 431 } 432 433 return block; 434 435 err_second_set_create: 436 mlxsw_afa_set_destroy(block->first_set); 437 err_first_set_create: 438 kfree(block); 439 return ERR_PTR(-ENOMEM); 440 } 441 EXPORT_SYMBOL(mlxsw_afa_block_create); 442 mlxsw_afa_block_destroy(struct mlxsw_afa_block * block)443 void mlxsw_afa_block_destroy(struct mlxsw_afa_block *block) 444 { 445 struct mlxsw_afa_set *set = block->first_set; 446 struct mlxsw_afa_set *next_set; 447 448 do { 449 next_set = set->next; 450 mlxsw_afa_set_put(block->afa, set); 451 set = next_set; 452 } while (set); 453 mlxsw_afa_resources_destroy(block); 454 kfree(block); 455 } 456 EXPORT_SYMBOL(mlxsw_afa_block_destroy); 457 mlxsw_afa_block_commit(struct mlxsw_afa_block * block)458 int mlxsw_afa_block_commit(struct mlxsw_afa_block *block) 459 { 460 struct mlxsw_afa_set *set = block->cur_set; 461 struct mlxsw_afa_set *prev_set; 462 463 block->cur_set = NULL; 464 block->finished = true; 465 466 /* Go over all linked sets starting from last 467 * and try to find existing set in the hash table. 468 * In case it is not there, assign a KVD linear index 469 * and insert it. 470 */ 471 do { 472 prev_set = set->prev; 473 set = mlxsw_afa_set_get(block->afa, set); 474 if (IS_ERR(set)) 475 /* No rollback is needed since the chain is 476 * in consistent state and mlxsw_afa_block_destroy 477 * will take care of putting it away. 478 */ 479 return PTR_ERR(set); 480 if (prev_set) { 481 prev_set->next = set; 482 mlxsw_afa_set_next_set(prev_set, set->kvdl_index); 483 set = prev_set; 484 } 485 } while (prev_set); 486 487 block->first_set = set; 488 return 0; 489 } 490 EXPORT_SYMBOL(mlxsw_afa_block_commit); 491 mlxsw_afa_block_first_set(struct mlxsw_afa_block * block)492 char *mlxsw_afa_block_first_set(struct mlxsw_afa_block *block) 493 { 494 return block->first_set->ht_key.enc_actions; 495 } 496 EXPORT_SYMBOL(mlxsw_afa_block_first_set); 497 mlxsw_afa_block_cur_set(struct mlxsw_afa_block * block)498 char *mlxsw_afa_block_cur_set(struct mlxsw_afa_block *block) 499 { 500 return block->cur_set->ht_key.enc_actions; 501 } 502 EXPORT_SYMBOL(mlxsw_afa_block_cur_set); 503 mlxsw_afa_block_first_kvdl_index(struct mlxsw_afa_block * block)504 u32 mlxsw_afa_block_first_kvdl_index(struct mlxsw_afa_block *block) 505 { 506 /* First set is never in KVD linear. So the first set 507 * with valid KVD linear index is always the second one. 508 */ 509 if (WARN_ON(!block->first_set->next)) 510 return 0; 511 return block->first_set->next->kvdl_index; 512 } 513 EXPORT_SYMBOL(mlxsw_afa_block_first_kvdl_index); 514 mlxsw_afa_block_activity_get(struct mlxsw_afa_block * block,bool * activity)515 int mlxsw_afa_block_activity_get(struct mlxsw_afa_block *block, bool *activity) 516 { 517 u32 kvdl_index = mlxsw_afa_block_first_kvdl_index(block); 518 519 return block->afa->ops->kvdl_set_activity_get(block->afa->ops_priv, 520 kvdl_index, activity); 521 } 522 EXPORT_SYMBOL(mlxsw_afa_block_activity_get); 523 mlxsw_afa_block_continue(struct mlxsw_afa_block * block)524 int mlxsw_afa_block_continue(struct mlxsw_afa_block *block) 525 { 526 if (block->finished) 527 return -EINVAL; 528 mlxsw_afa_set_goto_set(block->cur_set, 529 MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE, 0); 530 block->finished = true; 531 return 0; 532 } 533 EXPORT_SYMBOL(mlxsw_afa_block_continue); 534 mlxsw_afa_block_jump(struct mlxsw_afa_block * block,u16 group_id)535 int mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id) 536 { 537 if (block->finished) 538 return -EINVAL; 539 mlxsw_afa_set_goto_set(block->cur_set, 540 MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP, group_id); 541 block->finished = true; 542 return 0; 543 } 544 EXPORT_SYMBOL(mlxsw_afa_block_jump); 545 mlxsw_afa_block_terminate(struct mlxsw_afa_block * block)546 int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block) 547 { 548 if (block->finished) 549 return -EINVAL; 550 mlxsw_afa_set_goto_set(block->cur_set, 551 MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0); 552 block->finished = true; 553 return 0; 554 } 555 EXPORT_SYMBOL(mlxsw_afa_block_terminate); 556 557 static struct mlxsw_afa_fwd_entry * mlxsw_afa_fwd_entry_create(struct mlxsw_afa * mlxsw_afa,u16 local_port)558 mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u16 local_port) 559 { 560 struct mlxsw_afa_fwd_entry *fwd_entry; 561 int err; 562 563 fwd_entry = kzalloc(sizeof(*fwd_entry), GFP_KERNEL); 564 if (!fwd_entry) 565 return ERR_PTR(-ENOMEM); 566 fwd_entry->ht_key.local_port = local_port; 567 refcount_set(&fwd_entry->ref_count, 1); 568 569 err = rhashtable_insert_fast(&mlxsw_afa->fwd_entry_ht, 570 &fwd_entry->ht_node, 571 mlxsw_afa_fwd_entry_ht_params); 572 if (err) 573 goto err_rhashtable_insert; 574 575 err = mlxsw_afa->ops->kvdl_fwd_entry_add(mlxsw_afa->ops_priv, 576 &fwd_entry->kvdl_index, 577 local_port); 578 if (err) 579 goto err_kvdl_fwd_entry_add; 580 return fwd_entry; 581 582 err_kvdl_fwd_entry_add: 583 rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node, 584 mlxsw_afa_fwd_entry_ht_params); 585 err_rhashtable_insert: 586 kfree(fwd_entry); 587 return ERR_PTR(err); 588 } 589 mlxsw_afa_fwd_entry_destroy(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_fwd_entry * fwd_entry)590 static void mlxsw_afa_fwd_entry_destroy(struct mlxsw_afa *mlxsw_afa, 591 struct mlxsw_afa_fwd_entry *fwd_entry) 592 { 593 mlxsw_afa->ops->kvdl_fwd_entry_del(mlxsw_afa->ops_priv, 594 fwd_entry->kvdl_index); 595 rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node, 596 mlxsw_afa_fwd_entry_ht_params); 597 kfree(fwd_entry); 598 } 599 600 static struct mlxsw_afa_fwd_entry * mlxsw_afa_fwd_entry_get(struct mlxsw_afa * mlxsw_afa,u16 local_port)601 mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port) 602 { 603 struct mlxsw_afa_fwd_entry_ht_key ht_key = {0}; 604 struct mlxsw_afa_fwd_entry *fwd_entry; 605 606 ht_key.local_port = local_port; 607 fwd_entry = rhashtable_lookup_fast(&mlxsw_afa->fwd_entry_ht, &ht_key, 608 mlxsw_afa_fwd_entry_ht_params); 609 if (fwd_entry) { 610 refcount_inc(&fwd_entry->ref_count); 611 return fwd_entry; 612 } 613 return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port); 614 } 615 mlxsw_afa_fwd_entry_put(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_fwd_entry * fwd_entry)616 static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa, 617 struct mlxsw_afa_fwd_entry *fwd_entry) 618 { 619 if (!refcount_dec_and_test(&fwd_entry->ref_count)) 620 return; 621 mlxsw_afa_fwd_entry_destroy(mlxsw_afa, fwd_entry); 622 } 623 624 struct mlxsw_afa_fwd_entry_ref { 625 struct mlxsw_afa_resource resource; 626 struct mlxsw_afa_fwd_entry *fwd_entry; 627 }; 628 629 static void mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block * block,struct mlxsw_afa_fwd_entry_ref * fwd_entry_ref)630 mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block *block, 631 struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref) 632 { 633 mlxsw_afa_resource_del(&fwd_entry_ref->resource); 634 mlxsw_afa_fwd_entry_put(block->afa, fwd_entry_ref->fwd_entry); 635 kfree(fwd_entry_ref); 636 } 637 638 static void mlxsw_afa_fwd_entry_ref_destructor(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)639 mlxsw_afa_fwd_entry_ref_destructor(struct mlxsw_afa_block *block, 640 struct mlxsw_afa_resource *resource) 641 { 642 struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref; 643 644 fwd_entry_ref = container_of(resource, struct mlxsw_afa_fwd_entry_ref, 645 resource); 646 mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref); 647 } 648 649 static struct mlxsw_afa_fwd_entry_ref * mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block * block,u16 local_port)650 mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u16 local_port) 651 { 652 struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref; 653 struct mlxsw_afa_fwd_entry *fwd_entry; 654 int err; 655 656 fwd_entry_ref = kzalloc(sizeof(*fwd_entry_ref), GFP_KERNEL); 657 if (!fwd_entry_ref) 658 return ERR_PTR(-ENOMEM); 659 fwd_entry = mlxsw_afa_fwd_entry_get(block->afa, local_port); 660 if (IS_ERR(fwd_entry)) { 661 err = PTR_ERR(fwd_entry); 662 goto err_fwd_entry_get; 663 } 664 fwd_entry_ref->fwd_entry = fwd_entry; 665 fwd_entry_ref->resource.destructor = mlxsw_afa_fwd_entry_ref_destructor; 666 mlxsw_afa_resource_add(block, &fwd_entry_ref->resource); 667 return fwd_entry_ref; 668 669 err_fwd_entry_get: 670 kfree(fwd_entry_ref); 671 return ERR_PTR(err); 672 } 673 674 struct mlxsw_afa_counter { 675 struct mlxsw_afa_resource resource; 676 u32 counter_index; 677 }; 678 679 static void mlxsw_afa_counter_destroy(struct mlxsw_afa_block * block,struct mlxsw_afa_counter * counter)680 mlxsw_afa_counter_destroy(struct mlxsw_afa_block *block, 681 struct mlxsw_afa_counter *counter) 682 { 683 mlxsw_afa_resource_del(&counter->resource); 684 block->afa->ops->counter_index_put(block->afa->ops_priv, 685 counter->counter_index); 686 kfree(counter); 687 } 688 689 static void mlxsw_afa_counter_destructor(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)690 mlxsw_afa_counter_destructor(struct mlxsw_afa_block *block, 691 struct mlxsw_afa_resource *resource) 692 { 693 struct mlxsw_afa_counter *counter; 694 695 counter = container_of(resource, struct mlxsw_afa_counter, resource); 696 mlxsw_afa_counter_destroy(block, counter); 697 } 698 699 static struct mlxsw_afa_counter * mlxsw_afa_counter_create(struct mlxsw_afa_block * block)700 mlxsw_afa_counter_create(struct mlxsw_afa_block *block) 701 { 702 struct mlxsw_afa_counter *counter; 703 int err; 704 705 counter = kzalloc(sizeof(*counter), GFP_KERNEL); 706 if (!counter) 707 return ERR_PTR(-ENOMEM); 708 709 err = block->afa->ops->counter_index_get(block->afa->ops_priv, 710 &counter->counter_index); 711 if (err) 712 goto err_counter_index_get; 713 counter->resource.destructor = mlxsw_afa_counter_destructor; 714 mlxsw_afa_resource_add(block, &counter->resource); 715 return counter; 716 717 err_counter_index_get: 718 kfree(counter); 719 return ERR_PTR(err); 720 } 721 722 /* 20 bits is a maximum that hardware can handle in trap with userdef action 723 * and carry along with the trapped packet. 724 */ 725 #define MLXSW_AFA_COOKIE_INDEX_BITS 20 726 #define MLXSW_AFA_COOKIE_INDEX_MAX ((1 << MLXSW_AFA_COOKIE_INDEX_BITS) - 1) 727 728 static struct mlxsw_afa_cookie * mlxsw_afa_cookie_create(struct mlxsw_afa * mlxsw_afa,const struct flow_action_cookie * fa_cookie)729 mlxsw_afa_cookie_create(struct mlxsw_afa *mlxsw_afa, 730 const struct flow_action_cookie *fa_cookie) 731 { 732 struct mlxsw_afa_cookie *cookie; 733 u32 cookie_index; 734 int err; 735 736 cookie = kzalloc(sizeof(*cookie) + fa_cookie->cookie_len, GFP_KERNEL); 737 if (!cookie) 738 return ERR_PTR(-ENOMEM); 739 refcount_set(&cookie->ref_count, 1); 740 cookie->fa_cookie = *fa_cookie; 741 memcpy(cookie->fa_cookie.cookie, fa_cookie->cookie, 742 fa_cookie->cookie_len); 743 744 err = rhashtable_insert_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 745 mlxsw_afa_cookie_ht_params); 746 if (err) 747 goto err_rhashtable_insert; 748 749 /* Start cookie indexes with 1. Leave the 0 index unused. Packets 750 * that come from the HW which are not dropped by drop-with-cookie 751 * action are going to pass cookie_index 0 to lookup. 752 */ 753 cookie_index = 1; 754 err = idr_alloc_u32(&mlxsw_afa->cookie_idr, cookie, &cookie_index, 755 MLXSW_AFA_COOKIE_INDEX_MAX, GFP_KERNEL); 756 if (err) 757 goto err_idr_alloc; 758 cookie->cookie_index = cookie_index; 759 return cookie; 760 761 err_idr_alloc: 762 rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 763 mlxsw_afa_cookie_ht_params); 764 err_rhashtable_insert: 765 kfree(cookie); 766 return ERR_PTR(err); 767 } 768 mlxsw_afa_cookie_destroy(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_cookie * cookie)769 static void mlxsw_afa_cookie_destroy(struct mlxsw_afa *mlxsw_afa, 770 struct mlxsw_afa_cookie *cookie) 771 { 772 idr_remove(&mlxsw_afa->cookie_idr, cookie->cookie_index); 773 rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 774 mlxsw_afa_cookie_ht_params); 775 kfree_rcu(cookie, rcu); 776 } 777 778 static struct mlxsw_afa_cookie * mlxsw_afa_cookie_get(struct mlxsw_afa * mlxsw_afa,const struct flow_action_cookie * fa_cookie)779 mlxsw_afa_cookie_get(struct mlxsw_afa *mlxsw_afa, 780 const struct flow_action_cookie *fa_cookie) 781 { 782 struct mlxsw_afa_cookie *cookie; 783 784 cookie = rhashtable_lookup_fast(&mlxsw_afa->cookie_ht, fa_cookie, 785 mlxsw_afa_cookie_ht_params); 786 if (cookie) { 787 refcount_inc(&cookie->ref_count); 788 return cookie; 789 } 790 return mlxsw_afa_cookie_create(mlxsw_afa, fa_cookie); 791 } 792 mlxsw_afa_cookie_put(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_cookie * cookie)793 static void mlxsw_afa_cookie_put(struct mlxsw_afa *mlxsw_afa, 794 struct mlxsw_afa_cookie *cookie) 795 { 796 if (!refcount_dec_and_test(&cookie->ref_count)) 797 return; 798 mlxsw_afa_cookie_destroy(mlxsw_afa, cookie); 799 } 800 801 /* RCU read lock must be held */ 802 const struct flow_action_cookie * mlxsw_afa_cookie_lookup(struct mlxsw_afa * mlxsw_afa,u32 cookie_index)803 mlxsw_afa_cookie_lookup(struct mlxsw_afa *mlxsw_afa, u32 cookie_index) 804 { 805 struct mlxsw_afa_cookie *cookie; 806 807 /* 0 index means no cookie */ 808 if (!cookie_index) 809 return NULL; 810 cookie = idr_find(&mlxsw_afa->cookie_idr, cookie_index); 811 if (!cookie) 812 return NULL; 813 return &cookie->fa_cookie; 814 } 815 EXPORT_SYMBOL(mlxsw_afa_cookie_lookup); 816 817 struct mlxsw_afa_cookie_ref { 818 struct mlxsw_afa_resource resource; 819 struct mlxsw_afa_cookie *cookie; 820 }; 821 822 static void mlxsw_afa_cookie_ref_destroy(struct mlxsw_afa_block * block,struct mlxsw_afa_cookie_ref * cookie_ref)823 mlxsw_afa_cookie_ref_destroy(struct mlxsw_afa_block *block, 824 struct mlxsw_afa_cookie_ref *cookie_ref) 825 { 826 mlxsw_afa_resource_del(&cookie_ref->resource); 827 mlxsw_afa_cookie_put(block->afa, cookie_ref->cookie); 828 kfree(cookie_ref); 829 } 830 831 static void mlxsw_afa_cookie_ref_destructor(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)832 mlxsw_afa_cookie_ref_destructor(struct mlxsw_afa_block *block, 833 struct mlxsw_afa_resource *resource) 834 { 835 struct mlxsw_afa_cookie_ref *cookie_ref; 836 837 cookie_ref = container_of(resource, struct mlxsw_afa_cookie_ref, 838 resource); 839 mlxsw_afa_cookie_ref_destroy(block, cookie_ref); 840 } 841 842 static struct mlxsw_afa_cookie_ref * mlxsw_afa_cookie_ref_create(struct mlxsw_afa_block * block,const struct flow_action_cookie * fa_cookie)843 mlxsw_afa_cookie_ref_create(struct mlxsw_afa_block *block, 844 const struct flow_action_cookie *fa_cookie) 845 { 846 struct mlxsw_afa_cookie_ref *cookie_ref; 847 struct mlxsw_afa_cookie *cookie; 848 int err; 849 850 cookie_ref = kzalloc(sizeof(*cookie_ref), GFP_KERNEL); 851 if (!cookie_ref) 852 return ERR_PTR(-ENOMEM); 853 cookie = mlxsw_afa_cookie_get(block->afa, fa_cookie); 854 if (IS_ERR(cookie)) { 855 err = PTR_ERR(cookie); 856 goto err_cookie_get; 857 } 858 cookie_ref->cookie = cookie; 859 cookie_ref->resource.destructor = mlxsw_afa_cookie_ref_destructor; 860 mlxsw_afa_resource_add(block, &cookie_ref->resource); 861 return cookie_ref; 862 863 err_cookie_get: 864 kfree(cookie_ref); 865 return ERR_PTR(err); 866 } 867 868 static struct mlxsw_afa_policer * mlxsw_afa_policer_create(struct mlxsw_afa * mlxsw_afa,u32 fa_index,u64 rate_bytes_ps,u32 burst,struct netlink_ext_ack * extack)869 mlxsw_afa_policer_create(struct mlxsw_afa *mlxsw_afa, u32 fa_index, 870 u64 rate_bytes_ps, u32 burst, 871 struct netlink_ext_ack *extack) 872 { 873 struct mlxsw_afa_policer *policer; 874 int err; 875 876 policer = kzalloc(sizeof(*policer), GFP_KERNEL); 877 if (!policer) 878 return ERR_PTR(-ENOMEM); 879 880 err = mlxsw_afa->ops->policer_add(mlxsw_afa->ops_priv, rate_bytes_ps, 881 burst, &policer->policer_index, 882 extack); 883 if (err) 884 goto err_policer_add; 885 886 refcount_set(&policer->ref_count, 1); 887 policer->fa_index = fa_index; 888 889 err = rhashtable_insert_fast(&mlxsw_afa->policer_ht, &policer->ht_node, 890 mlxsw_afa_policer_ht_params); 891 if (err) 892 goto err_rhashtable_insert; 893 894 list_add_tail(&policer->list, &mlxsw_afa->policer_list); 895 896 return policer; 897 898 err_rhashtable_insert: 899 mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv, 900 policer->policer_index); 901 err_policer_add: 902 kfree(policer); 903 return ERR_PTR(err); 904 } 905 mlxsw_afa_policer_destroy(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_policer * policer)906 static void mlxsw_afa_policer_destroy(struct mlxsw_afa *mlxsw_afa, 907 struct mlxsw_afa_policer *policer) 908 { 909 list_del(&policer->list); 910 rhashtable_remove_fast(&mlxsw_afa->policer_ht, &policer->ht_node, 911 mlxsw_afa_policer_ht_params); 912 mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv, 913 policer->policer_index); 914 kfree(policer); 915 } 916 917 static struct mlxsw_afa_policer * mlxsw_afa_policer_get(struct mlxsw_afa * mlxsw_afa,u32 fa_index,u64 rate_bytes_ps,u32 burst,struct netlink_ext_ack * extack)918 mlxsw_afa_policer_get(struct mlxsw_afa *mlxsw_afa, u32 fa_index, 919 u64 rate_bytes_ps, u32 burst, 920 struct netlink_ext_ack *extack) 921 { 922 struct mlxsw_afa_policer *policer; 923 924 policer = rhashtable_lookup_fast(&mlxsw_afa->policer_ht, &fa_index, 925 mlxsw_afa_policer_ht_params); 926 if (policer) { 927 refcount_inc(&policer->ref_count); 928 return policer; 929 } 930 931 return mlxsw_afa_policer_create(mlxsw_afa, fa_index, rate_bytes_ps, 932 burst, extack); 933 } 934 mlxsw_afa_policer_put(struct mlxsw_afa * mlxsw_afa,struct mlxsw_afa_policer * policer)935 static void mlxsw_afa_policer_put(struct mlxsw_afa *mlxsw_afa, 936 struct mlxsw_afa_policer *policer) 937 { 938 if (!refcount_dec_and_test(&policer->ref_count)) 939 return; 940 mlxsw_afa_policer_destroy(mlxsw_afa, policer); 941 } 942 943 struct mlxsw_afa_policer_ref { 944 struct mlxsw_afa_resource resource; 945 struct mlxsw_afa_policer *policer; 946 }; 947 948 static void mlxsw_afa_policer_ref_destroy(struct mlxsw_afa_block * block,struct mlxsw_afa_policer_ref * policer_ref)949 mlxsw_afa_policer_ref_destroy(struct mlxsw_afa_block *block, 950 struct mlxsw_afa_policer_ref *policer_ref) 951 { 952 mlxsw_afa_resource_del(&policer_ref->resource); 953 mlxsw_afa_policer_put(block->afa, policer_ref->policer); 954 kfree(policer_ref); 955 } 956 957 static void mlxsw_afa_policer_ref_destructor(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)958 mlxsw_afa_policer_ref_destructor(struct mlxsw_afa_block *block, 959 struct mlxsw_afa_resource *resource) 960 { 961 struct mlxsw_afa_policer_ref *policer_ref; 962 963 policer_ref = container_of(resource, struct mlxsw_afa_policer_ref, 964 resource); 965 mlxsw_afa_policer_ref_destroy(block, policer_ref); 966 } 967 968 static struct mlxsw_afa_policer_ref * mlxsw_afa_policer_ref_create(struct mlxsw_afa_block * block,u32 fa_index,u64 rate_bytes_ps,u32 burst,struct netlink_ext_ack * extack)969 mlxsw_afa_policer_ref_create(struct mlxsw_afa_block *block, u32 fa_index, 970 u64 rate_bytes_ps, u32 burst, 971 struct netlink_ext_ack *extack) 972 { 973 struct mlxsw_afa_policer_ref *policer_ref; 974 struct mlxsw_afa_policer *policer; 975 int err; 976 977 policer_ref = kzalloc(sizeof(*policer_ref), GFP_KERNEL); 978 if (!policer_ref) 979 return ERR_PTR(-ENOMEM); 980 981 policer = mlxsw_afa_policer_get(block->afa, fa_index, rate_bytes_ps, 982 burst, extack); 983 if (IS_ERR(policer)) { 984 err = PTR_ERR(policer); 985 goto err_policer_get; 986 } 987 988 policer_ref->policer = policer; 989 policer_ref->resource.destructor = mlxsw_afa_policer_ref_destructor; 990 mlxsw_afa_resource_add(block, &policer_ref->resource); 991 992 return policer_ref; 993 994 err_policer_get: 995 kfree(policer_ref); 996 return ERR_PTR(err); 997 } 998 999 #define MLXSW_AFA_ONE_ACTION_LEN 32 1000 #define MLXSW_AFA_PAYLOAD_OFFSET 4 1001 1002 enum mlxsw_afa_action_type { 1003 MLXSW_AFA_ACTION_TYPE_TRAP, 1004 MLXSW_AFA_ACTION_TYPE_POLICE, 1005 MLXSW_AFA_ACTION_TYPE_OTHER, 1006 }; 1007 1008 static bool mlxsw_afa_block_need_split(const struct mlxsw_afa_block * block,enum mlxsw_afa_action_type type)1009 mlxsw_afa_block_need_split(const struct mlxsw_afa_block *block, 1010 enum mlxsw_afa_action_type type) 1011 { 1012 struct mlxsw_afa_set *cur_set = block->cur_set; 1013 1014 /* Due to a hardware limitation, police action cannot be in the same 1015 * action set with MLXSW_AFA_TRAP_CODE or MLXSW_AFA_TRAPWU_CODE 1016 * actions. Work around this limitation by creating a new action set 1017 * and place the new action there. 1018 */ 1019 return (cur_set->has_trap && type == MLXSW_AFA_ACTION_TYPE_POLICE) || 1020 (cur_set->has_police && type == MLXSW_AFA_ACTION_TYPE_TRAP); 1021 } 1022 mlxsw_afa_block_append_action_ext(struct mlxsw_afa_block * block,u8 action_code,u8 action_size,enum mlxsw_afa_action_type type)1023 static char *mlxsw_afa_block_append_action_ext(struct mlxsw_afa_block *block, 1024 u8 action_code, u8 action_size, 1025 enum mlxsw_afa_action_type type) 1026 { 1027 char *oneact; 1028 char *actions; 1029 1030 if (block->finished) 1031 return ERR_PTR(-EINVAL); 1032 if (block->cur_act_index + action_size > block->afa->max_acts_per_set || 1033 mlxsw_afa_block_need_split(block, type)) { 1034 struct mlxsw_afa_set *set; 1035 1036 /* The appended action won't fit into the current action set, 1037 * so create a new set. 1038 */ 1039 set = mlxsw_afa_set_create(false); 1040 if (!set) 1041 return ERR_PTR(-ENOBUFS); 1042 set->prev = block->cur_set; 1043 block->cur_act_index = 0; 1044 block->cur_set->next = set; 1045 block->cur_set = set; 1046 } 1047 1048 switch (type) { 1049 case MLXSW_AFA_ACTION_TYPE_TRAP: 1050 block->cur_set->has_trap = true; 1051 break; 1052 case MLXSW_AFA_ACTION_TYPE_POLICE: 1053 block->cur_set->has_police = true; 1054 break; 1055 default: 1056 break; 1057 } 1058 1059 actions = block->cur_set->ht_key.enc_actions; 1060 oneact = actions + block->cur_act_index * MLXSW_AFA_ONE_ACTION_LEN; 1061 block->cur_act_index += action_size; 1062 mlxsw_afa_all_action_type_set(oneact, action_code); 1063 return oneact + MLXSW_AFA_PAYLOAD_OFFSET; 1064 } 1065 mlxsw_afa_block_append_action(struct mlxsw_afa_block * block,u8 action_code,u8 action_size)1066 static char *mlxsw_afa_block_append_action(struct mlxsw_afa_block *block, 1067 u8 action_code, u8 action_size) 1068 { 1069 return mlxsw_afa_block_append_action_ext(block, action_code, 1070 action_size, 1071 MLXSW_AFA_ACTION_TYPE_OTHER); 1072 } 1073 1074 /* VLAN Action 1075 * ----------- 1076 * VLAN action is used for manipulating VLANs. It can be used to implement QinQ, 1077 * VLAN translation, change of PCP bits of the VLAN tag, push, pop as swap VLANs 1078 * and more. 1079 */ 1080 1081 #define MLXSW_AFA_VLAN_CODE 0x02 1082 #define MLXSW_AFA_VLAN_SIZE 1 1083 1084 enum mlxsw_afa_vlan_vlan_tag_cmd { 1085 MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP, 1086 MLXSW_AFA_VLAN_VLAN_TAG_CMD_PUSH_TAG, 1087 MLXSW_AFA_VLAN_VLAN_TAG_CMD_POP_TAG, 1088 }; 1089 1090 enum mlxsw_afa_vlan_cmd { 1091 MLXSW_AFA_VLAN_CMD_NOP, 1092 MLXSW_AFA_VLAN_CMD_SET_OUTER, 1093 MLXSW_AFA_VLAN_CMD_SET_INNER, 1094 MLXSW_AFA_VLAN_CMD_COPY_OUTER_TO_INNER, 1095 MLXSW_AFA_VLAN_CMD_COPY_INNER_TO_OUTER, 1096 MLXSW_AFA_VLAN_CMD_SWAP, 1097 }; 1098 1099 /* afa_vlan_vlan_tag_cmd 1100 * Tag command: push, pop, nop VLAN header. 1101 */ 1102 MLXSW_ITEM32(afa, vlan, vlan_tag_cmd, 0x00, 29, 3); 1103 1104 /* afa_vlan_vid_cmd */ 1105 MLXSW_ITEM32(afa, vlan, vid_cmd, 0x04, 29, 3); 1106 1107 /* afa_vlan_vid */ 1108 MLXSW_ITEM32(afa, vlan, vid, 0x04, 0, 12); 1109 1110 /* afa_vlan_ethertype_cmd */ 1111 MLXSW_ITEM32(afa, vlan, ethertype_cmd, 0x08, 29, 3); 1112 1113 /* afa_vlan_ethertype 1114 * Index to EtherTypes in Switch VLAN EtherType Register (SVER). 1115 */ 1116 MLXSW_ITEM32(afa, vlan, ethertype, 0x08, 24, 3); 1117 1118 /* afa_vlan_pcp_cmd */ 1119 MLXSW_ITEM32(afa, vlan, pcp_cmd, 0x08, 13, 3); 1120 1121 /* afa_vlan_pcp */ 1122 MLXSW_ITEM32(afa, vlan, pcp, 0x08, 8, 3); 1123 1124 static inline void mlxsw_afa_vlan_pack(char * payload,enum mlxsw_afa_vlan_vlan_tag_cmd vlan_tag_cmd,enum mlxsw_afa_vlan_cmd vid_cmd,u16 vid,enum mlxsw_afa_vlan_cmd pcp_cmd,u8 pcp,enum mlxsw_afa_vlan_cmd ethertype_cmd,u8 ethertype)1125 mlxsw_afa_vlan_pack(char *payload, 1126 enum mlxsw_afa_vlan_vlan_tag_cmd vlan_tag_cmd, 1127 enum mlxsw_afa_vlan_cmd vid_cmd, u16 vid, 1128 enum mlxsw_afa_vlan_cmd pcp_cmd, u8 pcp, 1129 enum mlxsw_afa_vlan_cmd ethertype_cmd, u8 ethertype) 1130 { 1131 mlxsw_afa_vlan_vlan_tag_cmd_set(payload, vlan_tag_cmd); 1132 mlxsw_afa_vlan_vid_cmd_set(payload, vid_cmd); 1133 mlxsw_afa_vlan_vid_set(payload, vid); 1134 mlxsw_afa_vlan_pcp_cmd_set(payload, pcp_cmd); 1135 mlxsw_afa_vlan_pcp_set(payload, pcp); 1136 mlxsw_afa_vlan_ethertype_cmd_set(payload, ethertype_cmd); 1137 mlxsw_afa_vlan_ethertype_set(payload, ethertype); 1138 } 1139 mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block * block,u16 vid,u8 pcp,u8 et,struct netlink_ext_ack * extack)1140 int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, 1141 u16 vid, u8 pcp, u8 et, 1142 struct netlink_ext_ack *extack) 1143 { 1144 char *act = mlxsw_afa_block_append_action(block, 1145 MLXSW_AFA_VLAN_CODE, 1146 MLXSW_AFA_VLAN_SIZE); 1147 1148 if (IS_ERR(act)) { 1149 NL_SET_ERR_MSG_MOD(extack, "Cannot append vlan_modify action"); 1150 return PTR_ERR(act); 1151 } 1152 mlxsw_afa_vlan_pack(act, MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP, 1153 MLXSW_AFA_VLAN_CMD_SET_OUTER, vid, 1154 MLXSW_AFA_VLAN_CMD_SET_OUTER, pcp, 1155 MLXSW_AFA_VLAN_CMD_SET_OUTER, et); 1156 return 0; 1157 } 1158 EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify); 1159 1160 /* Trap Action / Trap With Userdef Action 1161 * -------------------------------------- 1162 * The Trap action enables trapping / mirroring packets to the CPU 1163 * as well as discarding packets. 1164 * The ACL Trap / Discard separates the forward/discard control from CPU 1165 * trap control. In addition, the Trap / Discard action enables activating 1166 * SPAN (port mirroring). 1167 * 1168 * The Trap with userdef action has the same functionality as 1169 * the Trap action with addition of user defined value that can be set 1170 * and used by higher layer applications. 1171 */ 1172 1173 #define MLXSW_AFA_TRAP_CODE 0x03 1174 #define MLXSW_AFA_TRAP_SIZE 1 1175 1176 #define MLXSW_AFA_TRAPWU_CODE 0x04 1177 #define MLXSW_AFA_TRAPWU_SIZE 2 1178 1179 enum mlxsw_afa_trap_trap_action { 1180 MLXSW_AFA_TRAP_TRAP_ACTION_NOP = 0, 1181 MLXSW_AFA_TRAP_TRAP_ACTION_TRAP = 2, 1182 }; 1183 1184 /* afa_trap_trap_action 1185 * Trap Action. 1186 */ 1187 MLXSW_ITEM32(afa, trap, trap_action, 0x00, 24, 4); 1188 1189 enum mlxsw_afa_trap_forward_action { 1190 MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD = 1, 1191 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD = 3, 1192 }; 1193 1194 /* afa_trap_forward_action 1195 * Forward Action. 1196 */ 1197 MLXSW_ITEM32(afa, trap, forward_action, 0x00, 0, 4); 1198 1199 /* afa_trap_trap_id 1200 * Trap ID to configure. 1201 */ 1202 MLXSW_ITEM32(afa, trap, trap_id, 0x04, 0, 9); 1203 1204 /* afa_trap_mirror_agent 1205 * Mirror agent. 1206 */ 1207 MLXSW_ITEM32(afa, trap, mirror_agent, 0x08, 29, 3); 1208 1209 /* afa_trap_mirror_enable 1210 * Mirror enable. 1211 */ 1212 MLXSW_ITEM32(afa, trap, mirror_enable, 0x08, 24, 1); 1213 1214 /* user_def_val 1215 * Value for the SW usage. Can be used to pass information of which 1216 * rule has caused a trap. This may be overwritten by later traps. 1217 * This field does a set on the packet's user_def_val only if this 1218 * is the first trap_id or if the trap_id has replaced the previous 1219 * packet's trap_id. 1220 */ 1221 MLXSW_ITEM32(afa, trap, user_def_val, 0x0C, 0, 20); 1222 1223 static inline void mlxsw_afa_trap_pack(char * payload,enum mlxsw_afa_trap_trap_action trap_action,enum mlxsw_afa_trap_forward_action forward_action,u16 trap_id)1224 mlxsw_afa_trap_pack(char *payload, 1225 enum mlxsw_afa_trap_trap_action trap_action, 1226 enum mlxsw_afa_trap_forward_action forward_action, 1227 u16 trap_id) 1228 { 1229 mlxsw_afa_trap_trap_action_set(payload, trap_action); 1230 mlxsw_afa_trap_forward_action_set(payload, forward_action); 1231 mlxsw_afa_trap_trap_id_set(payload, trap_id); 1232 } 1233 1234 static inline void mlxsw_afa_trapwu_pack(char * payload,enum mlxsw_afa_trap_trap_action trap_action,enum mlxsw_afa_trap_forward_action forward_action,u16 trap_id,u32 user_def_val)1235 mlxsw_afa_trapwu_pack(char *payload, 1236 enum mlxsw_afa_trap_trap_action trap_action, 1237 enum mlxsw_afa_trap_forward_action forward_action, 1238 u16 trap_id, u32 user_def_val) 1239 { 1240 mlxsw_afa_trap_pack(payload, trap_action, forward_action, trap_id); 1241 mlxsw_afa_trap_user_def_val_set(payload, user_def_val); 1242 } 1243 1244 static inline void mlxsw_afa_trap_mirror_pack(char * payload,bool mirror_enable,u8 mirror_agent)1245 mlxsw_afa_trap_mirror_pack(char *payload, bool mirror_enable, 1246 u8 mirror_agent) 1247 { 1248 mlxsw_afa_trap_mirror_enable_set(payload, mirror_enable); 1249 mlxsw_afa_trap_mirror_agent_set(payload, mirror_agent); 1250 } 1251 mlxsw_afa_block_append_action_trap(struct mlxsw_afa_block * block,u8 action_code,u8 action_size)1252 static char *mlxsw_afa_block_append_action_trap(struct mlxsw_afa_block *block, 1253 u8 action_code, u8 action_size) 1254 { 1255 return mlxsw_afa_block_append_action_ext(block, action_code, 1256 action_size, 1257 MLXSW_AFA_ACTION_TYPE_TRAP); 1258 } 1259 mlxsw_afa_block_append_drop_plain(struct mlxsw_afa_block * block,bool ingress)1260 static int mlxsw_afa_block_append_drop_plain(struct mlxsw_afa_block *block, 1261 bool ingress) 1262 { 1263 char *act = mlxsw_afa_block_append_action_trap(block, 1264 MLXSW_AFA_TRAP_CODE, 1265 MLXSW_AFA_TRAP_SIZE); 1266 1267 if (IS_ERR(act)) 1268 return PTR_ERR(act); 1269 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1270 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, 1271 ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL : 1272 MLXSW_TRAP_ID_DISCARD_EGRESS_ACL); 1273 return 0; 1274 } 1275 1276 static int mlxsw_afa_block_append_drop_with_cookie(struct mlxsw_afa_block * block,bool ingress,const struct flow_action_cookie * fa_cookie,struct netlink_ext_ack * extack)1277 mlxsw_afa_block_append_drop_with_cookie(struct mlxsw_afa_block *block, 1278 bool ingress, 1279 const struct flow_action_cookie *fa_cookie, 1280 struct netlink_ext_ack *extack) 1281 { 1282 struct mlxsw_afa_cookie_ref *cookie_ref; 1283 u32 cookie_index; 1284 char *act; 1285 int err; 1286 1287 cookie_ref = mlxsw_afa_cookie_ref_create(block, fa_cookie); 1288 if (IS_ERR(cookie_ref)) { 1289 NL_SET_ERR_MSG_MOD(extack, "Cannot create cookie for drop action"); 1290 return PTR_ERR(cookie_ref); 1291 } 1292 cookie_index = cookie_ref->cookie->cookie_index; 1293 1294 act = mlxsw_afa_block_append_action_trap(block, MLXSW_AFA_TRAPWU_CODE, 1295 MLXSW_AFA_TRAPWU_SIZE); 1296 if (IS_ERR(act)) { 1297 NL_SET_ERR_MSG_MOD(extack, "Cannot append drop with cookie action"); 1298 err = PTR_ERR(act); 1299 goto err_append_action; 1300 } 1301 mlxsw_afa_trapwu_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1302 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, 1303 ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL : 1304 MLXSW_TRAP_ID_DISCARD_EGRESS_ACL, 1305 cookie_index); 1306 return 0; 1307 1308 err_append_action: 1309 mlxsw_afa_cookie_ref_destroy(block, cookie_ref); 1310 return err; 1311 } 1312 mlxsw_afa_block_append_drop(struct mlxsw_afa_block * block,bool ingress,const struct flow_action_cookie * fa_cookie,struct netlink_ext_ack * extack)1313 int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block, bool ingress, 1314 const struct flow_action_cookie *fa_cookie, 1315 struct netlink_ext_ack *extack) 1316 { 1317 return fa_cookie ? 1318 mlxsw_afa_block_append_drop_with_cookie(block, ingress, 1319 fa_cookie, extack) : 1320 mlxsw_afa_block_append_drop_plain(block, ingress); 1321 } 1322 EXPORT_SYMBOL(mlxsw_afa_block_append_drop); 1323 mlxsw_afa_block_append_trap(struct mlxsw_afa_block * block,u16 trap_id)1324 int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id) 1325 { 1326 char *act = mlxsw_afa_block_append_action_trap(block, 1327 MLXSW_AFA_TRAP_CODE, 1328 MLXSW_AFA_TRAP_SIZE); 1329 1330 if (IS_ERR(act)) 1331 return PTR_ERR(act); 1332 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1333 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, trap_id); 1334 return 0; 1335 } 1336 EXPORT_SYMBOL(mlxsw_afa_block_append_trap); 1337 mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block * block,u16 trap_id)1338 int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, 1339 u16 trap_id) 1340 { 1341 char *act = mlxsw_afa_block_append_action_trap(block, 1342 MLXSW_AFA_TRAP_CODE, 1343 MLXSW_AFA_TRAP_SIZE); 1344 1345 if (IS_ERR(act)) 1346 return PTR_ERR(act); 1347 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1348 MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, trap_id); 1349 return 0; 1350 } 1351 EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward); 1352 1353 struct mlxsw_afa_mirror { 1354 struct mlxsw_afa_resource resource; 1355 int span_id; 1356 u16 local_in_port; 1357 bool ingress; 1358 }; 1359 1360 static void mlxsw_afa_mirror_destroy(struct mlxsw_afa_block * block,struct mlxsw_afa_mirror * mirror)1361 mlxsw_afa_mirror_destroy(struct mlxsw_afa_block *block, 1362 struct mlxsw_afa_mirror *mirror) 1363 { 1364 mlxsw_afa_resource_del(&mirror->resource); 1365 block->afa->ops->mirror_del(block->afa->ops_priv, 1366 mirror->local_in_port, 1367 mirror->span_id, 1368 mirror->ingress); 1369 kfree(mirror); 1370 } 1371 1372 static void mlxsw_afa_mirror_destructor(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)1373 mlxsw_afa_mirror_destructor(struct mlxsw_afa_block *block, 1374 struct mlxsw_afa_resource *resource) 1375 { 1376 struct mlxsw_afa_mirror *mirror; 1377 1378 mirror = container_of(resource, struct mlxsw_afa_mirror, resource); 1379 mlxsw_afa_mirror_destroy(block, mirror); 1380 } 1381 1382 static struct mlxsw_afa_mirror * mlxsw_afa_mirror_create(struct mlxsw_afa_block * block,u16 local_in_port,const struct net_device * out_dev,bool ingress)1383 mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, u16 local_in_port, 1384 const struct net_device *out_dev, bool ingress) 1385 { 1386 struct mlxsw_afa_mirror *mirror; 1387 int err; 1388 1389 mirror = kzalloc(sizeof(*mirror), GFP_KERNEL); 1390 if (!mirror) 1391 return ERR_PTR(-ENOMEM); 1392 1393 err = block->afa->ops->mirror_add(block->afa->ops_priv, 1394 local_in_port, out_dev, 1395 ingress, &mirror->span_id); 1396 if (err) 1397 goto err_mirror_add; 1398 1399 mirror->ingress = ingress; 1400 mirror->local_in_port = local_in_port; 1401 mirror->resource.destructor = mlxsw_afa_mirror_destructor; 1402 mlxsw_afa_resource_add(block, &mirror->resource); 1403 return mirror; 1404 1405 err_mirror_add: 1406 kfree(mirror); 1407 return ERR_PTR(err); 1408 } 1409 1410 static int mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block * block,u8 mirror_agent)1411 mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block, 1412 u8 mirror_agent) 1413 { 1414 char *act = mlxsw_afa_block_append_action_trap(block, 1415 MLXSW_AFA_TRAP_CODE, 1416 MLXSW_AFA_TRAP_SIZE); 1417 1418 if (IS_ERR(act)) 1419 return PTR_ERR(act); 1420 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_NOP, 1421 MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, 0); 1422 mlxsw_afa_trap_mirror_pack(act, true, mirror_agent); 1423 return 0; 1424 } 1425 1426 int mlxsw_afa_block_append_mirror(struct mlxsw_afa_block * block,u16 local_in_port,const struct net_device * out_dev,bool ingress,struct netlink_ext_ack * extack)1427 mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u16 local_in_port, 1428 const struct net_device *out_dev, bool ingress, 1429 struct netlink_ext_ack *extack) 1430 { 1431 struct mlxsw_afa_mirror *mirror; 1432 int err; 1433 1434 mirror = mlxsw_afa_mirror_create(block, local_in_port, out_dev, 1435 ingress); 1436 if (IS_ERR(mirror)) { 1437 NL_SET_ERR_MSG_MOD(extack, "Cannot create mirror action"); 1438 return PTR_ERR(mirror); 1439 } 1440 err = mlxsw_afa_block_append_allocated_mirror(block, mirror->span_id); 1441 if (err) { 1442 NL_SET_ERR_MSG_MOD(extack, "Cannot append mirror action"); 1443 goto err_append_allocated_mirror; 1444 } 1445 1446 return 0; 1447 1448 err_append_allocated_mirror: 1449 mlxsw_afa_mirror_destroy(block, mirror); 1450 return err; 1451 } 1452 EXPORT_SYMBOL(mlxsw_afa_block_append_mirror); 1453 1454 /* QoS Action 1455 * ---------- 1456 * The QOS_ACTION is used for manipulating the QoS attributes of a packet. It 1457 * can be used to change the DCSP, ECN, Color and Switch Priority of the packet. 1458 * Note that PCP field can be changed using the VLAN action. 1459 */ 1460 1461 #define MLXSW_AFA_QOS_CODE 0x06 1462 #define MLXSW_AFA_QOS_SIZE 1 1463 1464 enum mlxsw_afa_qos_ecn_cmd { 1465 /* Do nothing */ 1466 MLXSW_AFA_QOS_ECN_CMD_NOP, 1467 /* Set ECN to afa_qos_ecn */ 1468 MLXSW_AFA_QOS_ECN_CMD_SET, 1469 }; 1470 1471 /* afa_qos_ecn_cmd 1472 */ 1473 MLXSW_ITEM32(afa, qos, ecn_cmd, 0x04, 29, 3); 1474 1475 /* afa_qos_ecn 1476 * ECN value. 1477 */ 1478 MLXSW_ITEM32(afa, qos, ecn, 0x04, 24, 2); 1479 1480 enum mlxsw_afa_qos_dscp_cmd { 1481 /* Do nothing */ 1482 MLXSW_AFA_QOS_DSCP_CMD_NOP, 1483 /* Set DSCP 3 LSB bits according to dscp[2:0] */ 1484 MLXSW_AFA_QOS_DSCP_CMD_SET_3LSB, 1485 /* Set DSCP 3 MSB bits according to dscp[5:3] */ 1486 MLXSW_AFA_QOS_DSCP_CMD_SET_3MSB, 1487 /* Set DSCP 6 bits according to dscp[5:0] */ 1488 MLXSW_AFA_QOS_DSCP_CMD_SET_ALL, 1489 }; 1490 1491 /* afa_qos_dscp_cmd 1492 * DSCP command. 1493 */ 1494 MLXSW_ITEM32(afa, qos, dscp_cmd, 0x04, 14, 2); 1495 1496 /* afa_qos_dscp 1497 * DSCP value. 1498 */ 1499 MLXSW_ITEM32(afa, qos, dscp, 0x04, 0, 6); 1500 1501 enum mlxsw_afa_qos_switch_prio_cmd { 1502 /* Do nothing */ 1503 MLXSW_AFA_QOS_SWITCH_PRIO_CMD_NOP, 1504 /* Set Switch Priority to afa_qos_switch_prio */ 1505 MLXSW_AFA_QOS_SWITCH_PRIO_CMD_SET, 1506 }; 1507 1508 /* afa_qos_switch_prio_cmd 1509 */ 1510 MLXSW_ITEM32(afa, qos, switch_prio_cmd, 0x08, 14, 2); 1511 1512 /* afa_qos_switch_prio 1513 * Switch Priority. 1514 */ 1515 MLXSW_ITEM32(afa, qos, switch_prio, 0x08, 0, 4); 1516 1517 enum mlxsw_afa_qos_dscp_rw { 1518 MLXSW_AFA_QOS_DSCP_RW_PRESERVE, 1519 MLXSW_AFA_QOS_DSCP_RW_SET, 1520 MLXSW_AFA_QOS_DSCP_RW_CLEAR, 1521 }; 1522 1523 /* afa_qos_dscp_rw 1524 * DSCP Re-write Enable. Controlling the rewrite_enable for DSCP. 1525 */ 1526 MLXSW_ITEM32(afa, qos, dscp_rw, 0x0C, 30, 2); 1527 1528 static inline void mlxsw_afa_qos_ecn_pack(char * payload,enum mlxsw_afa_qos_ecn_cmd ecn_cmd,u8 ecn)1529 mlxsw_afa_qos_ecn_pack(char *payload, 1530 enum mlxsw_afa_qos_ecn_cmd ecn_cmd, u8 ecn) 1531 { 1532 mlxsw_afa_qos_ecn_cmd_set(payload, ecn_cmd); 1533 mlxsw_afa_qos_ecn_set(payload, ecn); 1534 } 1535 1536 static inline void mlxsw_afa_qos_dscp_pack(char * payload,enum mlxsw_afa_qos_dscp_cmd dscp_cmd,u8 dscp)1537 mlxsw_afa_qos_dscp_pack(char *payload, 1538 enum mlxsw_afa_qos_dscp_cmd dscp_cmd, u8 dscp) 1539 { 1540 mlxsw_afa_qos_dscp_cmd_set(payload, dscp_cmd); 1541 mlxsw_afa_qos_dscp_set(payload, dscp); 1542 } 1543 1544 static inline void mlxsw_afa_qos_switch_prio_pack(char * payload,enum mlxsw_afa_qos_switch_prio_cmd prio_cmd,u8 prio)1545 mlxsw_afa_qos_switch_prio_pack(char *payload, 1546 enum mlxsw_afa_qos_switch_prio_cmd prio_cmd, 1547 u8 prio) 1548 { 1549 mlxsw_afa_qos_switch_prio_cmd_set(payload, prio_cmd); 1550 mlxsw_afa_qos_switch_prio_set(payload, prio); 1551 } 1552 __mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block * block,bool set_dscp,u8 dscp,bool set_ecn,u8 ecn,struct netlink_ext_ack * extack)1553 static int __mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block, 1554 bool set_dscp, u8 dscp, 1555 bool set_ecn, u8 ecn, 1556 struct netlink_ext_ack *extack) 1557 { 1558 char *act = mlxsw_afa_block_append_action(block, 1559 MLXSW_AFA_QOS_CODE, 1560 MLXSW_AFA_QOS_SIZE); 1561 1562 if (IS_ERR(act)) { 1563 NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action"); 1564 return PTR_ERR(act); 1565 } 1566 1567 if (set_ecn) 1568 mlxsw_afa_qos_ecn_pack(act, MLXSW_AFA_QOS_ECN_CMD_SET, ecn); 1569 if (set_dscp) { 1570 mlxsw_afa_qos_dscp_pack(act, MLXSW_AFA_QOS_DSCP_CMD_SET_ALL, 1571 dscp); 1572 mlxsw_afa_qos_dscp_rw_set(act, MLXSW_AFA_QOS_DSCP_RW_CLEAR); 1573 } 1574 1575 return 0; 1576 } 1577 mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block * block,u8 dsfield,struct netlink_ext_ack * extack)1578 int mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block, 1579 u8 dsfield, 1580 struct netlink_ext_ack *extack) 1581 { 1582 return __mlxsw_afa_block_append_qos_dsfield(block, 1583 true, dsfield >> 2, 1584 true, dsfield & 0x03, 1585 extack); 1586 } 1587 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dsfield); 1588 mlxsw_afa_block_append_qos_dscp(struct mlxsw_afa_block * block,u8 dscp,struct netlink_ext_ack * extack)1589 int mlxsw_afa_block_append_qos_dscp(struct mlxsw_afa_block *block, 1590 u8 dscp, struct netlink_ext_ack *extack) 1591 { 1592 return __mlxsw_afa_block_append_qos_dsfield(block, 1593 true, dscp, 1594 false, 0, 1595 extack); 1596 } 1597 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dscp); 1598 mlxsw_afa_block_append_qos_ecn(struct mlxsw_afa_block * block,u8 ecn,struct netlink_ext_ack * extack)1599 int mlxsw_afa_block_append_qos_ecn(struct mlxsw_afa_block *block, 1600 u8 ecn, struct netlink_ext_ack *extack) 1601 { 1602 return __mlxsw_afa_block_append_qos_dsfield(block, 1603 false, 0, 1604 true, ecn, 1605 extack); 1606 } 1607 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_ecn); 1608 mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block * block,u8 prio,struct netlink_ext_ack * extack)1609 int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block, 1610 u8 prio, 1611 struct netlink_ext_ack *extack) 1612 { 1613 char *act = mlxsw_afa_block_append_action(block, 1614 MLXSW_AFA_QOS_CODE, 1615 MLXSW_AFA_QOS_SIZE); 1616 1617 if (IS_ERR(act)) { 1618 NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action"); 1619 return PTR_ERR(act); 1620 } 1621 mlxsw_afa_qos_switch_prio_pack(act, MLXSW_AFA_QOS_SWITCH_PRIO_CMD_SET, 1622 prio); 1623 return 0; 1624 } 1625 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_switch_prio); 1626 1627 /* Forwarding Action 1628 * ----------------- 1629 * Forwarding Action can be used to implement Policy Based Switching (PBS) 1630 * as well as OpenFlow related "Output" action. 1631 */ 1632 1633 #define MLXSW_AFA_FORWARD_CODE 0x07 1634 #define MLXSW_AFA_FORWARD_SIZE 1 1635 1636 enum mlxsw_afa_forward_type { 1637 /* PBS, Policy Based Switching */ 1638 MLXSW_AFA_FORWARD_TYPE_PBS, 1639 /* Output, OpenFlow output type */ 1640 MLXSW_AFA_FORWARD_TYPE_OUTPUT, 1641 }; 1642 1643 /* afa_forward_type */ 1644 MLXSW_ITEM32(afa, forward, type, 0x00, 24, 2); 1645 1646 /* afa_forward_pbs_ptr 1647 * A pointer to the PBS entry configured by PPBS register. 1648 * Reserved when in_port is set. 1649 */ 1650 MLXSW_ITEM32(afa, forward, pbs_ptr, 0x08, 0, 24); 1651 1652 /* afa_forward_in_port 1653 * Packet is forwarded back to the ingress port. 1654 */ 1655 MLXSW_ITEM32(afa, forward, in_port, 0x0C, 0, 1); 1656 1657 static inline void mlxsw_afa_forward_pack(char * payload,enum mlxsw_afa_forward_type type,u32 pbs_ptr,bool in_port)1658 mlxsw_afa_forward_pack(char *payload, enum mlxsw_afa_forward_type type, 1659 u32 pbs_ptr, bool in_port) 1660 { 1661 mlxsw_afa_forward_type_set(payload, type); 1662 mlxsw_afa_forward_pbs_ptr_set(payload, pbs_ptr); 1663 mlxsw_afa_forward_in_port_set(payload, in_port); 1664 } 1665 mlxsw_afa_block_append_fwd(struct mlxsw_afa_block * block,u16 local_port,bool in_port,struct netlink_ext_ack * extack)1666 int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, 1667 u16 local_port, bool in_port, 1668 struct netlink_ext_ack *extack) 1669 { 1670 struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref; 1671 u32 kvdl_index; 1672 char *act; 1673 int err; 1674 1675 if (in_port) { 1676 NL_SET_ERR_MSG_MOD(extack, "Forwarding to ingress port is not supported"); 1677 return -EOPNOTSUPP; 1678 } 1679 fwd_entry_ref = mlxsw_afa_fwd_entry_ref_create(block, local_port); 1680 if (IS_ERR(fwd_entry_ref)) { 1681 NL_SET_ERR_MSG_MOD(extack, "Cannot create forward action"); 1682 return PTR_ERR(fwd_entry_ref); 1683 } 1684 kvdl_index = fwd_entry_ref->fwd_entry->kvdl_index; 1685 1686 act = mlxsw_afa_block_append_action(block, MLXSW_AFA_FORWARD_CODE, 1687 MLXSW_AFA_FORWARD_SIZE); 1688 if (IS_ERR(act)) { 1689 NL_SET_ERR_MSG_MOD(extack, "Cannot append forward action"); 1690 err = PTR_ERR(act); 1691 goto err_append_action; 1692 } 1693 mlxsw_afa_forward_pack(act, MLXSW_AFA_FORWARD_TYPE_PBS, 1694 kvdl_index, in_port); 1695 return 0; 1696 1697 err_append_action: 1698 mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref); 1699 return err; 1700 } 1701 EXPORT_SYMBOL(mlxsw_afa_block_append_fwd); 1702 1703 /* Policing and Counting Action 1704 * ---------------------------- 1705 * Policing and Counting action is used for binding policer and counter 1706 * to ACL rules. 1707 */ 1708 1709 #define MLXSW_AFA_POLCNT_CODE 0x08 1710 #define MLXSW_AFA_POLCNT_SIZE 1 1711 1712 enum { 1713 MLXSW_AFA_POLCNT_COUNTER, 1714 MLXSW_AFA_POLCNT_POLICER, 1715 }; 1716 1717 /* afa_polcnt_c_p 1718 * Counter or policer. 1719 * Indicates whether the action binds a policer or a counter to the flow. 1720 * 0: Counter 1721 * 1: Policer 1722 */ 1723 MLXSW_ITEM32(afa, polcnt, c_p, 0x00, 31, 1); 1724 1725 enum mlxsw_afa_polcnt_counter_set_type { 1726 /* No count */ 1727 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT = 0x00, 1728 /* Count packets and bytes */ 1729 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03, 1730 /* Count only packets */ 1731 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS = 0x05, 1732 }; 1733 1734 /* afa_polcnt_counter_set_type 1735 * Counter set type for flow counters. 1736 */ 1737 MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8); 1738 1739 /* afa_polcnt_counter_index 1740 * Counter index for flow counters. 1741 */ 1742 MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24); 1743 1744 /* afa_polcnt_pid 1745 * Policer ID. 1746 * Reserved when c_p = 0 1747 */ 1748 MLXSW_ITEM32(afa, polcnt, pid, 0x08, 0, 14); 1749 1750 static inline void mlxsw_afa_polcnt_pack(char * payload,enum mlxsw_afa_polcnt_counter_set_type set_type,u32 counter_index)1751 mlxsw_afa_polcnt_pack(char *payload, 1752 enum mlxsw_afa_polcnt_counter_set_type set_type, 1753 u32 counter_index) 1754 { 1755 mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_COUNTER); 1756 mlxsw_afa_polcnt_counter_set_type_set(payload, set_type); 1757 mlxsw_afa_polcnt_counter_index_set(payload, counter_index); 1758 } 1759 mlxsw_afa_polcnt_policer_pack(char * payload,u16 policer_index)1760 static void mlxsw_afa_polcnt_policer_pack(char *payload, u16 policer_index) 1761 { 1762 mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_POLICER); 1763 mlxsw_afa_polcnt_pid_set(payload, policer_index); 1764 } 1765 mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block * block,u32 counter_index)1766 int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block, 1767 u32 counter_index) 1768 { 1769 char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_POLCNT_CODE, 1770 MLXSW_AFA_POLCNT_SIZE); 1771 if (IS_ERR(act)) 1772 return PTR_ERR(act); 1773 mlxsw_afa_polcnt_pack(act, MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES, 1774 counter_index); 1775 return 0; 1776 } 1777 EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter); 1778 mlxsw_afa_block_append_counter(struct mlxsw_afa_block * block,u32 * p_counter_index,struct netlink_ext_ack * extack)1779 int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, 1780 u32 *p_counter_index, 1781 struct netlink_ext_ack *extack) 1782 { 1783 struct mlxsw_afa_counter *counter; 1784 u32 counter_index; 1785 int err; 1786 1787 counter = mlxsw_afa_counter_create(block); 1788 if (IS_ERR(counter)) { 1789 NL_SET_ERR_MSG_MOD(extack, "Cannot create count action"); 1790 return PTR_ERR(counter); 1791 } 1792 counter_index = counter->counter_index; 1793 1794 err = mlxsw_afa_block_append_allocated_counter(block, counter_index); 1795 if (err) { 1796 NL_SET_ERR_MSG_MOD(extack, "Cannot append count action"); 1797 goto err_append_allocated_counter; 1798 } 1799 if (p_counter_index) 1800 *p_counter_index = counter_index; 1801 return 0; 1802 1803 err_append_allocated_counter: 1804 mlxsw_afa_counter_destroy(block, counter); 1805 return err; 1806 } 1807 EXPORT_SYMBOL(mlxsw_afa_block_append_counter); 1808 mlxsw_afa_block_append_police(struct mlxsw_afa_block * block,u32 fa_index,u64 rate_bytes_ps,u32 burst,u16 * p_policer_index,struct netlink_ext_ack * extack)1809 int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block, 1810 u32 fa_index, u64 rate_bytes_ps, u32 burst, 1811 u16 *p_policer_index, 1812 struct netlink_ext_ack *extack) 1813 { 1814 struct mlxsw_afa_policer_ref *policer_ref; 1815 char *act; 1816 int err; 1817 1818 policer_ref = mlxsw_afa_policer_ref_create(block, fa_index, 1819 rate_bytes_ps, 1820 burst, extack); 1821 if (IS_ERR(policer_ref)) 1822 return PTR_ERR(policer_ref); 1823 *p_policer_index = policer_ref->policer->policer_index; 1824 1825 act = mlxsw_afa_block_append_action_ext(block, MLXSW_AFA_POLCNT_CODE, 1826 MLXSW_AFA_POLCNT_SIZE, 1827 MLXSW_AFA_ACTION_TYPE_POLICE); 1828 if (IS_ERR(act)) { 1829 NL_SET_ERR_MSG_MOD(extack, "Cannot append police action"); 1830 err = PTR_ERR(act); 1831 goto err_append_action; 1832 } 1833 mlxsw_afa_polcnt_policer_pack(act, *p_policer_index); 1834 1835 return 0; 1836 1837 err_append_action: 1838 mlxsw_afa_policer_ref_destroy(block, policer_ref); 1839 return err; 1840 } 1841 EXPORT_SYMBOL(mlxsw_afa_block_append_police); 1842 1843 /* Virtual Router and Forwarding Domain Action 1844 * ------------------------------------------- 1845 * Virtual Switch action is used for manipulate the Virtual Router (VR), 1846 * MPLS label space and the Forwarding Identifier (FID). 1847 */ 1848 1849 #define MLXSW_AFA_VIRFWD_CODE 0x0E 1850 #define MLXSW_AFA_VIRFWD_SIZE 1 1851 1852 enum mlxsw_afa_virfwd_fid_cmd { 1853 /* Do nothing */ 1854 MLXSW_AFA_VIRFWD_FID_CMD_NOOP, 1855 /* Set the Forwarding Identifier (FID) to fid */ 1856 MLXSW_AFA_VIRFWD_FID_CMD_SET, 1857 }; 1858 1859 /* afa_virfwd_fid_cmd */ 1860 MLXSW_ITEM32(afa, virfwd, fid_cmd, 0x08, 29, 3); 1861 1862 /* afa_virfwd_fid 1863 * The FID value. 1864 */ 1865 MLXSW_ITEM32(afa, virfwd, fid, 0x08, 0, 16); 1866 mlxsw_afa_virfwd_pack(char * payload,enum mlxsw_afa_virfwd_fid_cmd fid_cmd,u16 fid)1867 static inline void mlxsw_afa_virfwd_pack(char *payload, 1868 enum mlxsw_afa_virfwd_fid_cmd fid_cmd, 1869 u16 fid) 1870 { 1871 mlxsw_afa_virfwd_fid_cmd_set(payload, fid_cmd); 1872 mlxsw_afa_virfwd_fid_set(payload, fid); 1873 } 1874 mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block * block,u16 fid,struct netlink_ext_ack * extack)1875 int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid, 1876 struct netlink_ext_ack *extack) 1877 { 1878 char *act = mlxsw_afa_block_append_action(block, 1879 MLXSW_AFA_VIRFWD_CODE, 1880 MLXSW_AFA_VIRFWD_SIZE); 1881 if (IS_ERR(act)) { 1882 NL_SET_ERR_MSG_MOD(extack, "Cannot append fid_set action"); 1883 return PTR_ERR(act); 1884 } 1885 mlxsw_afa_virfwd_pack(act, MLXSW_AFA_VIRFWD_FID_CMD_SET, fid); 1886 return 0; 1887 } 1888 EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set); 1889 1890 /* Ignore Action 1891 * ------------- 1892 * The ignore action is used to ignore basic switching functions such as 1893 * learning on a per-packet basis. 1894 */ 1895 1896 #define MLXSW_AFA_IGNORE_CODE 0x0F 1897 #define MLXSW_AFA_IGNORE_SIZE 1 1898 1899 /* afa_ignore_disable_learning 1900 * Disable learning on ingress. 1901 */ 1902 MLXSW_ITEM32(afa, ignore, disable_learning, 0x00, 29, 1); 1903 1904 /* afa_ignore_disable_security 1905 * Disable security lookup on ingress. 1906 * Reserved when Spectrum-1. 1907 */ 1908 MLXSW_ITEM32(afa, ignore, disable_security, 0x00, 28, 1); 1909 mlxsw_afa_ignore_pack(char * payload,bool disable_learning,bool disable_security)1910 static void mlxsw_afa_ignore_pack(char *payload, bool disable_learning, 1911 bool disable_security) 1912 { 1913 mlxsw_afa_ignore_disable_learning_set(payload, disable_learning); 1914 mlxsw_afa_ignore_disable_security_set(payload, disable_security); 1915 } 1916 mlxsw_afa_block_append_ignore(struct mlxsw_afa_block * block,bool disable_learning,bool disable_security)1917 int mlxsw_afa_block_append_ignore(struct mlxsw_afa_block *block, 1918 bool disable_learning, bool disable_security) 1919 { 1920 char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_IGNORE_CODE, 1921 MLXSW_AFA_IGNORE_SIZE); 1922 1923 if (IS_ERR(act)) 1924 return PTR_ERR(act); 1925 mlxsw_afa_ignore_pack(act, disable_learning, disable_security); 1926 return 0; 1927 } 1928 EXPORT_SYMBOL(mlxsw_afa_block_append_ignore); 1929 1930 /* MC Routing Action 1931 * ----------------- 1932 * The Multicast router action. Can be used by RMFT_V2 - Router Multicast 1933 * Forwarding Table Version 2 Register. 1934 */ 1935 1936 #define MLXSW_AFA_MCROUTER_CODE 0x10 1937 #define MLXSW_AFA_MCROUTER_SIZE 2 1938 1939 enum mlxsw_afa_mcrouter_rpf_action { 1940 MLXSW_AFA_MCROUTER_RPF_ACTION_NOP, 1941 MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP, 1942 MLXSW_AFA_MCROUTER_RPF_ACTION_DISCARD_ERROR, 1943 }; 1944 1945 /* afa_mcrouter_rpf_action */ 1946 MLXSW_ITEM32(afa, mcrouter, rpf_action, 0x00, 28, 3); 1947 1948 /* afa_mcrouter_expected_irif */ 1949 MLXSW_ITEM32(afa, mcrouter, expected_irif, 0x00, 0, 16); 1950 1951 /* afa_mcrouter_min_mtu */ 1952 MLXSW_ITEM32(afa, mcrouter, min_mtu, 0x08, 0, 16); 1953 1954 enum mlxsw_afa_mrouter_vrmid { 1955 MLXSW_AFA_MCROUTER_VRMID_INVALID, 1956 MLXSW_AFA_MCROUTER_VRMID_VALID 1957 }; 1958 1959 /* afa_mcrouter_vrmid 1960 * Valid RMID: rigr_rmid_index is used as RMID 1961 */ 1962 MLXSW_ITEM32(afa, mcrouter, vrmid, 0x0C, 31, 1); 1963 1964 /* afa_mcrouter_rigr_rmid_index 1965 * When the vrmid field is set to invalid, the field is used as pointer to 1966 * Router Interface Group (RIGR) Table in the KVD linear. 1967 * When the vrmid is set to valid, the field is used as RMID index, ranged 1968 * from 0 to max_mid - 1. The index is to the Port Group Table. 1969 */ 1970 MLXSW_ITEM32(afa, mcrouter, rigr_rmid_index, 0x0C, 0, 24); 1971 1972 static inline void mlxsw_afa_mcrouter_pack(char * payload,enum mlxsw_afa_mcrouter_rpf_action rpf_action,u16 expected_irif,u16 min_mtu,enum mlxsw_afa_mrouter_vrmid vrmid,u32 rigr_rmid_index)1973 mlxsw_afa_mcrouter_pack(char *payload, 1974 enum mlxsw_afa_mcrouter_rpf_action rpf_action, 1975 u16 expected_irif, u16 min_mtu, 1976 enum mlxsw_afa_mrouter_vrmid vrmid, u32 rigr_rmid_index) 1977 1978 { 1979 mlxsw_afa_mcrouter_rpf_action_set(payload, rpf_action); 1980 mlxsw_afa_mcrouter_expected_irif_set(payload, expected_irif); 1981 mlxsw_afa_mcrouter_min_mtu_set(payload, min_mtu); 1982 mlxsw_afa_mcrouter_vrmid_set(payload, vrmid); 1983 mlxsw_afa_mcrouter_rigr_rmid_index_set(payload, rigr_rmid_index); 1984 } 1985 mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block * block,u16 expected_irif,u16 min_mtu,bool rmid_valid,u32 kvdl_index)1986 int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block, 1987 u16 expected_irif, u16 min_mtu, 1988 bool rmid_valid, u32 kvdl_index) 1989 { 1990 char *act = mlxsw_afa_block_append_action(block, 1991 MLXSW_AFA_MCROUTER_CODE, 1992 MLXSW_AFA_MCROUTER_SIZE); 1993 if (IS_ERR(act)) 1994 return PTR_ERR(act); 1995 mlxsw_afa_mcrouter_pack(act, MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP, 1996 expected_irif, min_mtu, rmid_valid, kvdl_index); 1997 return 0; 1998 } 1999 EXPORT_SYMBOL(mlxsw_afa_block_append_mcrouter); 2000 2001 /* SIP DIP Action 2002 * -------------- 2003 * The SIP_DIP_ACTION is used for modifying the SIP and DIP fields of the 2004 * packet, e.g. for NAT. The L3 checksum is updated. Also, if the L4 is TCP or 2005 * if the L4 is UDP and the checksum field is not zero, then the L4 checksum is 2006 * updated. 2007 */ 2008 2009 #define MLXSW_AFA_IP_CODE 0x11 2010 #define MLXSW_AFA_IP_SIZE 2 2011 2012 enum mlxsw_afa_ip_s_d { 2013 /* ip refers to dip */ 2014 MLXSW_AFA_IP_S_D_DIP, 2015 /* ip refers to sip */ 2016 MLXSW_AFA_IP_S_D_SIP, 2017 }; 2018 2019 /* afa_ip_s_d 2020 * Source or destination. 2021 */ 2022 MLXSW_ITEM32(afa, ip, s_d, 0x00, 31, 1); 2023 2024 enum mlxsw_afa_ip_m_l { 2025 /* LSB: ip[63:0] refers to ip[63:0] */ 2026 MLXSW_AFA_IP_M_L_LSB, 2027 /* MSB: ip[63:0] refers to ip[127:64] */ 2028 MLXSW_AFA_IP_M_L_MSB, 2029 }; 2030 2031 /* afa_ip_m_l 2032 * MSB or LSB. 2033 */ 2034 MLXSW_ITEM32(afa, ip, m_l, 0x00, 30, 1); 2035 2036 /* afa_ip_ip_63_32 2037 * Bits [63:32] in the IP address to change to. 2038 */ 2039 MLXSW_ITEM32(afa, ip, ip_63_32, 0x08, 0, 32); 2040 2041 /* afa_ip_ip_31_0 2042 * Bits [31:0] in the IP address to change to. 2043 */ 2044 MLXSW_ITEM32(afa, ip, ip_31_0, 0x0C, 0, 32); 2045 mlxsw_afa_ip_pack(char * payload,enum mlxsw_afa_ip_s_d s_d,enum mlxsw_afa_ip_m_l m_l,u32 ip_31_0,u32 ip_63_32)2046 static void mlxsw_afa_ip_pack(char *payload, enum mlxsw_afa_ip_s_d s_d, 2047 enum mlxsw_afa_ip_m_l m_l, u32 ip_31_0, 2048 u32 ip_63_32) 2049 { 2050 mlxsw_afa_ip_s_d_set(payload, s_d); 2051 mlxsw_afa_ip_m_l_set(payload, m_l); 2052 mlxsw_afa_ip_ip_31_0_set(payload, ip_31_0); 2053 mlxsw_afa_ip_ip_63_32_set(payload, ip_63_32); 2054 } 2055 mlxsw_afa_block_append_ip(struct mlxsw_afa_block * block,bool is_dip,bool is_lsb,u32 val_31_0,u32 val_63_32,struct netlink_ext_ack * extack)2056 int mlxsw_afa_block_append_ip(struct mlxsw_afa_block *block, bool is_dip, 2057 bool is_lsb, u32 val_31_0, u32 val_63_32, 2058 struct netlink_ext_ack *extack) 2059 { 2060 enum mlxsw_afa_ip_s_d s_d = is_dip ? MLXSW_AFA_IP_S_D_DIP : 2061 MLXSW_AFA_IP_S_D_SIP; 2062 enum mlxsw_afa_ip_m_l m_l = is_lsb ? MLXSW_AFA_IP_M_L_LSB : 2063 MLXSW_AFA_IP_M_L_MSB; 2064 char *act = mlxsw_afa_block_append_action(block, 2065 MLXSW_AFA_IP_CODE, 2066 MLXSW_AFA_IP_SIZE); 2067 2068 if (IS_ERR(act)) { 2069 NL_SET_ERR_MSG_MOD(extack, "Cannot append IP action"); 2070 return PTR_ERR(act); 2071 } 2072 2073 mlxsw_afa_ip_pack(act, s_d, m_l, val_31_0, val_63_32); 2074 return 0; 2075 } 2076 EXPORT_SYMBOL(mlxsw_afa_block_append_ip); 2077 2078 /* L4 Port Action 2079 * -------------- 2080 * The L4_PORT_ACTION is used for modifying the sport and dport fields of the packet, e.g. for NAT. 2081 * If (the L4 is TCP) or if (the L4 is UDP and checksum field!=0) then the L4 checksum is updated. 2082 */ 2083 2084 #define MLXSW_AFA_L4PORT_CODE 0x12 2085 #define MLXSW_AFA_L4PORT_SIZE 1 2086 2087 enum mlxsw_afa_l4port_s_d { 2088 /* configure src_l4_port */ 2089 MLXSW_AFA_L4PORT_S_D_SRC, 2090 /* configure dst_l4_port */ 2091 MLXSW_AFA_L4PORT_S_D_DST, 2092 }; 2093 2094 /* afa_l4port_s_d 2095 * Source or destination. 2096 */ 2097 MLXSW_ITEM32(afa, l4port, s_d, 0x00, 31, 1); 2098 2099 /* afa_l4port_l4_port 2100 * Number of port to change to. 2101 */ 2102 MLXSW_ITEM32(afa, l4port, l4_port, 0x08, 0, 16); 2103 mlxsw_afa_l4port_pack(char * payload,enum mlxsw_afa_l4port_s_d s_d,u16 l4_port)2104 static void mlxsw_afa_l4port_pack(char *payload, enum mlxsw_afa_l4port_s_d s_d, u16 l4_port) 2105 { 2106 mlxsw_afa_l4port_s_d_set(payload, s_d); 2107 mlxsw_afa_l4port_l4_port_set(payload, l4_port); 2108 } 2109 mlxsw_afa_block_append_l4port(struct mlxsw_afa_block * block,bool is_dport,u16 l4_port,struct netlink_ext_ack * extack)2110 int mlxsw_afa_block_append_l4port(struct mlxsw_afa_block *block, bool is_dport, u16 l4_port, 2111 struct netlink_ext_ack *extack) 2112 { 2113 enum mlxsw_afa_l4port_s_d s_d = is_dport ? MLXSW_AFA_L4PORT_S_D_DST : 2114 MLXSW_AFA_L4PORT_S_D_SRC; 2115 char *act = mlxsw_afa_block_append_action(block, 2116 MLXSW_AFA_L4PORT_CODE, 2117 MLXSW_AFA_L4PORT_SIZE); 2118 2119 if (IS_ERR(act)) { 2120 NL_SET_ERR_MSG_MOD(extack, "Cannot append L4_PORT action"); 2121 return PTR_ERR(act); 2122 } 2123 2124 mlxsw_afa_l4port_pack(act, s_d, l4_port); 2125 return 0; 2126 } 2127 EXPORT_SYMBOL(mlxsw_afa_block_append_l4port); 2128 2129 /* Mirror Sampler Action 2130 * --------------------- 2131 * The SAMPLER_ACTION is used to mirror packets with a probability (sampling). 2132 */ 2133 2134 #define MLXSW_AFA_SAMPLER_CODE 0x13 2135 #define MLXSW_AFA_SAMPLER_SIZE 1 2136 2137 /* afa_sampler_mirror_agent 2138 * Mirror (SPAN) agent. 2139 */ 2140 MLXSW_ITEM32(afa, sampler, mirror_agent, 0x04, 0, 3); 2141 2142 #define MLXSW_AFA_SAMPLER_RATE_MAX (BIT(24) - 1) 2143 2144 /* afa_sampler_mirror_probability_rate 2145 * Mirroring probability. 2146 * Valid values are 1 to 2^24 - 1 2147 */ 2148 MLXSW_ITEM32(afa, sampler, mirror_probability_rate, 0x08, 0, 24); 2149 mlxsw_afa_sampler_pack(char * payload,u8 mirror_agent,u32 rate)2150 static void mlxsw_afa_sampler_pack(char *payload, u8 mirror_agent, u32 rate) 2151 { 2152 mlxsw_afa_sampler_mirror_agent_set(payload, mirror_agent); 2153 mlxsw_afa_sampler_mirror_probability_rate_set(payload, rate); 2154 } 2155 2156 struct mlxsw_afa_sampler { 2157 struct mlxsw_afa_resource resource; 2158 int span_id; 2159 u16 local_port; 2160 bool ingress; 2161 }; 2162 mlxsw_afa_sampler_destroy(struct mlxsw_afa_block * block,struct mlxsw_afa_sampler * sampler)2163 static void mlxsw_afa_sampler_destroy(struct mlxsw_afa_block *block, 2164 struct mlxsw_afa_sampler *sampler) 2165 { 2166 mlxsw_afa_resource_del(&sampler->resource); 2167 block->afa->ops->sampler_del(block->afa->ops_priv, sampler->local_port, 2168 sampler->span_id, sampler->ingress); 2169 kfree(sampler); 2170 } 2171 mlxsw_afa_sampler_destructor(struct mlxsw_afa_block * block,struct mlxsw_afa_resource * resource)2172 static void mlxsw_afa_sampler_destructor(struct mlxsw_afa_block *block, 2173 struct mlxsw_afa_resource *resource) 2174 { 2175 struct mlxsw_afa_sampler *sampler; 2176 2177 sampler = container_of(resource, struct mlxsw_afa_sampler, resource); 2178 mlxsw_afa_sampler_destroy(block, sampler); 2179 } 2180 2181 static struct mlxsw_afa_sampler * mlxsw_afa_sampler_create(struct mlxsw_afa_block * block,u16 local_port,struct psample_group * psample_group,u32 rate,u32 trunc_size,bool truncate,bool ingress,struct netlink_ext_ack * extack)2182 mlxsw_afa_sampler_create(struct mlxsw_afa_block *block, u16 local_port, 2183 struct psample_group *psample_group, u32 rate, 2184 u32 trunc_size, bool truncate, bool ingress, 2185 struct netlink_ext_ack *extack) 2186 { 2187 struct mlxsw_afa_sampler *sampler; 2188 int err; 2189 2190 sampler = kzalloc(sizeof(*sampler), GFP_KERNEL); 2191 if (!sampler) 2192 return ERR_PTR(-ENOMEM); 2193 2194 err = block->afa->ops->sampler_add(block->afa->ops_priv, local_port, 2195 psample_group, rate, trunc_size, 2196 truncate, ingress, &sampler->span_id, 2197 extack); 2198 if (err) 2199 goto err_sampler_add; 2200 2201 sampler->ingress = ingress; 2202 sampler->local_port = local_port; 2203 sampler->resource.destructor = mlxsw_afa_sampler_destructor; 2204 mlxsw_afa_resource_add(block, &sampler->resource); 2205 return sampler; 2206 2207 err_sampler_add: 2208 kfree(sampler); 2209 return ERR_PTR(err); 2210 } 2211 2212 static int mlxsw_afa_block_append_allocated_sampler(struct mlxsw_afa_block * block,u8 mirror_agent,u32 rate)2213 mlxsw_afa_block_append_allocated_sampler(struct mlxsw_afa_block *block, 2214 u8 mirror_agent, u32 rate) 2215 { 2216 char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_SAMPLER_CODE, 2217 MLXSW_AFA_SAMPLER_SIZE); 2218 2219 if (IS_ERR(act)) 2220 return PTR_ERR(act); 2221 mlxsw_afa_sampler_pack(act, mirror_agent, rate); 2222 return 0; 2223 } 2224 mlxsw_afa_block_append_sampler(struct mlxsw_afa_block * block,u16 local_port,struct psample_group * psample_group,u32 rate,u32 trunc_size,bool truncate,bool ingress,struct netlink_ext_ack * extack)2225 int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u16 local_port, 2226 struct psample_group *psample_group, 2227 u32 rate, u32 trunc_size, bool truncate, 2228 bool ingress, 2229 struct netlink_ext_ack *extack) 2230 { 2231 struct mlxsw_afa_sampler *sampler; 2232 int err; 2233 2234 if (rate > MLXSW_AFA_SAMPLER_RATE_MAX) { 2235 NL_SET_ERR_MSG_MOD(extack, "Sampling rate is too high"); 2236 return -EINVAL; 2237 } 2238 2239 sampler = mlxsw_afa_sampler_create(block, local_port, psample_group, 2240 rate, trunc_size, truncate, ingress, 2241 extack); 2242 if (IS_ERR(sampler)) 2243 return PTR_ERR(sampler); 2244 2245 err = mlxsw_afa_block_append_allocated_sampler(block, sampler->span_id, 2246 rate); 2247 if (err) { 2248 NL_SET_ERR_MSG_MOD(extack, "Cannot append sampler action"); 2249 goto err_append_allocated_sampler; 2250 } 2251 2252 return 0; 2253 2254 err_append_allocated_sampler: 2255 mlxsw_afa_sampler_destroy(block, sampler); 2256 return err; 2257 } 2258 EXPORT_SYMBOL(mlxsw_afa_block_append_sampler); 2259