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 18enum 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 */ 26MLXSW_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 */ 31MLXSW_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 */ 38MLXSW_ITEM32(afa, set, goto_g, 0xA4, 29, 1); 39 40enum 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 */ 50MLXSW_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 */ 56MLXSW_ITEM32(afa, set, goto_next_binding, 0xA4, 0, 16); 57 58/* afa_all_action_type 59 * Action Type. 60 */ 61MLXSW_ITEM32(afa, all, action_type, 0x00, 24, 6); 62 63struct 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 77struct 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 89struct 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 108static 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 115struct mlxsw_afa_fwd_entry_ht_key { 116 u16 local_port; 117}; 118 119struct 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 126static 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 133struct 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 141static 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 148static 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 155static 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 162static 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 174static 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 182struct 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 190static 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 197struct 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 229err_policer_rhashtable_init: 230 rhashtable_destroy(&mlxsw_afa->cookie_ht); 231err_cookie_rhashtable_init: 232 rhashtable_destroy(&mlxsw_afa->fwd_entry_ht); 233err_fwd_entry_rhashtable_init: 234 rhashtable_destroy(&mlxsw_afa->set_ht); 235err_set_rhashtable_init: 236 kfree(mlxsw_afa); 237 return ERR_PTR(err); 238} 239EXPORT_SYMBOL(mlxsw_afa_create); 240 241void 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} 252EXPORT_SYMBOL(mlxsw_afa_destroy); 253 254static 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 266static 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 275static 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 289static void mlxsw_afa_set_destroy(struct mlxsw_afa_set *set) 290{ 291 kfree(set); 292} 293 294static 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 313err_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 319static 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 330static 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 340static 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 368struct 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 379struct mlxsw_afa_resource { 380 struct list_head list; 381 void (*destructor)(struct mlxsw_afa_block *block, 382 struct mlxsw_afa_resource *resource); 383}; 384 385static 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 391static void mlxsw_afa_resource_del(struct mlxsw_afa_resource *resource) 392{ 393 list_del(&resource->list); 394} 395 396static 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 405struct 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 435err_second_set_create: 436 mlxsw_afa_set_destroy(block->first_set); 437err_first_set_create: 438 kfree(block); 439 return ERR_PTR(-ENOMEM); 440} 441EXPORT_SYMBOL(mlxsw_afa_block_create); 442 443void 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} 456EXPORT_SYMBOL(mlxsw_afa_block_destroy); 457 458int 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} 490EXPORT_SYMBOL(mlxsw_afa_block_commit); 491 492char *mlxsw_afa_block_first_set(struct mlxsw_afa_block *block) 493{ 494 return block->first_set->ht_key.enc_actions; 495} 496EXPORT_SYMBOL(mlxsw_afa_block_first_set); 497 498char *mlxsw_afa_block_cur_set(struct mlxsw_afa_block *block) 499{ 500 return block->cur_set->ht_key.enc_actions; 501} 502EXPORT_SYMBOL(mlxsw_afa_block_cur_set); 503 504u32 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} 513EXPORT_SYMBOL(mlxsw_afa_block_first_kvdl_index); 514 515int 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} 522EXPORT_SYMBOL(mlxsw_afa_block_activity_get); 523 524int 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} 533EXPORT_SYMBOL(mlxsw_afa_block_continue); 534 535int 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} 544EXPORT_SYMBOL(mlxsw_afa_block_jump); 545 546int 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} 555EXPORT_SYMBOL(mlxsw_afa_block_terminate); 556 557static struct mlxsw_afa_fwd_entry * 558mlxsw_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 582err_kvdl_fwd_entry_add: 583 rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node, 584 mlxsw_afa_fwd_entry_ht_params); 585err_rhashtable_insert: 586 kfree(fwd_entry); 587 return ERR_PTR(err); 588} 589 590static 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 600static struct mlxsw_afa_fwd_entry * 601mlxsw_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 616static 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 624struct mlxsw_afa_fwd_entry_ref { 625 struct mlxsw_afa_resource resource; 626 struct mlxsw_afa_fwd_entry *fwd_entry; 627}; 628 629static void 630mlxsw_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 638static void 639mlxsw_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 649static struct mlxsw_afa_fwd_entry_ref * 650mlxsw_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 669err_fwd_entry_get: 670 kfree(fwd_entry_ref); 671 return ERR_PTR(err); 672} 673 674struct mlxsw_afa_counter { 675 struct mlxsw_afa_resource resource; 676 u32 counter_index; 677}; 678 679static void 680mlxsw_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 689static void 690mlxsw_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 699static struct mlxsw_afa_counter * 700mlxsw_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 717err_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 728static struct mlxsw_afa_cookie * 729mlxsw_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 761err_idr_alloc: 762 rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 763 mlxsw_afa_cookie_ht_params); 764err_rhashtable_insert: 765 kfree(cookie); 766 return ERR_PTR(err); 767} 768 769static 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 778static struct mlxsw_afa_cookie * 779mlxsw_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 793static 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 */ 802const struct flow_action_cookie * 803mlxsw_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} 815EXPORT_SYMBOL(mlxsw_afa_cookie_lookup); 816 817struct mlxsw_afa_cookie_ref { 818 struct mlxsw_afa_resource resource; 819 struct mlxsw_afa_cookie *cookie; 820}; 821 822static void 823mlxsw_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 831static void 832mlxsw_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 842static struct mlxsw_afa_cookie_ref * 843mlxsw_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 863err_cookie_get: 864 kfree(cookie_ref); 865 return ERR_PTR(err); 866} 867 868static struct mlxsw_afa_policer * 869mlxsw_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 898err_rhashtable_insert: 899 mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv, 900 policer->policer_index); 901err_policer_add: 902 kfree(policer); 903 return ERR_PTR(err); 904} 905 906static 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 917static struct mlxsw_afa_policer * 918mlxsw_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 935static 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 943struct mlxsw_afa_policer_ref { 944 struct mlxsw_afa_resource resource; 945 struct mlxsw_afa_policer *policer; 946}; 947 948static void 949mlxsw_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 957static void 958mlxsw_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 968static struct mlxsw_afa_policer_ref * 969mlxsw_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 994err_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 1002enum mlxsw_afa_action_type { 1003 MLXSW_AFA_ACTION_TYPE_TRAP, 1004 MLXSW_AFA_ACTION_TYPE_POLICE, 1005 MLXSW_AFA_ACTION_TYPE_OTHER, 1006}; 1007 1008static bool 1009mlxsw_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 1023static 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 1066static 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 1084enum 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 1090enum 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 */ 1102MLXSW_ITEM32(afa, vlan, vlan_tag_cmd, 0x00, 29, 3); 1103 1104/* afa_vlan_vid_cmd */ 1105MLXSW_ITEM32(afa, vlan, vid_cmd, 0x04, 29, 3); 1106 1107/* afa_vlan_vid */ 1108MLXSW_ITEM32(afa, vlan, vid, 0x04, 0, 12); 1109 1110/* afa_vlan_ethertype_cmd */ 1111MLXSW_ITEM32(afa, vlan, ethertype_cmd, 0x08, 29, 3); 1112 1113/* afa_vlan_ethertype 1114 * Index to EtherTypes in Switch VLAN EtherType Register (SVER). 1115 */ 1116MLXSW_ITEM32(afa, vlan, ethertype, 0x08, 24, 3); 1117 1118/* afa_vlan_pcp_cmd */ 1119MLXSW_ITEM32(afa, vlan, pcp_cmd, 0x08, 13, 3); 1120 1121/* afa_vlan_pcp */ 1122MLXSW_ITEM32(afa, vlan, pcp, 0x08, 8, 3); 1123 1124static inline void 1125mlxsw_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 1140int 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} 1158EXPORT_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 1179enum 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 */ 1187MLXSW_ITEM32(afa, trap, trap_action, 0x00, 24, 4); 1188 1189enum 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 */ 1197MLXSW_ITEM32(afa, trap, forward_action, 0x00, 0, 4); 1198 1199/* afa_trap_trap_id 1200 * Trap ID to configure. 1201 */ 1202MLXSW_ITEM32(afa, trap, trap_id, 0x04, 0, 9); 1203 1204/* afa_trap_mirror_agent 1205 * Mirror agent. 1206 */ 1207MLXSW_ITEM32(afa, trap, mirror_agent, 0x08, 29, 3); 1208 1209/* afa_trap_mirror_enable 1210 * Mirror enable. 1211 */ 1212MLXSW_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 */ 1221MLXSW_ITEM32(afa, trap, user_def_val, 0x0C, 0, 20); 1222 1223static inline void 1224mlxsw_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 1234static inline void 1235mlxsw_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 1244static inline void 1245mlxsw_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 1252static 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 1260static 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 1276static int 1277mlxsw_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 1308err_append_action: 1309 mlxsw_afa_cookie_ref_destroy(block, cookie_ref); 1310 return err; 1311} 1312 1313int 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} 1322EXPORT_SYMBOL(mlxsw_afa_block_append_drop); 1323 1324int 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} 1336EXPORT_SYMBOL(mlxsw_afa_block_append_trap); 1337 1338int 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} 1351EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward); 1352 1353struct mlxsw_afa_mirror { 1354 struct mlxsw_afa_resource resource; 1355 int span_id; 1356 u16 local_in_port; 1357 bool ingress; 1358}; 1359 1360static void 1361mlxsw_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 1372static void 1373mlxsw_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 1382static struct mlxsw_afa_mirror * 1383mlxsw_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 1405err_mirror_add: 1406 kfree(mirror); 1407 return ERR_PTR(err); 1408} 1409 1410static int 1411mlxsw_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 1426int 1427mlxsw_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 1448err_append_allocated_mirror: 1449 mlxsw_afa_mirror_destroy(block, mirror); 1450 return err; 1451} 1452EXPORT_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 1464enum 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 */ 1473MLXSW_ITEM32(afa, qos, ecn_cmd, 0x04, 29, 3); 1474 1475/* afa_qos_ecn 1476 * ECN value. 1477 */ 1478MLXSW_ITEM32(afa, qos, ecn, 0x04, 24, 2); 1479 1480enum 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 */ 1494MLXSW_ITEM32(afa, qos, dscp_cmd, 0x04, 14, 2); 1495 1496/* afa_qos_dscp 1497 * DSCP value. 1498 */ 1499MLXSW_ITEM32(afa, qos, dscp, 0x04, 0, 6); 1500 1501enum 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 */ 1510MLXSW_ITEM32(afa, qos, switch_prio_cmd, 0x08, 14, 2); 1511 1512/* afa_qos_switch_prio 1513 * Switch Priority. 1514 */ 1515MLXSW_ITEM32(afa, qos, switch_prio, 0x08, 0, 4); 1516 1517enum 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 */ 1526MLXSW_ITEM32(afa, qos, dscp_rw, 0x0C, 30, 2); 1527 1528static inline void 1529mlxsw_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 1536static inline void 1537mlxsw_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 1544static inline void 1545mlxsw_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 1553static 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 1578int 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} 1587EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dsfield); 1588 1589int 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} 1597EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dscp); 1598 1599int 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} 1607EXPORT_SYMBOL(mlxsw_afa_block_append_qos_ecn); 1608 1609int 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} 1625EXPORT_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 1636enum 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 */ 1644MLXSW_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 */ 1650MLXSW_ITEM32(afa, forward, pbs_ptr, 0x08, 0, 24); 1651 1652/* afa_forward_in_port 1653 * Packet is forwarded back to the ingress port. 1654 */ 1655MLXSW_ITEM32(afa, forward, in_port, 0x0C, 0, 1); 1656 1657static inline void 1658mlxsw_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 1666int 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 1697err_append_action: 1698 mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref); 1699 return err; 1700} 1701EXPORT_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 1712enum { 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 */ 1723MLXSW_ITEM32(afa, polcnt, c_p, 0x00, 31, 1); 1724 1725enum 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 */ 1737MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8); 1738 1739/* afa_polcnt_counter_index 1740 * Counter index for flow counters. 1741 */ 1742MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24); 1743 1744/* afa_polcnt_pid 1745 * Policer ID. 1746 * Reserved when c_p = 0 1747 */ 1748MLXSW_ITEM32(afa, polcnt, pid, 0x08, 0, 14); 1749 1750static inline void 1751mlxsw_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 1760static 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 1766int 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} 1777EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter); 1778 1779int 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 1803err_append_allocated_counter: 1804 mlxsw_afa_counter_destroy(block, counter); 1805 return err; 1806} 1807EXPORT_SYMBOL(mlxsw_afa_block_append_counter); 1808 1809int 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 1837err_append_action: 1838 mlxsw_afa_policer_ref_destroy(block, policer_ref); 1839 return err; 1840} 1841EXPORT_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 1852enum 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 */ 1860MLXSW_ITEM32(afa, virfwd, fid_cmd, 0x08, 29, 3); 1861 1862/* afa_virfwd_fid 1863 * The FID value. 1864 */ 1865MLXSW_ITEM32(afa, virfwd, fid, 0x08, 0, 16); 1866 1867static 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 1875int 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} 1888EXPORT_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 */ 1902MLXSW_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 */ 1908MLXSW_ITEM32(afa, ignore, disable_security, 0x00, 28, 1); 1909 1910static 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 1917int 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} 1928EXPORT_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 1939enum 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 */ 1946MLXSW_ITEM32(afa, mcrouter, rpf_action, 0x00, 28, 3); 1947 1948/* afa_mcrouter_expected_irif */ 1949MLXSW_ITEM32(afa, mcrouter, expected_irif, 0x00, 0, 16); 1950 1951/* afa_mcrouter_min_mtu */ 1952MLXSW_ITEM32(afa, mcrouter, min_mtu, 0x08, 0, 16); 1953 1954enum 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 */ 1962MLXSW_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 */ 1970MLXSW_ITEM32(afa, mcrouter, rigr_rmid_index, 0x0C, 0, 24); 1971 1972static inline void 1973mlxsw_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 1986int 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} 1999EXPORT_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 2012enum 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 */ 2022MLXSW_ITEM32(afa, ip, s_d, 0x00, 31, 1); 2023 2024enum 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 */ 2034MLXSW_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 */ 2039MLXSW_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 */ 2044MLXSW_ITEM32(afa, ip, ip_31_0, 0x0C, 0, 32); 2045 2046static 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 2056int 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} 2076EXPORT_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 2087enum 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 */ 2097MLXSW_ITEM32(afa, l4port, s_d, 0x00, 31, 1); 2098 2099/* afa_l4port_l4_port 2100 * Number of port to change to. 2101 */ 2102MLXSW_ITEM32(afa, l4port, l4_port, 0x08, 0, 16); 2103 2104static 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 2110int 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} 2127EXPORT_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 */ 2140MLXSW_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 */ 2148MLXSW_ITEM32(afa, sampler, mirror_probability_rate, 0x08, 0, 24); 2149 2150static 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 2156struct mlxsw_afa_sampler { 2157 struct mlxsw_afa_resource resource; 2158 int span_id; 2159 u16 local_port; 2160 bool ingress; 2161}; 2162 2163static 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 2172static 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 2181static struct mlxsw_afa_sampler * 2182mlxsw_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 2207err_sampler_add: 2208 kfree(sampler); 2209 return ERR_PTR(err); 2210} 2211 2212static int 2213mlxsw_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 2225int 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 2254err_append_allocated_sampler: 2255 mlxsw_afa_sampler_destroy(block, sampler); 2256 return err; 2257} 2258EXPORT_SYMBOL(mlxsw_afa_block_append_sampler); 2259