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 unsigned int 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 u8 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 unsigned int 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 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 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 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 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 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 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 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 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 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 set->ref_count = 1; 286 return set; 287 } 288 289 static void mlxsw_afa_set_destroy(struct mlxsw_afa_set *set) 290 { 291 kfree(set); 292 } 293 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 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 330 static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa, 331 struct mlxsw_afa_set *set) 332 { 333 if (--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 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 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 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 391 static void mlxsw_afa_resource_del(struct mlxsw_afa_resource *resource) 392 { 393 list_del(&resource->list); 394 } 395 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 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 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 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 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 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 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 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 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 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 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 * 558 mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u8 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 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 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 * 601 mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u8 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 fwd_entry->ref_count++; 611 return fwd_entry; 612 } 613 return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port); 614 } 615 616 static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa, 617 struct mlxsw_afa_fwd_entry *fwd_entry) 618 { 619 if (--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 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 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 * 650 mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u8 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 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 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 * 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 * 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 memcpy(&cookie->fa_cookie, fa_cookie, 741 sizeof(*fa_cookie) + fa_cookie->cookie_len); 742 743 err = rhashtable_insert_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 744 mlxsw_afa_cookie_ht_params); 745 if (err) 746 goto err_rhashtable_insert; 747 748 /* Start cookie indexes with 1. Leave the 0 index unused. Packets 749 * that come from the HW which are not dropped by drop-with-cookie 750 * action are going to pass cookie_index 0 to lookup. 751 */ 752 cookie_index = 1; 753 err = idr_alloc_u32(&mlxsw_afa->cookie_idr, cookie, &cookie_index, 754 MLXSW_AFA_COOKIE_INDEX_MAX, GFP_KERNEL); 755 if (err) 756 goto err_idr_alloc; 757 cookie->cookie_index = cookie_index; 758 return cookie; 759 760 err_idr_alloc: 761 rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 762 mlxsw_afa_cookie_ht_params); 763 err_rhashtable_insert: 764 kfree(cookie); 765 return ERR_PTR(err); 766 } 767 768 static void mlxsw_afa_cookie_destroy(struct mlxsw_afa *mlxsw_afa, 769 struct mlxsw_afa_cookie *cookie) 770 { 771 idr_remove(&mlxsw_afa->cookie_idr, cookie->cookie_index); 772 rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, 773 mlxsw_afa_cookie_ht_params); 774 kfree_rcu(cookie, rcu); 775 } 776 777 static struct mlxsw_afa_cookie * 778 mlxsw_afa_cookie_get(struct mlxsw_afa *mlxsw_afa, 779 const struct flow_action_cookie *fa_cookie) 780 { 781 struct mlxsw_afa_cookie *cookie; 782 783 cookie = rhashtable_lookup_fast(&mlxsw_afa->cookie_ht, fa_cookie, 784 mlxsw_afa_cookie_ht_params); 785 if (cookie) { 786 refcount_inc(&cookie->ref_count); 787 return cookie; 788 } 789 return mlxsw_afa_cookie_create(mlxsw_afa, fa_cookie); 790 } 791 792 static void mlxsw_afa_cookie_put(struct mlxsw_afa *mlxsw_afa, 793 struct mlxsw_afa_cookie *cookie) 794 { 795 if (!refcount_dec_and_test(&cookie->ref_count)) 796 return; 797 mlxsw_afa_cookie_destroy(mlxsw_afa, cookie); 798 } 799 800 /* RCU read lock must be held */ 801 const struct flow_action_cookie * 802 mlxsw_afa_cookie_lookup(struct mlxsw_afa *mlxsw_afa, u32 cookie_index) 803 { 804 struct mlxsw_afa_cookie *cookie; 805 806 /* 0 index means no cookie */ 807 if (!cookie_index) 808 return NULL; 809 cookie = idr_find(&mlxsw_afa->cookie_idr, cookie_index); 810 if (!cookie) 811 return NULL; 812 return &cookie->fa_cookie; 813 } 814 EXPORT_SYMBOL(mlxsw_afa_cookie_lookup); 815 816 struct mlxsw_afa_cookie_ref { 817 struct mlxsw_afa_resource resource; 818 struct mlxsw_afa_cookie *cookie; 819 }; 820 821 static void 822 mlxsw_afa_cookie_ref_destroy(struct mlxsw_afa_block *block, 823 struct mlxsw_afa_cookie_ref *cookie_ref) 824 { 825 mlxsw_afa_resource_del(&cookie_ref->resource); 826 mlxsw_afa_cookie_put(block->afa, cookie_ref->cookie); 827 kfree(cookie_ref); 828 } 829 830 static void 831 mlxsw_afa_cookie_ref_destructor(struct mlxsw_afa_block *block, 832 struct mlxsw_afa_resource *resource) 833 { 834 struct mlxsw_afa_cookie_ref *cookie_ref; 835 836 cookie_ref = container_of(resource, struct mlxsw_afa_cookie_ref, 837 resource); 838 mlxsw_afa_cookie_ref_destroy(block, cookie_ref); 839 } 840 841 static struct mlxsw_afa_cookie_ref * 842 mlxsw_afa_cookie_ref_create(struct mlxsw_afa_block *block, 843 const struct flow_action_cookie *fa_cookie) 844 { 845 struct mlxsw_afa_cookie_ref *cookie_ref; 846 struct mlxsw_afa_cookie *cookie; 847 int err; 848 849 cookie_ref = kzalloc(sizeof(*cookie_ref), GFP_KERNEL); 850 if (!cookie_ref) 851 return ERR_PTR(-ENOMEM); 852 cookie = mlxsw_afa_cookie_get(block->afa, fa_cookie); 853 if (IS_ERR(cookie)) { 854 err = PTR_ERR(cookie); 855 goto err_cookie_get; 856 } 857 cookie_ref->cookie = cookie; 858 cookie_ref->resource.destructor = mlxsw_afa_cookie_ref_destructor; 859 mlxsw_afa_resource_add(block, &cookie_ref->resource); 860 return cookie_ref; 861 862 err_cookie_get: 863 kfree(cookie_ref); 864 return ERR_PTR(err); 865 } 866 867 static struct mlxsw_afa_policer * 868 mlxsw_afa_policer_create(struct mlxsw_afa *mlxsw_afa, u32 fa_index, 869 u64 rate_bytes_ps, u32 burst, 870 struct netlink_ext_ack *extack) 871 { 872 struct mlxsw_afa_policer *policer; 873 int err; 874 875 policer = kzalloc(sizeof(*policer), GFP_KERNEL); 876 if (!policer) 877 return ERR_PTR(-ENOMEM); 878 879 err = mlxsw_afa->ops->policer_add(mlxsw_afa->ops_priv, rate_bytes_ps, 880 burst, &policer->policer_index, 881 extack); 882 if (err) 883 goto err_policer_add; 884 885 refcount_set(&policer->ref_count, 1); 886 policer->fa_index = fa_index; 887 888 err = rhashtable_insert_fast(&mlxsw_afa->policer_ht, &policer->ht_node, 889 mlxsw_afa_policer_ht_params); 890 if (err) 891 goto err_rhashtable_insert; 892 893 list_add_tail(&policer->list, &mlxsw_afa->policer_list); 894 895 return policer; 896 897 err_rhashtable_insert: 898 mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv, 899 policer->policer_index); 900 err_policer_add: 901 kfree(policer); 902 return ERR_PTR(err); 903 } 904 905 static void mlxsw_afa_policer_destroy(struct mlxsw_afa *mlxsw_afa, 906 struct mlxsw_afa_policer *policer) 907 { 908 list_del(&policer->list); 909 rhashtable_remove_fast(&mlxsw_afa->policer_ht, &policer->ht_node, 910 mlxsw_afa_policer_ht_params); 911 mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv, 912 policer->policer_index); 913 kfree(policer); 914 } 915 916 static struct mlxsw_afa_policer * 917 mlxsw_afa_policer_get(struct mlxsw_afa *mlxsw_afa, u32 fa_index, 918 u64 rate_bytes_ps, u32 burst, 919 struct netlink_ext_ack *extack) 920 { 921 struct mlxsw_afa_policer *policer; 922 923 policer = rhashtable_lookup_fast(&mlxsw_afa->policer_ht, &fa_index, 924 mlxsw_afa_policer_ht_params); 925 if (policer) { 926 refcount_inc(&policer->ref_count); 927 return policer; 928 } 929 930 return mlxsw_afa_policer_create(mlxsw_afa, fa_index, rate_bytes_ps, 931 burst, extack); 932 } 933 934 static void mlxsw_afa_policer_put(struct mlxsw_afa *mlxsw_afa, 935 struct mlxsw_afa_policer *policer) 936 { 937 if (!refcount_dec_and_test(&policer->ref_count)) 938 return; 939 mlxsw_afa_policer_destroy(mlxsw_afa, policer); 940 } 941 942 struct mlxsw_afa_policer_ref { 943 struct mlxsw_afa_resource resource; 944 struct mlxsw_afa_policer *policer; 945 }; 946 947 static void 948 mlxsw_afa_policer_ref_destroy(struct mlxsw_afa_block *block, 949 struct mlxsw_afa_policer_ref *policer_ref) 950 { 951 mlxsw_afa_resource_del(&policer_ref->resource); 952 mlxsw_afa_policer_put(block->afa, policer_ref->policer); 953 kfree(policer_ref); 954 } 955 956 static void 957 mlxsw_afa_policer_ref_destructor(struct mlxsw_afa_block *block, 958 struct mlxsw_afa_resource *resource) 959 { 960 struct mlxsw_afa_policer_ref *policer_ref; 961 962 policer_ref = container_of(resource, struct mlxsw_afa_policer_ref, 963 resource); 964 mlxsw_afa_policer_ref_destroy(block, policer_ref); 965 } 966 967 static struct mlxsw_afa_policer_ref * 968 mlxsw_afa_policer_ref_create(struct mlxsw_afa_block *block, u32 fa_index, 969 u64 rate_bytes_ps, u32 burst, 970 struct netlink_ext_ack *extack) 971 { 972 struct mlxsw_afa_policer_ref *policer_ref; 973 struct mlxsw_afa_policer *policer; 974 int err; 975 976 policer_ref = kzalloc(sizeof(*policer_ref), GFP_KERNEL); 977 if (!policer_ref) 978 return ERR_PTR(-ENOMEM); 979 980 policer = mlxsw_afa_policer_get(block->afa, fa_index, rate_bytes_ps, 981 burst, extack); 982 if (IS_ERR(policer)) { 983 err = PTR_ERR(policer); 984 goto err_policer_get; 985 } 986 987 policer_ref->policer = policer; 988 policer_ref->resource.destructor = mlxsw_afa_policer_ref_destructor; 989 mlxsw_afa_resource_add(block, &policer_ref->resource); 990 991 return policer_ref; 992 993 err_policer_get: 994 kfree(policer_ref); 995 return ERR_PTR(err); 996 } 997 998 #define MLXSW_AFA_ONE_ACTION_LEN 32 999 #define MLXSW_AFA_PAYLOAD_OFFSET 4 1000 1001 enum mlxsw_afa_action_type { 1002 MLXSW_AFA_ACTION_TYPE_TRAP, 1003 MLXSW_AFA_ACTION_TYPE_POLICE, 1004 MLXSW_AFA_ACTION_TYPE_OTHER, 1005 }; 1006 1007 static bool 1008 mlxsw_afa_block_need_split(const struct mlxsw_afa_block *block, 1009 enum mlxsw_afa_action_type type) 1010 { 1011 struct mlxsw_afa_set *cur_set = block->cur_set; 1012 1013 /* Due to a hardware limitation, police action cannot be in the same 1014 * action set with MLXSW_AFA_TRAP_CODE or MLXSW_AFA_TRAPWU_CODE 1015 * actions. Work around this limitation by creating a new action set 1016 * and place the new action there. 1017 */ 1018 return (cur_set->has_trap && type == MLXSW_AFA_ACTION_TYPE_POLICE) || 1019 (cur_set->has_police && type == MLXSW_AFA_ACTION_TYPE_TRAP); 1020 } 1021 1022 static char *mlxsw_afa_block_append_action_ext(struct mlxsw_afa_block *block, 1023 u8 action_code, u8 action_size, 1024 enum mlxsw_afa_action_type type) 1025 { 1026 char *oneact; 1027 char *actions; 1028 1029 if (block->finished) 1030 return ERR_PTR(-EINVAL); 1031 if (block->cur_act_index + action_size > block->afa->max_acts_per_set || 1032 mlxsw_afa_block_need_split(block, type)) { 1033 struct mlxsw_afa_set *set; 1034 1035 /* The appended action won't fit into the current action set, 1036 * so create a new set. 1037 */ 1038 set = mlxsw_afa_set_create(false); 1039 if (!set) 1040 return ERR_PTR(-ENOBUFS); 1041 set->prev = block->cur_set; 1042 block->cur_act_index = 0; 1043 block->cur_set->next = set; 1044 block->cur_set = set; 1045 } 1046 1047 switch (type) { 1048 case MLXSW_AFA_ACTION_TYPE_TRAP: 1049 block->cur_set->has_trap = true; 1050 break; 1051 case MLXSW_AFA_ACTION_TYPE_POLICE: 1052 block->cur_set->has_police = true; 1053 break; 1054 default: 1055 break; 1056 } 1057 1058 actions = block->cur_set->ht_key.enc_actions; 1059 oneact = actions + block->cur_act_index * MLXSW_AFA_ONE_ACTION_LEN; 1060 block->cur_act_index += action_size; 1061 mlxsw_afa_all_action_type_set(oneact, action_code); 1062 return oneact + MLXSW_AFA_PAYLOAD_OFFSET; 1063 } 1064 1065 static char *mlxsw_afa_block_append_action(struct mlxsw_afa_block *block, 1066 u8 action_code, u8 action_size) 1067 { 1068 return mlxsw_afa_block_append_action_ext(block, action_code, 1069 action_size, 1070 MLXSW_AFA_ACTION_TYPE_OTHER); 1071 } 1072 1073 /* VLAN Action 1074 * ----------- 1075 * VLAN action is used for manipulating VLANs. It can be used to implement QinQ, 1076 * VLAN translation, change of PCP bits of the VLAN tag, push, pop as swap VLANs 1077 * and more. 1078 */ 1079 1080 #define MLXSW_AFA_VLAN_CODE 0x02 1081 #define MLXSW_AFA_VLAN_SIZE 1 1082 1083 enum mlxsw_afa_vlan_vlan_tag_cmd { 1084 MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP, 1085 MLXSW_AFA_VLAN_VLAN_TAG_CMD_PUSH_TAG, 1086 MLXSW_AFA_VLAN_VLAN_TAG_CMD_POP_TAG, 1087 }; 1088 1089 enum mlxsw_afa_vlan_cmd { 1090 MLXSW_AFA_VLAN_CMD_NOP, 1091 MLXSW_AFA_VLAN_CMD_SET_OUTER, 1092 MLXSW_AFA_VLAN_CMD_SET_INNER, 1093 MLXSW_AFA_VLAN_CMD_COPY_OUTER_TO_INNER, 1094 MLXSW_AFA_VLAN_CMD_COPY_INNER_TO_OUTER, 1095 MLXSW_AFA_VLAN_CMD_SWAP, 1096 }; 1097 1098 /* afa_vlan_vlan_tag_cmd 1099 * Tag command: push, pop, nop VLAN header. 1100 */ 1101 MLXSW_ITEM32(afa, vlan, vlan_tag_cmd, 0x00, 29, 3); 1102 1103 /* afa_vlan_vid_cmd */ 1104 MLXSW_ITEM32(afa, vlan, vid_cmd, 0x04, 29, 3); 1105 1106 /* afa_vlan_vid */ 1107 MLXSW_ITEM32(afa, vlan, vid, 0x04, 0, 12); 1108 1109 /* afa_vlan_ethertype_cmd */ 1110 MLXSW_ITEM32(afa, vlan, ethertype_cmd, 0x08, 29, 3); 1111 1112 /* afa_vlan_ethertype 1113 * Index to EtherTypes in Switch VLAN EtherType Register (SVER). 1114 */ 1115 MLXSW_ITEM32(afa, vlan, ethertype, 0x08, 24, 3); 1116 1117 /* afa_vlan_pcp_cmd */ 1118 MLXSW_ITEM32(afa, vlan, pcp_cmd, 0x08, 13, 3); 1119 1120 /* afa_vlan_pcp */ 1121 MLXSW_ITEM32(afa, vlan, pcp, 0x08, 8, 3); 1122 1123 static inline void 1124 mlxsw_afa_vlan_pack(char *payload, 1125 enum mlxsw_afa_vlan_vlan_tag_cmd vlan_tag_cmd, 1126 enum mlxsw_afa_vlan_cmd vid_cmd, u16 vid, 1127 enum mlxsw_afa_vlan_cmd pcp_cmd, u8 pcp, 1128 enum mlxsw_afa_vlan_cmd ethertype_cmd, u8 ethertype) 1129 { 1130 mlxsw_afa_vlan_vlan_tag_cmd_set(payload, vlan_tag_cmd); 1131 mlxsw_afa_vlan_vid_cmd_set(payload, vid_cmd); 1132 mlxsw_afa_vlan_vid_set(payload, vid); 1133 mlxsw_afa_vlan_pcp_cmd_set(payload, pcp_cmd); 1134 mlxsw_afa_vlan_pcp_set(payload, pcp); 1135 mlxsw_afa_vlan_ethertype_cmd_set(payload, ethertype_cmd); 1136 mlxsw_afa_vlan_ethertype_set(payload, ethertype); 1137 } 1138 1139 int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, 1140 u16 vid, u8 pcp, u8 et, 1141 struct netlink_ext_ack *extack) 1142 { 1143 char *act = mlxsw_afa_block_append_action(block, 1144 MLXSW_AFA_VLAN_CODE, 1145 MLXSW_AFA_VLAN_SIZE); 1146 1147 if (IS_ERR(act)) { 1148 NL_SET_ERR_MSG_MOD(extack, "Cannot append vlan_modify action"); 1149 return PTR_ERR(act); 1150 } 1151 mlxsw_afa_vlan_pack(act, MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP, 1152 MLXSW_AFA_VLAN_CMD_SET_OUTER, vid, 1153 MLXSW_AFA_VLAN_CMD_SET_OUTER, pcp, 1154 MLXSW_AFA_VLAN_CMD_SET_OUTER, et); 1155 return 0; 1156 } 1157 EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify); 1158 1159 /* Trap Action / Trap With Userdef Action 1160 * -------------------------------------- 1161 * The Trap action enables trapping / mirroring packets to the CPU 1162 * as well as discarding packets. 1163 * The ACL Trap / Discard separates the forward/discard control from CPU 1164 * trap control. In addition, the Trap / Discard action enables activating 1165 * SPAN (port mirroring). 1166 * 1167 * The Trap with userdef action action has the same functionality as 1168 * the Trap action with addition of user defined value that can be set 1169 * and used by higher layer applications. 1170 */ 1171 1172 #define MLXSW_AFA_TRAP_CODE 0x03 1173 #define MLXSW_AFA_TRAP_SIZE 1 1174 1175 #define MLXSW_AFA_TRAPWU_CODE 0x04 1176 #define MLXSW_AFA_TRAPWU_SIZE 2 1177 1178 enum mlxsw_afa_trap_trap_action { 1179 MLXSW_AFA_TRAP_TRAP_ACTION_NOP = 0, 1180 MLXSW_AFA_TRAP_TRAP_ACTION_TRAP = 2, 1181 }; 1182 1183 /* afa_trap_trap_action 1184 * Trap Action. 1185 */ 1186 MLXSW_ITEM32(afa, trap, trap_action, 0x00, 24, 4); 1187 1188 enum mlxsw_afa_trap_forward_action { 1189 MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD = 1, 1190 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD = 3, 1191 }; 1192 1193 /* afa_trap_forward_action 1194 * Forward Action. 1195 */ 1196 MLXSW_ITEM32(afa, trap, forward_action, 0x00, 0, 4); 1197 1198 /* afa_trap_trap_id 1199 * Trap ID to configure. 1200 */ 1201 MLXSW_ITEM32(afa, trap, trap_id, 0x04, 0, 9); 1202 1203 /* afa_trap_mirror_agent 1204 * Mirror agent. 1205 */ 1206 MLXSW_ITEM32(afa, trap, mirror_agent, 0x08, 29, 3); 1207 1208 /* afa_trap_mirror_enable 1209 * Mirror enable. 1210 */ 1211 MLXSW_ITEM32(afa, trap, mirror_enable, 0x08, 24, 1); 1212 1213 /* user_def_val 1214 * Value for the SW usage. Can be used to pass information of which 1215 * rule has caused a trap. This may be overwritten by later traps. 1216 * This field does a set on the packet's user_def_val only if this 1217 * is the first trap_id or if the trap_id has replaced the previous 1218 * packet's trap_id. 1219 */ 1220 MLXSW_ITEM32(afa, trap, user_def_val, 0x0C, 0, 20); 1221 1222 static inline void 1223 mlxsw_afa_trap_pack(char *payload, 1224 enum mlxsw_afa_trap_trap_action trap_action, 1225 enum mlxsw_afa_trap_forward_action forward_action, 1226 u16 trap_id) 1227 { 1228 mlxsw_afa_trap_trap_action_set(payload, trap_action); 1229 mlxsw_afa_trap_forward_action_set(payload, forward_action); 1230 mlxsw_afa_trap_trap_id_set(payload, trap_id); 1231 } 1232 1233 static inline void 1234 mlxsw_afa_trapwu_pack(char *payload, 1235 enum mlxsw_afa_trap_trap_action trap_action, 1236 enum mlxsw_afa_trap_forward_action forward_action, 1237 u16 trap_id, u32 user_def_val) 1238 { 1239 mlxsw_afa_trap_pack(payload, trap_action, forward_action, trap_id); 1240 mlxsw_afa_trap_user_def_val_set(payload, user_def_val); 1241 } 1242 1243 static inline void 1244 mlxsw_afa_trap_mirror_pack(char *payload, bool mirror_enable, 1245 u8 mirror_agent) 1246 { 1247 mlxsw_afa_trap_mirror_enable_set(payload, mirror_enable); 1248 mlxsw_afa_trap_mirror_agent_set(payload, mirror_agent); 1249 } 1250 1251 static char *mlxsw_afa_block_append_action_trap(struct mlxsw_afa_block *block, 1252 u8 action_code, u8 action_size) 1253 { 1254 return mlxsw_afa_block_append_action_ext(block, action_code, 1255 action_size, 1256 MLXSW_AFA_ACTION_TYPE_TRAP); 1257 } 1258 1259 static int mlxsw_afa_block_append_drop_plain(struct mlxsw_afa_block *block, 1260 bool ingress) 1261 { 1262 char *act = mlxsw_afa_block_append_action_trap(block, 1263 MLXSW_AFA_TRAP_CODE, 1264 MLXSW_AFA_TRAP_SIZE); 1265 1266 if (IS_ERR(act)) 1267 return PTR_ERR(act); 1268 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1269 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, 1270 ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL : 1271 MLXSW_TRAP_ID_DISCARD_EGRESS_ACL); 1272 return 0; 1273 } 1274 1275 static int 1276 mlxsw_afa_block_append_drop_with_cookie(struct mlxsw_afa_block *block, 1277 bool ingress, 1278 const struct flow_action_cookie *fa_cookie, 1279 struct netlink_ext_ack *extack) 1280 { 1281 struct mlxsw_afa_cookie_ref *cookie_ref; 1282 u32 cookie_index; 1283 char *act; 1284 int err; 1285 1286 cookie_ref = mlxsw_afa_cookie_ref_create(block, fa_cookie); 1287 if (IS_ERR(cookie_ref)) { 1288 NL_SET_ERR_MSG_MOD(extack, "Cannot create cookie for drop action"); 1289 return PTR_ERR(cookie_ref); 1290 } 1291 cookie_index = cookie_ref->cookie->cookie_index; 1292 1293 act = mlxsw_afa_block_append_action_trap(block, MLXSW_AFA_TRAPWU_CODE, 1294 MLXSW_AFA_TRAPWU_SIZE); 1295 if (IS_ERR(act)) { 1296 NL_SET_ERR_MSG_MOD(extack, "Cannot append drop with cookie action"); 1297 err = PTR_ERR(act); 1298 goto err_append_action; 1299 } 1300 mlxsw_afa_trapwu_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1301 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, 1302 ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL : 1303 MLXSW_TRAP_ID_DISCARD_EGRESS_ACL, 1304 cookie_index); 1305 return 0; 1306 1307 err_append_action: 1308 mlxsw_afa_cookie_ref_destroy(block, cookie_ref); 1309 return err; 1310 } 1311 1312 int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block, bool ingress, 1313 const struct flow_action_cookie *fa_cookie, 1314 struct netlink_ext_ack *extack) 1315 { 1316 return fa_cookie ? 1317 mlxsw_afa_block_append_drop_with_cookie(block, ingress, 1318 fa_cookie, extack) : 1319 mlxsw_afa_block_append_drop_plain(block, ingress); 1320 } 1321 EXPORT_SYMBOL(mlxsw_afa_block_append_drop); 1322 1323 int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id) 1324 { 1325 char *act = mlxsw_afa_block_append_action_trap(block, 1326 MLXSW_AFA_TRAP_CODE, 1327 MLXSW_AFA_TRAP_SIZE); 1328 1329 if (IS_ERR(act)) 1330 return PTR_ERR(act); 1331 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1332 MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, trap_id); 1333 return 0; 1334 } 1335 EXPORT_SYMBOL(mlxsw_afa_block_append_trap); 1336 1337 int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, 1338 u16 trap_id) 1339 { 1340 char *act = mlxsw_afa_block_append_action_trap(block, 1341 MLXSW_AFA_TRAP_CODE, 1342 MLXSW_AFA_TRAP_SIZE); 1343 1344 if (IS_ERR(act)) 1345 return PTR_ERR(act); 1346 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, 1347 MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, trap_id); 1348 return 0; 1349 } 1350 EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward); 1351 1352 struct mlxsw_afa_mirror { 1353 struct mlxsw_afa_resource resource; 1354 int span_id; 1355 u8 local_in_port; 1356 bool ingress; 1357 }; 1358 1359 static void 1360 mlxsw_afa_mirror_destroy(struct mlxsw_afa_block *block, 1361 struct mlxsw_afa_mirror *mirror) 1362 { 1363 mlxsw_afa_resource_del(&mirror->resource); 1364 block->afa->ops->mirror_del(block->afa->ops_priv, 1365 mirror->local_in_port, 1366 mirror->span_id, 1367 mirror->ingress); 1368 kfree(mirror); 1369 } 1370 1371 static void 1372 mlxsw_afa_mirror_destructor(struct mlxsw_afa_block *block, 1373 struct mlxsw_afa_resource *resource) 1374 { 1375 struct mlxsw_afa_mirror *mirror; 1376 1377 mirror = container_of(resource, struct mlxsw_afa_mirror, resource); 1378 mlxsw_afa_mirror_destroy(block, mirror); 1379 } 1380 1381 static struct mlxsw_afa_mirror * 1382 mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, u8 local_in_port, 1383 const struct net_device *out_dev, bool ingress) 1384 { 1385 struct mlxsw_afa_mirror *mirror; 1386 int err; 1387 1388 mirror = kzalloc(sizeof(*mirror), GFP_KERNEL); 1389 if (!mirror) 1390 return ERR_PTR(-ENOMEM); 1391 1392 err = block->afa->ops->mirror_add(block->afa->ops_priv, 1393 local_in_port, out_dev, 1394 ingress, &mirror->span_id); 1395 if (err) 1396 goto err_mirror_add; 1397 1398 mirror->ingress = ingress; 1399 mirror->local_in_port = local_in_port; 1400 mirror->resource.destructor = mlxsw_afa_mirror_destructor; 1401 mlxsw_afa_resource_add(block, &mirror->resource); 1402 return mirror; 1403 1404 err_mirror_add: 1405 kfree(mirror); 1406 return ERR_PTR(err); 1407 } 1408 1409 static int 1410 mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block, 1411 u8 mirror_agent) 1412 { 1413 char *act = mlxsw_afa_block_append_action_trap(block, 1414 MLXSW_AFA_TRAP_CODE, 1415 MLXSW_AFA_TRAP_SIZE); 1416 1417 if (IS_ERR(act)) 1418 return PTR_ERR(act); 1419 mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_NOP, 1420 MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, 0); 1421 mlxsw_afa_trap_mirror_pack(act, true, mirror_agent); 1422 return 0; 1423 } 1424 1425 int 1426 mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u8 local_in_port, 1427 const struct net_device *out_dev, bool ingress, 1428 struct netlink_ext_ack *extack) 1429 { 1430 struct mlxsw_afa_mirror *mirror; 1431 int err; 1432 1433 mirror = mlxsw_afa_mirror_create(block, local_in_port, out_dev, 1434 ingress); 1435 if (IS_ERR(mirror)) { 1436 NL_SET_ERR_MSG_MOD(extack, "Cannot create mirror action"); 1437 return PTR_ERR(mirror); 1438 } 1439 err = mlxsw_afa_block_append_allocated_mirror(block, mirror->span_id); 1440 if (err) { 1441 NL_SET_ERR_MSG_MOD(extack, "Cannot append mirror action"); 1442 goto err_append_allocated_mirror; 1443 } 1444 1445 return 0; 1446 1447 err_append_allocated_mirror: 1448 mlxsw_afa_mirror_destroy(block, mirror); 1449 return err; 1450 } 1451 EXPORT_SYMBOL(mlxsw_afa_block_append_mirror); 1452 1453 /* QoS Action 1454 * ---------- 1455 * The QOS_ACTION is used for manipulating the QoS attributes of a packet. It 1456 * can be used to change the DCSP, ECN, Color and Switch Priority of the packet. 1457 * Note that PCP field can be changed using the VLAN action. 1458 */ 1459 1460 #define MLXSW_AFA_QOS_CODE 0x06 1461 #define MLXSW_AFA_QOS_SIZE 1 1462 1463 enum mlxsw_afa_qos_ecn_cmd { 1464 /* Do nothing */ 1465 MLXSW_AFA_QOS_ECN_CMD_NOP, 1466 /* Set ECN to afa_qos_ecn */ 1467 MLXSW_AFA_QOS_ECN_CMD_SET, 1468 }; 1469 1470 /* afa_qos_ecn_cmd 1471 */ 1472 MLXSW_ITEM32(afa, qos, ecn_cmd, 0x04, 29, 3); 1473 1474 /* afa_qos_ecn 1475 * ECN value. 1476 */ 1477 MLXSW_ITEM32(afa, qos, ecn, 0x04, 24, 2); 1478 1479 enum mlxsw_afa_qos_dscp_cmd { 1480 /* Do nothing */ 1481 MLXSW_AFA_QOS_DSCP_CMD_NOP, 1482 /* Set DSCP 3 LSB bits according to dscp[2:0] */ 1483 MLXSW_AFA_QOS_DSCP_CMD_SET_3LSB, 1484 /* Set DSCP 3 MSB bits according to dscp[5:3] */ 1485 MLXSW_AFA_QOS_DSCP_CMD_SET_3MSB, 1486 /* Set DSCP 6 bits according to dscp[5:0] */ 1487 MLXSW_AFA_QOS_DSCP_CMD_SET_ALL, 1488 }; 1489 1490 /* afa_qos_dscp_cmd 1491 * DSCP command. 1492 */ 1493 MLXSW_ITEM32(afa, qos, dscp_cmd, 0x04, 14, 2); 1494 1495 /* afa_qos_dscp 1496 * DSCP value. 1497 */ 1498 MLXSW_ITEM32(afa, qos, dscp, 0x04, 0, 6); 1499 1500 enum mlxsw_afa_qos_switch_prio_cmd { 1501 /* Do nothing */ 1502 MLXSW_AFA_QOS_SWITCH_PRIO_CMD_NOP, 1503 /* Set Switch Priority to afa_qos_switch_prio */ 1504 MLXSW_AFA_QOS_SWITCH_PRIO_CMD_SET, 1505 }; 1506 1507 /* afa_qos_switch_prio_cmd 1508 */ 1509 MLXSW_ITEM32(afa, qos, switch_prio_cmd, 0x08, 14, 2); 1510 1511 /* afa_qos_switch_prio 1512 * Switch Priority. 1513 */ 1514 MLXSW_ITEM32(afa, qos, switch_prio, 0x08, 0, 4); 1515 1516 enum mlxsw_afa_qos_dscp_rw { 1517 MLXSW_AFA_QOS_DSCP_RW_PRESERVE, 1518 MLXSW_AFA_QOS_DSCP_RW_SET, 1519 MLXSW_AFA_QOS_DSCP_RW_CLEAR, 1520 }; 1521 1522 /* afa_qos_dscp_rw 1523 * DSCP Re-write Enable. Controlling the rewrite_enable for DSCP. 1524 */ 1525 MLXSW_ITEM32(afa, qos, dscp_rw, 0x0C, 30, 2); 1526 1527 static inline void 1528 mlxsw_afa_qos_ecn_pack(char *payload, 1529 enum mlxsw_afa_qos_ecn_cmd ecn_cmd, u8 ecn) 1530 { 1531 mlxsw_afa_qos_ecn_cmd_set(payload, ecn_cmd); 1532 mlxsw_afa_qos_ecn_set(payload, ecn); 1533 } 1534 1535 static inline void 1536 mlxsw_afa_qos_dscp_pack(char *payload, 1537 enum mlxsw_afa_qos_dscp_cmd dscp_cmd, u8 dscp) 1538 { 1539 mlxsw_afa_qos_dscp_cmd_set(payload, dscp_cmd); 1540 mlxsw_afa_qos_dscp_set(payload, dscp); 1541 } 1542 1543 static inline void 1544 mlxsw_afa_qos_switch_prio_pack(char *payload, 1545 enum mlxsw_afa_qos_switch_prio_cmd prio_cmd, 1546 u8 prio) 1547 { 1548 mlxsw_afa_qos_switch_prio_cmd_set(payload, prio_cmd); 1549 mlxsw_afa_qos_switch_prio_set(payload, prio); 1550 } 1551 1552 static int __mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block, 1553 bool set_dscp, u8 dscp, 1554 bool set_ecn, u8 ecn, 1555 struct netlink_ext_ack *extack) 1556 { 1557 char *act = mlxsw_afa_block_append_action(block, 1558 MLXSW_AFA_QOS_CODE, 1559 MLXSW_AFA_QOS_SIZE); 1560 1561 if (IS_ERR(act)) { 1562 NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action"); 1563 return PTR_ERR(act); 1564 } 1565 1566 if (set_ecn) 1567 mlxsw_afa_qos_ecn_pack(act, MLXSW_AFA_QOS_ECN_CMD_SET, ecn); 1568 if (set_dscp) { 1569 mlxsw_afa_qos_dscp_pack(act, MLXSW_AFA_QOS_DSCP_CMD_SET_ALL, 1570 dscp); 1571 mlxsw_afa_qos_dscp_rw_set(act, MLXSW_AFA_QOS_DSCP_RW_CLEAR); 1572 } 1573 1574 return 0; 1575 } 1576 1577 int mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block, 1578 u8 dsfield, 1579 struct netlink_ext_ack *extack) 1580 { 1581 return __mlxsw_afa_block_append_qos_dsfield(block, 1582 true, dsfield >> 2, 1583 true, dsfield & 0x03, 1584 extack); 1585 } 1586 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dsfield); 1587 1588 int mlxsw_afa_block_append_qos_dscp(struct mlxsw_afa_block *block, 1589 u8 dscp, struct netlink_ext_ack *extack) 1590 { 1591 return __mlxsw_afa_block_append_qos_dsfield(block, 1592 true, dscp, 1593 false, 0, 1594 extack); 1595 } 1596 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dscp); 1597 1598 int mlxsw_afa_block_append_qos_ecn(struct mlxsw_afa_block *block, 1599 u8 ecn, struct netlink_ext_ack *extack) 1600 { 1601 return __mlxsw_afa_block_append_qos_dsfield(block, 1602 false, 0, 1603 true, ecn, 1604 extack); 1605 } 1606 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_ecn); 1607 1608 int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block, 1609 u8 prio, 1610 struct netlink_ext_ack *extack) 1611 { 1612 char *act = mlxsw_afa_block_append_action(block, 1613 MLXSW_AFA_QOS_CODE, 1614 MLXSW_AFA_QOS_SIZE); 1615 1616 if (IS_ERR(act)) { 1617 NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action"); 1618 return PTR_ERR(act); 1619 } 1620 mlxsw_afa_qos_switch_prio_pack(act, MLXSW_AFA_QOS_SWITCH_PRIO_CMD_SET, 1621 prio); 1622 return 0; 1623 } 1624 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_switch_prio); 1625 1626 /* Forwarding Action 1627 * ----------------- 1628 * Forwarding Action can be used to implement Policy Based Switching (PBS) 1629 * as well as OpenFlow related "Output" action. 1630 */ 1631 1632 #define MLXSW_AFA_FORWARD_CODE 0x07 1633 #define MLXSW_AFA_FORWARD_SIZE 1 1634 1635 enum mlxsw_afa_forward_type { 1636 /* PBS, Policy Based Switching */ 1637 MLXSW_AFA_FORWARD_TYPE_PBS, 1638 /* Output, OpenFlow output type */ 1639 MLXSW_AFA_FORWARD_TYPE_OUTPUT, 1640 }; 1641 1642 /* afa_forward_type */ 1643 MLXSW_ITEM32(afa, forward, type, 0x00, 24, 2); 1644 1645 /* afa_forward_pbs_ptr 1646 * A pointer to the PBS entry configured by PPBS register. 1647 * Reserved when in_port is set. 1648 */ 1649 MLXSW_ITEM32(afa, forward, pbs_ptr, 0x08, 0, 24); 1650 1651 /* afa_forward_in_port 1652 * Packet is forwarded back to the ingress port. 1653 */ 1654 MLXSW_ITEM32(afa, forward, in_port, 0x0C, 0, 1); 1655 1656 static inline void 1657 mlxsw_afa_forward_pack(char *payload, enum mlxsw_afa_forward_type type, 1658 u32 pbs_ptr, bool in_port) 1659 { 1660 mlxsw_afa_forward_type_set(payload, type); 1661 mlxsw_afa_forward_pbs_ptr_set(payload, pbs_ptr); 1662 mlxsw_afa_forward_in_port_set(payload, in_port); 1663 } 1664 1665 int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, 1666 u8 local_port, bool in_port, 1667 struct netlink_ext_ack *extack) 1668 { 1669 struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref; 1670 u32 kvdl_index; 1671 char *act; 1672 int err; 1673 1674 if (in_port) { 1675 NL_SET_ERR_MSG_MOD(extack, "Forwarding to ingress port is not supported"); 1676 return -EOPNOTSUPP; 1677 } 1678 fwd_entry_ref = mlxsw_afa_fwd_entry_ref_create(block, local_port); 1679 if (IS_ERR(fwd_entry_ref)) { 1680 NL_SET_ERR_MSG_MOD(extack, "Cannot create forward action"); 1681 return PTR_ERR(fwd_entry_ref); 1682 } 1683 kvdl_index = fwd_entry_ref->fwd_entry->kvdl_index; 1684 1685 act = mlxsw_afa_block_append_action(block, MLXSW_AFA_FORWARD_CODE, 1686 MLXSW_AFA_FORWARD_SIZE); 1687 if (IS_ERR(act)) { 1688 NL_SET_ERR_MSG_MOD(extack, "Cannot append forward action"); 1689 err = PTR_ERR(act); 1690 goto err_append_action; 1691 } 1692 mlxsw_afa_forward_pack(act, MLXSW_AFA_FORWARD_TYPE_PBS, 1693 kvdl_index, in_port); 1694 return 0; 1695 1696 err_append_action: 1697 mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref); 1698 return err; 1699 } 1700 EXPORT_SYMBOL(mlxsw_afa_block_append_fwd); 1701 1702 /* Policing and Counting Action 1703 * ---------------------------- 1704 * Policing and Counting action is used for binding policer and counter 1705 * to ACL rules. 1706 */ 1707 1708 #define MLXSW_AFA_POLCNT_CODE 0x08 1709 #define MLXSW_AFA_POLCNT_SIZE 1 1710 1711 enum { 1712 MLXSW_AFA_POLCNT_COUNTER, 1713 MLXSW_AFA_POLCNT_POLICER, 1714 }; 1715 1716 /* afa_polcnt_c_p 1717 * Counter or policer. 1718 * Indicates whether the action binds a policer or a counter to the flow. 1719 * 0: Counter 1720 * 1: Policer 1721 */ 1722 MLXSW_ITEM32(afa, polcnt, c_p, 0x00, 31, 1); 1723 1724 enum mlxsw_afa_polcnt_counter_set_type { 1725 /* No count */ 1726 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT = 0x00, 1727 /* Count packets and bytes */ 1728 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03, 1729 /* Count only packets */ 1730 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS = 0x05, 1731 }; 1732 1733 /* afa_polcnt_counter_set_type 1734 * Counter set type for flow counters. 1735 */ 1736 MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8); 1737 1738 /* afa_polcnt_counter_index 1739 * Counter index for flow counters. 1740 */ 1741 MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24); 1742 1743 /* afa_polcnt_pid 1744 * Policer ID. 1745 * Reserved when c_p = 0 1746 */ 1747 MLXSW_ITEM32(afa, polcnt, pid, 0x08, 0, 14); 1748 1749 static inline void 1750 mlxsw_afa_polcnt_pack(char *payload, 1751 enum mlxsw_afa_polcnt_counter_set_type set_type, 1752 u32 counter_index) 1753 { 1754 mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_COUNTER); 1755 mlxsw_afa_polcnt_counter_set_type_set(payload, set_type); 1756 mlxsw_afa_polcnt_counter_index_set(payload, counter_index); 1757 } 1758 1759 static void mlxsw_afa_polcnt_policer_pack(char *payload, u16 policer_index) 1760 { 1761 mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_POLICER); 1762 mlxsw_afa_polcnt_pid_set(payload, policer_index); 1763 } 1764 1765 int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block, 1766 u32 counter_index) 1767 { 1768 char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_POLCNT_CODE, 1769 MLXSW_AFA_POLCNT_SIZE); 1770 if (IS_ERR(act)) 1771 return PTR_ERR(act); 1772 mlxsw_afa_polcnt_pack(act, MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES, 1773 counter_index); 1774 return 0; 1775 } 1776 EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter); 1777 1778 int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, 1779 u32 *p_counter_index, 1780 struct netlink_ext_ack *extack) 1781 { 1782 struct mlxsw_afa_counter *counter; 1783 u32 counter_index; 1784 int err; 1785 1786 counter = mlxsw_afa_counter_create(block); 1787 if (IS_ERR(counter)) { 1788 NL_SET_ERR_MSG_MOD(extack, "Cannot create count action"); 1789 return PTR_ERR(counter); 1790 } 1791 counter_index = counter->counter_index; 1792 1793 err = mlxsw_afa_block_append_allocated_counter(block, counter_index); 1794 if (err) { 1795 NL_SET_ERR_MSG_MOD(extack, "Cannot append count action"); 1796 goto err_append_allocated_counter; 1797 } 1798 if (p_counter_index) 1799 *p_counter_index = counter_index; 1800 return 0; 1801 1802 err_append_allocated_counter: 1803 mlxsw_afa_counter_destroy(block, counter); 1804 return err; 1805 } 1806 EXPORT_SYMBOL(mlxsw_afa_block_append_counter); 1807 1808 int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block, 1809 u32 fa_index, u64 rate_bytes_ps, u32 burst, 1810 u16 *p_policer_index, 1811 struct netlink_ext_ack *extack) 1812 { 1813 struct mlxsw_afa_policer_ref *policer_ref; 1814 char *act; 1815 int err; 1816 1817 policer_ref = mlxsw_afa_policer_ref_create(block, fa_index, 1818 rate_bytes_ps, 1819 burst, extack); 1820 if (IS_ERR(policer_ref)) 1821 return PTR_ERR(policer_ref); 1822 *p_policer_index = policer_ref->policer->policer_index; 1823 1824 act = mlxsw_afa_block_append_action_ext(block, MLXSW_AFA_POLCNT_CODE, 1825 MLXSW_AFA_POLCNT_SIZE, 1826 MLXSW_AFA_ACTION_TYPE_POLICE); 1827 if (IS_ERR(act)) { 1828 NL_SET_ERR_MSG_MOD(extack, "Cannot append police action"); 1829 err = PTR_ERR(act); 1830 goto err_append_action; 1831 } 1832 mlxsw_afa_polcnt_policer_pack(act, *p_policer_index); 1833 1834 return 0; 1835 1836 err_append_action: 1837 mlxsw_afa_policer_ref_destroy(block, policer_ref); 1838 return err; 1839 } 1840 EXPORT_SYMBOL(mlxsw_afa_block_append_police); 1841 1842 /* Virtual Router and Forwarding Domain Action 1843 * ------------------------------------------- 1844 * Virtual Switch action is used for manipulate the Virtual Router (VR), 1845 * MPLS label space and the Forwarding Identifier (FID). 1846 */ 1847 1848 #define MLXSW_AFA_VIRFWD_CODE 0x0E 1849 #define MLXSW_AFA_VIRFWD_SIZE 1 1850 1851 enum mlxsw_afa_virfwd_fid_cmd { 1852 /* Do nothing */ 1853 MLXSW_AFA_VIRFWD_FID_CMD_NOOP, 1854 /* Set the Forwarding Identifier (FID) to fid */ 1855 MLXSW_AFA_VIRFWD_FID_CMD_SET, 1856 }; 1857 1858 /* afa_virfwd_fid_cmd */ 1859 MLXSW_ITEM32(afa, virfwd, fid_cmd, 0x08, 29, 3); 1860 1861 /* afa_virfwd_fid 1862 * The FID value. 1863 */ 1864 MLXSW_ITEM32(afa, virfwd, fid, 0x08, 0, 16); 1865 1866 static inline void mlxsw_afa_virfwd_pack(char *payload, 1867 enum mlxsw_afa_virfwd_fid_cmd fid_cmd, 1868 u16 fid) 1869 { 1870 mlxsw_afa_virfwd_fid_cmd_set(payload, fid_cmd); 1871 mlxsw_afa_virfwd_fid_set(payload, fid); 1872 } 1873 1874 int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid, 1875 struct netlink_ext_ack *extack) 1876 { 1877 char *act = mlxsw_afa_block_append_action(block, 1878 MLXSW_AFA_VIRFWD_CODE, 1879 MLXSW_AFA_VIRFWD_SIZE); 1880 if (IS_ERR(act)) { 1881 NL_SET_ERR_MSG_MOD(extack, "Cannot append fid_set action"); 1882 return PTR_ERR(act); 1883 } 1884 mlxsw_afa_virfwd_pack(act, MLXSW_AFA_VIRFWD_FID_CMD_SET, fid); 1885 return 0; 1886 } 1887 EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set); 1888 1889 /* MC Routing Action 1890 * ----------------- 1891 * The Multicast router action. Can be used by RMFT_V2 - Router Multicast 1892 * Forwarding Table Version 2 Register. 1893 */ 1894 1895 #define MLXSW_AFA_MCROUTER_CODE 0x10 1896 #define MLXSW_AFA_MCROUTER_SIZE 2 1897 1898 enum mlxsw_afa_mcrouter_rpf_action { 1899 MLXSW_AFA_MCROUTER_RPF_ACTION_NOP, 1900 MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP, 1901 MLXSW_AFA_MCROUTER_RPF_ACTION_DISCARD_ERROR, 1902 }; 1903 1904 /* afa_mcrouter_rpf_action */ 1905 MLXSW_ITEM32(afa, mcrouter, rpf_action, 0x00, 28, 3); 1906 1907 /* afa_mcrouter_expected_irif */ 1908 MLXSW_ITEM32(afa, mcrouter, expected_irif, 0x00, 0, 16); 1909 1910 /* afa_mcrouter_min_mtu */ 1911 MLXSW_ITEM32(afa, mcrouter, min_mtu, 0x08, 0, 16); 1912 1913 enum mlxsw_afa_mrouter_vrmid { 1914 MLXSW_AFA_MCROUTER_VRMID_INVALID, 1915 MLXSW_AFA_MCROUTER_VRMID_VALID 1916 }; 1917 1918 /* afa_mcrouter_vrmid 1919 * Valid RMID: rigr_rmid_index is used as RMID 1920 */ 1921 MLXSW_ITEM32(afa, mcrouter, vrmid, 0x0C, 31, 1); 1922 1923 /* afa_mcrouter_rigr_rmid_index 1924 * When the vrmid field is set to invalid, the field is used as pointer to 1925 * Router Interface Group (RIGR) Table in the KVD linear. 1926 * When the vrmid is set to valid, the field is used as RMID index, ranged 1927 * from 0 to max_mid - 1. The index is to the Port Group Table. 1928 */ 1929 MLXSW_ITEM32(afa, mcrouter, rigr_rmid_index, 0x0C, 0, 24); 1930 1931 static inline void 1932 mlxsw_afa_mcrouter_pack(char *payload, 1933 enum mlxsw_afa_mcrouter_rpf_action rpf_action, 1934 u16 expected_irif, u16 min_mtu, 1935 enum mlxsw_afa_mrouter_vrmid vrmid, u32 rigr_rmid_index) 1936 1937 { 1938 mlxsw_afa_mcrouter_rpf_action_set(payload, rpf_action); 1939 mlxsw_afa_mcrouter_expected_irif_set(payload, expected_irif); 1940 mlxsw_afa_mcrouter_min_mtu_set(payload, min_mtu); 1941 mlxsw_afa_mcrouter_vrmid_set(payload, vrmid); 1942 mlxsw_afa_mcrouter_rigr_rmid_index_set(payload, rigr_rmid_index); 1943 } 1944 1945 int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block, 1946 u16 expected_irif, u16 min_mtu, 1947 bool rmid_valid, u32 kvdl_index) 1948 { 1949 char *act = mlxsw_afa_block_append_action(block, 1950 MLXSW_AFA_MCROUTER_CODE, 1951 MLXSW_AFA_MCROUTER_SIZE); 1952 if (IS_ERR(act)) 1953 return PTR_ERR(act); 1954 mlxsw_afa_mcrouter_pack(act, MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP, 1955 expected_irif, min_mtu, rmid_valid, kvdl_index); 1956 return 0; 1957 } 1958 EXPORT_SYMBOL(mlxsw_afa_block_append_mcrouter); 1959 1960 /* L4 Port Action 1961 * -------------- 1962 * The L4_PORT_ACTION is used for modifying the sport and dport fields of the packet, e.g. for NAT. 1963 * If (the L4 is TCP) or if (the L4 is UDP and checksum field!=0) then the L4 checksum is updated. 1964 */ 1965 1966 #define MLXSW_AFA_L4PORT_CODE 0x12 1967 #define MLXSW_AFA_L4PORT_SIZE 1 1968 1969 enum mlxsw_afa_l4port_s_d { 1970 /* configure src_l4_port */ 1971 MLXSW_AFA_L4PORT_S_D_SRC, 1972 /* configure dst_l4_port */ 1973 MLXSW_AFA_L4PORT_S_D_DST, 1974 }; 1975 1976 /* afa_l4port_s_d 1977 * Source or destination. 1978 */ 1979 MLXSW_ITEM32(afa, l4port, s_d, 0x00, 31, 1); 1980 1981 /* afa_l4port_l4_port 1982 * Number of port to change to. 1983 */ 1984 MLXSW_ITEM32(afa, l4port, l4_port, 0x08, 0, 16); 1985 1986 static void mlxsw_afa_l4port_pack(char *payload, enum mlxsw_afa_l4port_s_d s_d, u16 l4_port) 1987 { 1988 mlxsw_afa_l4port_s_d_set(payload, s_d); 1989 mlxsw_afa_l4port_l4_port_set(payload, l4_port); 1990 } 1991 1992 int mlxsw_afa_block_append_l4port(struct mlxsw_afa_block *block, bool is_dport, u16 l4_port, 1993 struct netlink_ext_ack *extack) 1994 { 1995 enum mlxsw_afa_l4port_s_d s_d = is_dport ? MLXSW_AFA_L4PORT_S_D_DST : 1996 MLXSW_AFA_L4PORT_S_D_SRC; 1997 char *act = mlxsw_afa_block_append_action(block, 1998 MLXSW_AFA_L4PORT_CODE, 1999 MLXSW_AFA_L4PORT_SIZE); 2000 2001 if (IS_ERR(act)) { 2002 NL_SET_ERR_MSG_MOD(extack, "Cannot append L4_PORT action"); 2003 return PTR_ERR(act); 2004 } 2005 2006 mlxsw_afa_l4port_pack(act, s_d, l4_port); 2007 return 0; 2008 } 2009 EXPORT_SYMBOL(mlxsw_afa_block_append_l4port); 2010