linux/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
<<
>>
Prefs
   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        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
 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        u8 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        unsigned int 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        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 (--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                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, 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
 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, 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
 616static 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
 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, 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
 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        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
 760err_idr_alloc:
 761        rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node,
 762                               mlxsw_afa_cookie_ht_params);
 763err_rhashtable_insert:
 764        kfree(cookie);
 765        return ERR_PTR(err);
 766}
 767
 768static 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
 777static struct mlxsw_afa_cookie *
 778mlxsw_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
 792static 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 */
 801const struct flow_action_cookie *
 802mlxsw_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}
 814EXPORT_SYMBOL(mlxsw_afa_cookie_lookup);
 815
 816struct mlxsw_afa_cookie_ref {
 817        struct mlxsw_afa_resource resource;
 818        struct mlxsw_afa_cookie *cookie;
 819};
 820
 821static void
 822mlxsw_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
 830static void
 831mlxsw_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
 841static struct mlxsw_afa_cookie_ref *
 842mlxsw_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
 862err_cookie_get:
 863        kfree(cookie_ref);
 864        return ERR_PTR(err);
 865}
 866
 867static struct mlxsw_afa_policer *
 868mlxsw_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
 897err_rhashtable_insert:
 898        mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv,
 899                                    policer->policer_index);
 900err_policer_add:
 901        kfree(policer);
 902        return ERR_PTR(err);
 903}
 904
 905static 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
 916static struct mlxsw_afa_policer *
 917mlxsw_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
 934static 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
 942struct mlxsw_afa_policer_ref {
 943        struct mlxsw_afa_resource resource;
 944        struct mlxsw_afa_policer *policer;
 945};
 946
 947static void
 948mlxsw_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
 956static void
 957mlxsw_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
 967static struct mlxsw_afa_policer_ref *
 968mlxsw_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
 993err_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
1001enum mlxsw_afa_action_type {
1002        MLXSW_AFA_ACTION_TYPE_TRAP,
1003        MLXSW_AFA_ACTION_TYPE_POLICE,
1004        MLXSW_AFA_ACTION_TYPE_OTHER,
1005};
1006
1007static bool
1008mlxsw_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
1022static 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
1065static 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
1083enum 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
1089enum 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 */
1101MLXSW_ITEM32(afa, vlan, vlan_tag_cmd, 0x00, 29, 3);
1102
1103/* afa_vlan_vid_cmd */
1104MLXSW_ITEM32(afa, vlan, vid_cmd, 0x04, 29, 3);
1105
1106/* afa_vlan_vid */
1107MLXSW_ITEM32(afa, vlan, vid, 0x04, 0, 12);
1108
1109/* afa_vlan_ethertype_cmd */
1110MLXSW_ITEM32(afa, vlan, ethertype_cmd, 0x08, 29, 3);
1111
1112/* afa_vlan_ethertype
1113 * Index to EtherTypes in Switch VLAN EtherType Register (SVER).
1114 */
1115MLXSW_ITEM32(afa, vlan, ethertype, 0x08, 24, 3);
1116
1117/* afa_vlan_pcp_cmd */
1118MLXSW_ITEM32(afa, vlan, pcp_cmd, 0x08, 13, 3);
1119
1120/* afa_vlan_pcp */
1121MLXSW_ITEM32(afa, vlan, pcp, 0x08, 8, 3);
1122
1123static inline void
1124mlxsw_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
1139int 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}
1157EXPORT_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
1178enum 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 */
1186MLXSW_ITEM32(afa, trap, trap_action, 0x00, 24, 4);
1187
1188enum 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 */
1196MLXSW_ITEM32(afa, trap, forward_action, 0x00, 0, 4);
1197
1198/* afa_trap_trap_id
1199 * Trap ID to configure.
1200 */
1201MLXSW_ITEM32(afa, trap, trap_id, 0x04, 0, 9);
1202
1203/* afa_trap_mirror_agent
1204 * Mirror agent.
1205 */
1206MLXSW_ITEM32(afa, trap, mirror_agent, 0x08, 29, 3);
1207
1208/* afa_trap_mirror_enable
1209 * Mirror enable.
1210 */
1211MLXSW_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 */
1220MLXSW_ITEM32(afa, trap, user_def_val, 0x0C, 0, 20);
1221
1222static inline void
1223mlxsw_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
1233static inline void
1234mlxsw_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
1243static inline void
1244mlxsw_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
1251static 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
1259static 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
1275static int
1276mlxsw_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
1307err_append_action:
1308        mlxsw_afa_cookie_ref_destroy(block, cookie_ref);
1309        return err;
1310}
1311
1312int 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}
1321EXPORT_SYMBOL(mlxsw_afa_block_append_drop);
1322
1323int 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}
1335EXPORT_SYMBOL(mlxsw_afa_block_append_trap);
1336
1337int 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}
1350EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward);
1351
1352struct mlxsw_afa_mirror {
1353        struct mlxsw_afa_resource resource;
1354        int span_id;
1355        u8 local_in_port;
1356        bool ingress;
1357};
1358
1359static void
1360mlxsw_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
1371static void
1372mlxsw_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
1381static struct mlxsw_afa_mirror *
1382mlxsw_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
1404err_mirror_add:
1405        kfree(mirror);
1406        return ERR_PTR(err);
1407}
1408
1409static int
1410mlxsw_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
1425int
1426mlxsw_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
1447err_append_allocated_mirror:
1448        mlxsw_afa_mirror_destroy(block, mirror);
1449        return err;
1450}
1451EXPORT_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
1463enum 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 */
1472MLXSW_ITEM32(afa, qos, ecn_cmd, 0x04, 29, 3);
1473
1474/* afa_qos_ecn
1475 * ECN value.
1476 */
1477MLXSW_ITEM32(afa, qos, ecn, 0x04, 24, 2);
1478
1479enum 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 */
1493MLXSW_ITEM32(afa, qos, dscp_cmd, 0x04, 14, 2);
1494
1495/* afa_qos_dscp
1496 * DSCP value.
1497 */
1498MLXSW_ITEM32(afa, qos, dscp, 0x04, 0, 6);
1499
1500enum 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 */
1509MLXSW_ITEM32(afa, qos, switch_prio_cmd, 0x08, 14, 2);
1510
1511/* afa_qos_switch_prio
1512 * Switch Priority.
1513 */
1514MLXSW_ITEM32(afa, qos, switch_prio, 0x08, 0, 4);
1515
1516enum 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 */
1525MLXSW_ITEM32(afa, qos, dscp_rw, 0x0C, 30, 2);
1526
1527static inline void
1528mlxsw_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
1535static inline void
1536mlxsw_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
1543static inline void
1544mlxsw_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
1552static 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
1577int 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}
1586EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dsfield);
1587
1588int 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}
1596EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dscp);
1597
1598int 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}
1606EXPORT_SYMBOL(mlxsw_afa_block_append_qos_ecn);
1607
1608int 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}
1624EXPORT_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
1635enum 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 */
1643MLXSW_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 */
1649MLXSW_ITEM32(afa, forward, pbs_ptr, 0x08, 0, 24);
1650
1651/* afa_forward_in_port
1652 * Packet is forwarded back to the ingress port.
1653 */
1654MLXSW_ITEM32(afa, forward, in_port, 0x0C, 0, 1);
1655
1656static inline void
1657mlxsw_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
1665int 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                err = PTR_ERR(act);
1689                NL_SET_ERR_MSG_MOD(extack, "Cannot append forward action");
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
1696err_append_action:
1697        mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref);
1698        return err;
1699}
1700EXPORT_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
1711enum {
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 */
1722MLXSW_ITEM32(afa, polcnt, c_p, 0x00, 31, 1);
1723
1724enum 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 */
1736MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8);
1737
1738/* afa_polcnt_counter_index
1739 * Counter index for flow counters.
1740 */
1741MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24);
1742
1743/* afa_polcnt_pid
1744 * Policer ID.
1745 * Reserved when c_p = 0
1746 */
1747MLXSW_ITEM32(afa, polcnt, pid, 0x08, 0, 14);
1748
1749static inline void
1750mlxsw_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
1759static 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
1765int 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}
1776EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter);
1777
1778int 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
1802err_append_allocated_counter:
1803        mlxsw_afa_counter_destroy(block, counter);
1804        return err;
1805}
1806EXPORT_SYMBOL(mlxsw_afa_block_append_counter);
1807
1808int 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
1836err_append_action:
1837        mlxsw_afa_policer_ref_destroy(block, policer_ref);
1838        return err;
1839}
1840EXPORT_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
1851enum 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 */
1859MLXSW_ITEM32(afa, virfwd, fid_cmd, 0x08, 29, 3);
1860
1861/* afa_virfwd_fid
1862 * The FID value.
1863 */
1864MLXSW_ITEM32(afa, virfwd, fid, 0x08, 0, 16);
1865
1866static 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
1874int 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}
1887EXPORT_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
1898enum 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 */
1905MLXSW_ITEM32(afa, mcrouter, rpf_action, 0x00, 28, 3);
1906
1907/* afa_mcrouter_expected_irif */
1908MLXSW_ITEM32(afa, mcrouter, expected_irif, 0x00, 0, 16);
1909
1910/* afa_mcrouter_min_mtu */
1911MLXSW_ITEM32(afa, mcrouter, min_mtu, 0x08, 0, 16);
1912
1913enum 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 */
1921MLXSW_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 */
1929MLXSW_ITEM32(afa, mcrouter, rigr_rmid_index, 0x0C, 0, 24);
1930
1931static inline void
1932mlxsw_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
1945int 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}
1958EXPORT_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
1969enum 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 */
1979MLXSW_ITEM32(afa, l4port, s_d, 0x00, 31, 1);
1980
1981/* afa_l4port_l4_port
1982 * Number of port to change to.
1983 */
1984MLXSW_ITEM32(afa, l4port, l4_port, 0x08, 0, 16);
1985
1986static 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
1992int 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}
2009EXPORT_SYMBOL(mlxsw_afa_block_append_l4port);
2010
2011/* Mirror Sampler Action
2012 * ---------------------
2013 * The SAMPLER_ACTION is used to mirror packets with a probability (sampling).
2014 */
2015
2016#define MLXSW_AFA_SAMPLER_CODE 0x13
2017#define MLXSW_AFA_SAMPLER_SIZE 1
2018
2019/* afa_sampler_mirror_agent
2020 * Mirror (SPAN) agent.
2021 */
2022MLXSW_ITEM32(afa, sampler, mirror_agent, 0x04, 0, 3);
2023
2024#define MLXSW_AFA_SAMPLER_RATE_MAX (BIT(24) - 1)
2025
2026/* afa_sampler_mirror_probability_rate
2027 * Mirroring probability.
2028 * Valid values are 1 to 2^24 - 1
2029 */
2030MLXSW_ITEM32(afa, sampler, mirror_probability_rate, 0x08, 0, 24);
2031
2032static void mlxsw_afa_sampler_pack(char *payload, u8 mirror_agent, u32 rate)
2033{
2034        mlxsw_afa_sampler_mirror_agent_set(payload, mirror_agent);
2035        mlxsw_afa_sampler_mirror_probability_rate_set(payload, rate);
2036}
2037
2038struct mlxsw_afa_sampler {
2039        struct mlxsw_afa_resource resource;
2040        int span_id;
2041        u8 local_port;
2042        bool ingress;
2043};
2044
2045static void mlxsw_afa_sampler_destroy(struct mlxsw_afa_block *block,
2046                                      struct mlxsw_afa_sampler *sampler)
2047{
2048        mlxsw_afa_resource_del(&sampler->resource);
2049        block->afa->ops->sampler_del(block->afa->ops_priv, sampler->local_port,
2050                                     sampler->span_id, sampler->ingress);
2051        kfree(sampler);
2052}
2053
2054static void mlxsw_afa_sampler_destructor(struct mlxsw_afa_block *block,
2055                                         struct mlxsw_afa_resource *resource)
2056{
2057        struct mlxsw_afa_sampler *sampler;
2058
2059        sampler = container_of(resource, struct mlxsw_afa_sampler, resource);
2060        mlxsw_afa_sampler_destroy(block, sampler);
2061}
2062
2063static struct mlxsw_afa_sampler *
2064mlxsw_afa_sampler_create(struct mlxsw_afa_block *block, u8 local_port,
2065                         struct psample_group *psample_group, u32 rate,
2066                         u32 trunc_size, bool truncate, bool ingress,
2067                         struct netlink_ext_ack *extack)
2068{
2069        struct mlxsw_afa_sampler *sampler;
2070        int err;
2071
2072        sampler = kzalloc(sizeof(*sampler), GFP_KERNEL);
2073        if (!sampler)
2074                return ERR_PTR(-ENOMEM);
2075
2076        err = block->afa->ops->sampler_add(block->afa->ops_priv, local_port,
2077                                           psample_group, rate, trunc_size,
2078                                           truncate, ingress, &sampler->span_id,
2079                                           extack);
2080        if (err)
2081                goto err_sampler_add;
2082
2083        sampler->ingress = ingress;
2084        sampler->local_port = local_port;
2085        sampler->resource.destructor = mlxsw_afa_sampler_destructor;
2086        mlxsw_afa_resource_add(block, &sampler->resource);
2087        return sampler;
2088
2089err_sampler_add:
2090        kfree(sampler);
2091        return ERR_PTR(err);
2092}
2093
2094static int
2095mlxsw_afa_block_append_allocated_sampler(struct mlxsw_afa_block *block,
2096                                         u8 mirror_agent, u32 rate)
2097{
2098        char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_SAMPLER_CODE,
2099                                                  MLXSW_AFA_SAMPLER_SIZE);
2100
2101        if (IS_ERR(act))
2102                return PTR_ERR(act);
2103        mlxsw_afa_sampler_pack(act, mirror_agent, rate);
2104        return 0;
2105}
2106
2107int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u8 local_port,
2108                                   struct psample_group *psample_group,
2109                                   u32 rate, u32 trunc_size, bool truncate,
2110                                   bool ingress,
2111                                   struct netlink_ext_ack *extack)
2112{
2113        struct mlxsw_afa_sampler *sampler;
2114        int err;
2115
2116        if (rate > MLXSW_AFA_SAMPLER_RATE_MAX) {
2117                NL_SET_ERR_MSG_MOD(extack, "Sampling rate is too high");
2118                return -EINVAL;
2119        }
2120
2121        sampler = mlxsw_afa_sampler_create(block, local_port, psample_group,
2122                                           rate, trunc_size, truncate, ingress,
2123                                           extack);
2124        if (IS_ERR(sampler))
2125                return PTR_ERR(sampler);
2126
2127        err = mlxsw_afa_block_append_allocated_sampler(block, sampler->span_id,
2128                                                       rate);
2129        if (err) {
2130                NL_SET_ERR_MSG_MOD(extack, "Cannot append sampler action");
2131                goto err_append_allocated_sampler;
2132        }
2133
2134        return 0;
2135
2136err_append_allocated_sampler:
2137        mlxsw_afa_sampler_destroy(block, sampler);
2138        return err;
2139}
2140EXPORT_SYMBOL(mlxsw_afa_block_append_sampler);
2141