linux/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
<<
>>
Prefs
   1/*
   2 * drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
   3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
   4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions are met:
   8 *
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. Neither the names of the copyright holders nor the names of its
  15 *    contributors may be used to endorse or promote products derived from
  16 *    this software without specific prior written permission.
  17 *
  18 * Alternatively, this software may be distributed under the terms of the
  19 * GNU General Public License ("GPL") version 2 as published by the Free
  20 * Software Foundation.
  21 *
  22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32 * POSSIBILITY OF SUCH DAMAGE.
  33 */
  34
  35#include <linux/kernel.h>
  36#include <linux/types.h>
  37#include <linux/slab.h>
  38#include <linux/errno.h>
  39#include <linux/rhashtable.h>
  40#include <linux/list.h>
  41
  42#include "item.h"
  43#include "trap.h"
  44#include "core_acl_flex_actions.h"
  45
  46enum mlxsw_afa_set_type {
  47        MLXSW_AFA_SET_TYPE_NEXT,
  48        MLXSW_AFA_SET_TYPE_GOTO,
  49};
  50
  51/* afa_set_type
  52 * Type of the record at the end of the action set.
  53 */
  54MLXSW_ITEM32(afa, set, type, 0xA0, 28, 4);
  55
  56/* afa_set_next_action_set_ptr
  57 * A pointer to the next action set in the KVD Centralized database.
  58 */
  59MLXSW_ITEM32(afa, set, next_action_set_ptr, 0xA4, 0, 24);
  60
  61/* afa_set_goto_g
  62 * group - When set, the binding is of an ACL group. When cleared,
  63 * the binding is of an ACL.
  64 * Must be set to 1 for Spectrum.
  65 */
  66MLXSW_ITEM32(afa, set, goto_g, 0xA4, 29, 1);
  67
  68enum mlxsw_afa_set_goto_binding_cmd {
  69        /* continue go the next binding point */
  70        MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE,
  71        /* jump to the next binding point no return */
  72        MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP,
  73        /* terminate the acl binding */
  74        MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM = 4,
  75};
  76
  77/* afa_set_goto_binding_cmd */
  78MLXSW_ITEM32(afa, set, goto_binding_cmd, 0xA4, 24, 3);
  79
  80/* afa_set_goto_next_binding
  81 * ACL/ACL group identifier. If the g bit is set, this field should hold
  82 * the acl_group_id, else it should hold the acl_id.
  83 */
  84MLXSW_ITEM32(afa, set, goto_next_binding, 0xA4, 0, 16);
  85
  86/* afa_all_action_type
  87 * Action Type.
  88 */
  89MLXSW_ITEM32(afa, all, action_type, 0x00, 24, 6);
  90
  91struct mlxsw_afa {
  92        unsigned int max_acts_per_set;
  93        const struct mlxsw_afa_ops *ops;
  94        void *ops_priv;
  95        struct rhashtable set_ht;
  96        struct rhashtable fwd_entry_ht;
  97};
  98
  99#define MLXSW_AFA_SET_LEN 0xA8
 100
 101struct mlxsw_afa_set_ht_key {
 102        char enc_actions[MLXSW_AFA_SET_LEN]; /* Encoded set */
 103        bool is_first;
 104};
 105
 106/* Set structure holds one action set record. It contains up to three
 107 * actions (depends on size of particular actions). The set is either
 108 * put directly to a rule, or it is stored in KVD linear area.
 109 * To prevent duplicate entries in KVD linear area, a hashtable is
 110 * used to track sets that were previously inserted and may be shared.
 111 */
 112
 113struct mlxsw_afa_set {
 114        struct rhash_head ht_node;
 115        struct mlxsw_afa_set_ht_key ht_key;
 116        u32 kvdl_index;
 117        bool shared; /* Inserted in hashtable (doesn't mean that
 118                      * kvdl_index is valid).
 119                      */
 120        unsigned int ref_count;
 121        struct mlxsw_afa_set *next; /* Pointer to the next set. */
 122        struct mlxsw_afa_set *prev; /* Pointer to the previous set,
 123                                     * note that set may have multiple
 124                                     * sets from multiple blocks
 125                                     * pointing at it. This is only
 126                                     * usable until commit.
 127                                     */
 128};
 129
 130static const struct rhashtable_params mlxsw_afa_set_ht_params = {
 131        .key_len = sizeof(struct mlxsw_afa_set_ht_key),
 132        .key_offset = offsetof(struct mlxsw_afa_set, ht_key),
 133        .head_offset = offsetof(struct mlxsw_afa_set, ht_node),
 134        .automatic_shrinking = true,
 135};
 136
 137struct mlxsw_afa_fwd_entry_ht_key {
 138        u8 local_port;
 139};
 140
 141struct mlxsw_afa_fwd_entry {
 142        struct rhash_head ht_node;
 143        struct mlxsw_afa_fwd_entry_ht_key ht_key;
 144        u32 kvdl_index;
 145        unsigned int ref_count;
 146};
 147
 148static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = {
 149        .key_len = sizeof(struct mlxsw_afa_fwd_entry_ht_key),
 150        .key_offset = offsetof(struct mlxsw_afa_fwd_entry, ht_key),
 151        .head_offset = offsetof(struct mlxsw_afa_fwd_entry, ht_node),
 152        .automatic_shrinking = true,
 153};
 154
 155struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set,
 156                                   const struct mlxsw_afa_ops *ops,
 157                                   void *ops_priv)
 158{
 159        struct mlxsw_afa *mlxsw_afa;
 160        int err;
 161
 162        mlxsw_afa = kzalloc(sizeof(*mlxsw_afa), GFP_KERNEL);
 163        if (!mlxsw_afa)
 164                return ERR_PTR(-ENOMEM);
 165        err = rhashtable_init(&mlxsw_afa->set_ht, &mlxsw_afa_set_ht_params);
 166        if (err)
 167                goto err_set_rhashtable_init;
 168        err = rhashtable_init(&mlxsw_afa->fwd_entry_ht,
 169                              &mlxsw_afa_fwd_entry_ht_params);
 170        if (err)
 171                goto err_fwd_entry_rhashtable_init;
 172        mlxsw_afa->max_acts_per_set = max_acts_per_set;
 173        mlxsw_afa->ops = ops;
 174        mlxsw_afa->ops_priv = ops_priv;
 175        return mlxsw_afa;
 176
 177err_fwd_entry_rhashtable_init:
 178        rhashtable_destroy(&mlxsw_afa->set_ht);
 179err_set_rhashtable_init:
 180        kfree(mlxsw_afa);
 181        return ERR_PTR(err);
 182}
 183EXPORT_SYMBOL(mlxsw_afa_create);
 184
 185void mlxsw_afa_destroy(struct mlxsw_afa *mlxsw_afa)
 186{
 187        rhashtable_destroy(&mlxsw_afa->fwd_entry_ht);
 188        rhashtable_destroy(&mlxsw_afa->set_ht);
 189        kfree(mlxsw_afa);
 190}
 191EXPORT_SYMBOL(mlxsw_afa_destroy);
 192
 193static void mlxsw_afa_set_goto_set(struct mlxsw_afa_set *set,
 194                                   enum mlxsw_afa_set_goto_binding_cmd cmd,
 195                                   u16 group_id)
 196{
 197        char *actions = set->ht_key.enc_actions;
 198
 199        mlxsw_afa_set_type_set(actions, MLXSW_AFA_SET_TYPE_GOTO);
 200        mlxsw_afa_set_goto_g_set(actions, true);
 201        mlxsw_afa_set_goto_binding_cmd_set(actions, cmd);
 202        mlxsw_afa_set_goto_next_binding_set(actions, group_id);
 203}
 204
 205static void mlxsw_afa_set_next_set(struct mlxsw_afa_set *set,
 206                                   u32 next_set_kvdl_index)
 207{
 208        char *actions = set->ht_key.enc_actions;
 209
 210        mlxsw_afa_set_type_set(actions, MLXSW_AFA_SET_TYPE_NEXT);
 211        mlxsw_afa_set_next_action_set_ptr_set(actions, next_set_kvdl_index);
 212}
 213
 214static struct mlxsw_afa_set *mlxsw_afa_set_create(bool is_first)
 215{
 216        struct mlxsw_afa_set *set;
 217
 218        set = kzalloc(sizeof(*set), GFP_KERNEL);
 219        if (!set)
 220                return NULL;
 221        /* Need to initialize the set to pass by default */
 222        mlxsw_afa_set_goto_set(set, MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0);
 223        set->ht_key.is_first = is_first;
 224        set->ref_count = 1;
 225        return set;
 226}
 227
 228static void mlxsw_afa_set_destroy(struct mlxsw_afa_set *set)
 229{
 230        kfree(set);
 231}
 232
 233static int mlxsw_afa_set_share(struct mlxsw_afa *mlxsw_afa,
 234                               struct mlxsw_afa_set *set)
 235{
 236        int err;
 237
 238        err = rhashtable_insert_fast(&mlxsw_afa->set_ht, &set->ht_node,
 239                                     mlxsw_afa_set_ht_params);
 240        if (err)
 241                return err;
 242        err = mlxsw_afa->ops->kvdl_set_add(mlxsw_afa->ops_priv,
 243                                           &set->kvdl_index,
 244                                           set->ht_key.enc_actions,
 245                                           set->ht_key.is_first);
 246        if (err)
 247                goto err_kvdl_set_add;
 248        set->shared = true;
 249        set->prev = NULL;
 250        return 0;
 251
 252err_kvdl_set_add:
 253        rhashtable_remove_fast(&mlxsw_afa->set_ht, &set->ht_node,
 254                               mlxsw_afa_set_ht_params);
 255        return err;
 256}
 257
 258static void mlxsw_afa_set_unshare(struct mlxsw_afa *mlxsw_afa,
 259                                  struct mlxsw_afa_set *set)
 260{
 261        mlxsw_afa->ops->kvdl_set_del(mlxsw_afa->ops_priv,
 262                                     set->kvdl_index,
 263                                     set->ht_key.is_first);
 264        rhashtable_remove_fast(&mlxsw_afa->set_ht, &set->ht_node,
 265                               mlxsw_afa_set_ht_params);
 266        set->shared = false;
 267}
 268
 269static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa,
 270                              struct mlxsw_afa_set *set)
 271{
 272        if (--set->ref_count)
 273                return;
 274        if (set->shared)
 275                mlxsw_afa_set_unshare(mlxsw_afa, set);
 276        mlxsw_afa_set_destroy(set);
 277}
 278
 279static struct mlxsw_afa_set *mlxsw_afa_set_get(struct mlxsw_afa *mlxsw_afa,
 280                                               struct mlxsw_afa_set *orig_set)
 281{
 282        struct mlxsw_afa_set *set;
 283        int err;
 284
 285        /* There is a hashtable of sets maintained. If a set with the exact
 286         * same encoding exists, we reuse it. Otherwise, the current set
 287         * is shared by making it available to others using the hash table.
 288         */
 289        set = rhashtable_lookup_fast(&mlxsw_afa->set_ht, &orig_set->ht_key,
 290                                     mlxsw_afa_set_ht_params);
 291        if (set) {
 292                set->ref_count++;
 293                mlxsw_afa_set_put(mlxsw_afa, orig_set);
 294        } else {
 295                set = orig_set;
 296                err = mlxsw_afa_set_share(mlxsw_afa, set);
 297                if (err)
 298                        return ERR_PTR(err);
 299        }
 300        return set;
 301}
 302
 303/* Block structure holds a list of action sets. One action block
 304 * represents one chain of actions executed upon match of a rule.
 305 */
 306
 307struct mlxsw_afa_block {
 308        struct mlxsw_afa *afa;
 309        bool finished;
 310        struct mlxsw_afa_set *first_set;
 311        struct mlxsw_afa_set *cur_set;
 312        unsigned int cur_act_index; /* In current set. */
 313        struct list_head fwd_entry_ref_list;
 314};
 315
 316struct mlxsw_afa_block *mlxsw_afa_block_create(struct mlxsw_afa *mlxsw_afa)
 317{
 318        struct mlxsw_afa_block *block;
 319
 320        block = kzalloc(sizeof(*block), GFP_KERNEL);
 321        if (!block)
 322                return NULL;
 323        INIT_LIST_HEAD(&block->fwd_entry_ref_list);
 324        block->afa = mlxsw_afa;
 325
 326        /* At least one action set is always present, so just create it here */
 327        block->first_set = mlxsw_afa_set_create(true);
 328        if (!block->first_set)
 329                goto err_first_set_create;
 330        block->cur_set = block->first_set;
 331        return block;
 332
 333err_first_set_create:
 334        kfree(block);
 335        return NULL;
 336}
 337EXPORT_SYMBOL(mlxsw_afa_block_create);
 338
 339static void mlxsw_afa_fwd_entry_refs_destroy(struct mlxsw_afa_block *block);
 340
 341void mlxsw_afa_block_destroy(struct mlxsw_afa_block *block)
 342{
 343        struct mlxsw_afa_set *set = block->first_set;
 344        struct mlxsw_afa_set *next_set;
 345
 346        do {
 347                next_set = set->next;
 348                mlxsw_afa_set_put(block->afa, set);
 349                set = next_set;
 350        } while (set);
 351        mlxsw_afa_fwd_entry_refs_destroy(block);
 352        kfree(block);
 353}
 354EXPORT_SYMBOL(mlxsw_afa_block_destroy);
 355
 356int mlxsw_afa_block_commit(struct mlxsw_afa_block *block)
 357{
 358        struct mlxsw_afa_set *set = block->cur_set;
 359        struct mlxsw_afa_set *prev_set;
 360
 361        block->cur_set = NULL;
 362        block->finished = true;
 363
 364        /* Go over all linked sets starting from last
 365         * and try to find existing set in the hash table.
 366         * In case it is not there, assign a KVD linear index
 367         * and insert it.
 368         */
 369        do {
 370                prev_set = set->prev;
 371                set = mlxsw_afa_set_get(block->afa, set);
 372                if (IS_ERR(set))
 373                        /* No rollback is needed since the chain is
 374                         * in consistent state and mlxsw_afa_block_destroy
 375                         * will take care of putting it away.
 376                         */
 377                        return PTR_ERR(set);
 378                if (prev_set) {
 379                        prev_set->next = set;
 380                        mlxsw_afa_set_next_set(prev_set, set->kvdl_index);
 381                        set = prev_set;
 382                }
 383        } while (prev_set);
 384
 385        block->first_set = set;
 386        return 0;
 387}
 388EXPORT_SYMBOL(mlxsw_afa_block_commit);
 389
 390char *mlxsw_afa_block_first_set(struct mlxsw_afa_block *block)
 391{
 392        return block->first_set->ht_key.enc_actions;
 393}
 394EXPORT_SYMBOL(mlxsw_afa_block_first_set);
 395
 396u32 mlxsw_afa_block_first_set_kvdl_index(struct mlxsw_afa_block *block)
 397{
 398        return block->first_set->kvdl_index;
 399}
 400EXPORT_SYMBOL(mlxsw_afa_block_first_set_kvdl_index);
 401
 402void mlxsw_afa_block_continue(struct mlxsw_afa_block *block)
 403{
 404        if (WARN_ON(block->finished))
 405                return;
 406        mlxsw_afa_set_goto_set(block->cur_set,
 407                               MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE, 0);
 408        block->finished = true;
 409}
 410EXPORT_SYMBOL(mlxsw_afa_block_continue);
 411
 412void mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id)
 413{
 414        if (WARN_ON(block->finished))
 415                return;
 416        mlxsw_afa_set_goto_set(block->cur_set,
 417                               MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP, group_id);
 418        block->finished = true;
 419}
 420EXPORT_SYMBOL(mlxsw_afa_block_jump);
 421
 422static struct mlxsw_afa_fwd_entry *
 423mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u8 local_port)
 424{
 425        struct mlxsw_afa_fwd_entry *fwd_entry;
 426        int err;
 427
 428        fwd_entry = kzalloc(sizeof(*fwd_entry), GFP_KERNEL);
 429        if (!fwd_entry)
 430                return ERR_PTR(-ENOMEM);
 431        fwd_entry->ht_key.local_port = local_port;
 432        fwd_entry->ref_count = 1;
 433
 434        err = rhashtable_insert_fast(&mlxsw_afa->fwd_entry_ht,
 435                                     &fwd_entry->ht_node,
 436                                     mlxsw_afa_fwd_entry_ht_params);
 437        if (err)
 438                goto err_rhashtable_insert;
 439
 440        err = mlxsw_afa->ops->kvdl_fwd_entry_add(mlxsw_afa->ops_priv,
 441                                                 &fwd_entry->kvdl_index,
 442                                                 local_port);
 443        if (err)
 444                goto err_kvdl_fwd_entry_add;
 445        return fwd_entry;
 446
 447err_kvdl_fwd_entry_add:
 448        rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node,
 449                               mlxsw_afa_fwd_entry_ht_params);
 450err_rhashtable_insert:
 451        kfree(fwd_entry);
 452        return ERR_PTR(err);
 453}
 454
 455static void mlxsw_afa_fwd_entry_destroy(struct mlxsw_afa *mlxsw_afa,
 456                                        struct mlxsw_afa_fwd_entry *fwd_entry)
 457{
 458        mlxsw_afa->ops->kvdl_fwd_entry_del(mlxsw_afa->ops_priv,
 459                                           fwd_entry->kvdl_index);
 460        rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node,
 461                               mlxsw_afa_fwd_entry_ht_params);
 462        kfree(fwd_entry);
 463}
 464
 465static struct mlxsw_afa_fwd_entry *
 466mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u8 local_port)
 467{
 468        struct mlxsw_afa_fwd_entry_ht_key ht_key = {0};
 469        struct mlxsw_afa_fwd_entry *fwd_entry;
 470
 471        ht_key.local_port = local_port;
 472        fwd_entry = rhashtable_lookup_fast(&mlxsw_afa->fwd_entry_ht, &ht_key,
 473                                           mlxsw_afa_fwd_entry_ht_params);
 474        if (fwd_entry) {
 475                fwd_entry->ref_count++;
 476                return fwd_entry;
 477        }
 478        return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port);
 479}
 480
 481static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa,
 482                                    struct mlxsw_afa_fwd_entry *fwd_entry)
 483{
 484        if (--fwd_entry->ref_count)
 485                return;
 486        mlxsw_afa_fwd_entry_destroy(mlxsw_afa, fwd_entry);
 487}
 488
 489struct mlxsw_afa_fwd_entry_ref {
 490        struct list_head list;
 491        struct mlxsw_afa_fwd_entry *fwd_entry;
 492};
 493
 494static struct mlxsw_afa_fwd_entry_ref *
 495mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u8 local_port)
 496{
 497        struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref;
 498        struct mlxsw_afa_fwd_entry *fwd_entry;
 499        int err;
 500
 501        fwd_entry_ref = kzalloc(sizeof(*fwd_entry_ref), GFP_KERNEL);
 502        if (!fwd_entry_ref)
 503                return ERR_PTR(-ENOMEM);
 504        fwd_entry = mlxsw_afa_fwd_entry_get(block->afa, local_port);
 505        if (IS_ERR(fwd_entry)) {
 506                err = PTR_ERR(fwd_entry);
 507                goto err_fwd_entry_get;
 508        }
 509        fwd_entry_ref->fwd_entry = fwd_entry;
 510        list_add(&fwd_entry_ref->list, &block->fwd_entry_ref_list);
 511        return fwd_entry_ref;
 512
 513err_fwd_entry_get:
 514        kfree(fwd_entry_ref);
 515        return ERR_PTR(err);
 516}
 517
 518static void
 519mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block *block,
 520                                struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref)
 521{
 522        list_del(&fwd_entry_ref->list);
 523        mlxsw_afa_fwd_entry_put(block->afa, fwd_entry_ref->fwd_entry);
 524        kfree(fwd_entry_ref);
 525}
 526
 527static void mlxsw_afa_fwd_entry_refs_destroy(struct mlxsw_afa_block *block)
 528{
 529        struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref;
 530        struct mlxsw_afa_fwd_entry_ref *tmp;
 531
 532        list_for_each_entry_safe(fwd_entry_ref, tmp,
 533                                 &block->fwd_entry_ref_list, list)
 534                mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref);
 535}
 536
 537#define MLXSW_AFA_ONE_ACTION_LEN 32
 538#define MLXSW_AFA_PAYLOAD_OFFSET 4
 539
 540static char *mlxsw_afa_block_append_action(struct mlxsw_afa_block *block,
 541                                           u8 action_code, u8 action_size)
 542{
 543        char *oneact;
 544        char *actions;
 545
 546        if (WARN_ON(block->finished))
 547                return NULL;
 548        if (block->cur_act_index + action_size >
 549            block->afa->max_acts_per_set) {
 550                struct mlxsw_afa_set *set;
 551
 552                /* The appended action won't fit into the current action set,
 553                 * so create a new set.
 554                 */
 555                set = mlxsw_afa_set_create(false);
 556                if (!set)
 557                        return NULL;
 558                set->prev = block->cur_set;
 559                block->cur_act_index = 0;
 560                block->cur_set->next = set;
 561                block->cur_set = set;
 562        }
 563
 564        actions = block->cur_set->ht_key.enc_actions;
 565        oneact = actions + block->cur_act_index * MLXSW_AFA_ONE_ACTION_LEN;
 566        block->cur_act_index += action_size;
 567        mlxsw_afa_all_action_type_set(oneact, action_code);
 568        return oneact + MLXSW_AFA_PAYLOAD_OFFSET;
 569}
 570
 571/* VLAN Action
 572 * -----------
 573 * VLAN action is used for manipulating VLANs. It can be used to implement QinQ,
 574 * VLAN translation, change of PCP bits of the VLAN tag, push, pop as swap VLANs
 575 * and more.
 576 */
 577
 578#define MLXSW_AFA_VLAN_CODE 0x02
 579#define MLXSW_AFA_VLAN_SIZE 1
 580
 581enum mlxsw_afa_vlan_vlan_tag_cmd {
 582        MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP,
 583        MLXSW_AFA_VLAN_VLAN_TAG_CMD_PUSH_TAG,
 584        MLXSW_AFA_VLAN_VLAN_TAG_CMD_POP_TAG,
 585};
 586
 587enum mlxsw_afa_vlan_cmd {
 588        MLXSW_AFA_VLAN_CMD_NOP,
 589        MLXSW_AFA_VLAN_CMD_SET_OUTER,
 590        MLXSW_AFA_VLAN_CMD_SET_INNER,
 591        MLXSW_AFA_VLAN_CMD_COPY_OUTER_TO_INNER,
 592        MLXSW_AFA_VLAN_CMD_COPY_INNER_TO_OUTER,
 593        MLXSW_AFA_VLAN_CMD_SWAP,
 594};
 595
 596/* afa_vlan_vlan_tag_cmd
 597 * Tag command: push, pop, nop VLAN header.
 598 */
 599MLXSW_ITEM32(afa, vlan, vlan_tag_cmd, 0x00, 29, 3);
 600
 601/* afa_vlan_vid_cmd */
 602MLXSW_ITEM32(afa, vlan, vid_cmd, 0x04, 29, 3);
 603
 604/* afa_vlan_vid */
 605MLXSW_ITEM32(afa, vlan, vid, 0x04, 0, 12);
 606
 607/* afa_vlan_ethertype_cmd */
 608MLXSW_ITEM32(afa, vlan, ethertype_cmd, 0x08, 29, 3);
 609
 610/* afa_vlan_ethertype
 611 * Index to EtherTypes in Switch VLAN EtherType Register (SVER).
 612 */
 613MLXSW_ITEM32(afa, vlan, ethertype, 0x08, 24, 3);
 614
 615/* afa_vlan_pcp_cmd */
 616MLXSW_ITEM32(afa, vlan, pcp_cmd, 0x08, 13, 3);
 617
 618/* afa_vlan_pcp */
 619MLXSW_ITEM32(afa, vlan, pcp, 0x08, 8, 3);
 620
 621static inline void
 622mlxsw_afa_vlan_pack(char *payload,
 623                    enum mlxsw_afa_vlan_vlan_tag_cmd vlan_tag_cmd,
 624                    enum mlxsw_afa_vlan_cmd vid_cmd, u16 vid,
 625                    enum mlxsw_afa_vlan_cmd pcp_cmd, u8 pcp,
 626                    enum mlxsw_afa_vlan_cmd ethertype_cmd, u8 ethertype)
 627{
 628        mlxsw_afa_vlan_vlan_tag_cmd_set(payload, vlan_tag_cmd);
 629        mlxsw_afa_vlan_vid_cmd_set(payload, vid_cmd);
 630        mlxsw_afa_vlan_vid_set(payload, vid);
 631        mlxsw_afa_vlan_pcp_cmd_set(payload, pcp_cmd);
 632        mlxsw_afa_vlan_pcp_set(payload, pcp);
 633        mlxsw_afa_vlan_ethertype_cmd_set(payload, ethertype_cmd);
 634        mlxsw_afa_vlan_ethertype_set(payload, ethertype);
 635}
 636
 637int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block,
 638                                       u16 vid, u8 pcp, u8 et)
 639{
 640        char *act = mlxsw_afa_block_append_action(block,
 641                                                  MLXSW_AFA_VLAN_CODE,
 642                                                  MLXSW_AFA_VLAN_SIZE);
 643
 644        if (!act)
 645                return -ENOBUFS;
 646        mlxsw_afa_vlan_pack(act, MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP,
 647                            MLXSW_AFA_VLAN_CMD_SET_OUTER, vid,
 648                            MLXSW_AFA_VLAN_CMD_SET_OUTER, pcp,
 649                            MLXSW_AFA_VLAN_CMD_SET_OUTER, et);
 650        return 0;
 651}
 652EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify);
 653
 654/* Trap / Discard Action
 655 * ---------------------
 656 * The Trap / Discard action enables trapping / mirroring packets to the CPU
 657 * as well as discarding packets.
 658 * The ACL Trap / Discard separates the forward/discard control from CPU
 659 * trap control. In addition, the Trap / Discard action enables activating
 660 * SPAN (port mirroring).
 661 */
 662
 663#define MLXSW_AFA_TRAPDISC_CODE 0x03
 664#define MLXSW_AFA_TRAPDISC_SIZE 1
 665
 666enum mlxsw_afa_trapdisc_trap_action {
 667        MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP = 0,
 668        MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP = 2,
 669};
 670
 671/* afa_trapdisc_trap_action
 672 * Trap Action.
 673 */
 674MLXSW_ITEM32(afa, trapdisc, trap_action, 0x00, 24, 4);
 675
 676enum mlxsw_afa_trapdisc_forward_action {
 677        MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD = 3,
 678};
 679
 680/* afa_trapdisc_forward_action
 681 * Forward Action.
 682 */
 683MLXSW_ITEM32(afa, trapdisc, forward_action, 0x00, 0, 4);
 684
 685/* afa_trapdisc_trap_id
 686 * Trap ID to configure.
 687 */
 688MLXSW_ITEM32(afa, trapdisc, trap_id, 0x04, 0, 9);
 689
 690static inline void
 691mlxsw_afa_trapdisc_pack(char *payload,
 692                        enum mlxsw_afa_trapdisc_trap_action trap_action,
 693                        enum mlxsw_afa_trapdisc_forward_action forward_action,
 694                        u16 trap_id)
 695{
 696        mlxsw_afa_trapdisc_trap_action_set(payload, trap_action);
 697        mlxsw_afa_trapdisc_forward_action_set(payload, forward_action);
 698        mlxsw_afa_trapdisc_trap_id_set(payload, trap_id);
 699}
 700
 701int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block)
 702{
 703        char *act = mlxsw_afa_block_append_action(block,
 704                                                  MLXSW_AFA_TRAPDISC_CODE,
 705                                                  MLXSW_AFA_TRAPDISC_SIZE);
 706
 707        if (!act)
 708                return -ENOBUFS;
 709        mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP,
 710                                MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, 0);
 711        return 0;
 712}
 713EXPORT_SYMBOL(mlxsw_afa_block_append_drop);
 714
 715int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block)
 716{
 717        char *act = mlxsw_afa_block_append_action(block,
 718                                                  MLXSW_AFA_TRAPDISC_CODE,
 719                                                  MLXSW_AFA_TRAPDISC_SIZE);
 720
 721        if (!act)
 722                return -ENOBUFS;
 723        mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP,
 724                                MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD,
 725                                MLXSW_TRAP_ID_ACL0);
 726        return 0;
 727}
 728EXPORT_SYMBOL(mlxsw_afa_block_append_trap);
 729
 730/* Forwarding Action
 731 * -----------------
 732 * Forwarding Action can be used to implement Policy Based Switching (PBS)
 733 * as well as OpenFlow related "Output" action.
 734 */
 735
 736#define MLXSW_AFA_FORWARD_CODE 0x07
 737#define MLXSW_AFA_FORWARD_SIZE 1
 738
 739enum mlxsw_afa_forward_type {
 740        /* PBS, Policy Based Switching */
 741        MLXSW_AFA_FORWARD_TYPE_PBS,
 742        /* Output, OpenFlow output type */
 743        MLXSW_AFA_FORWARD_TYPE_OUTPUT,
 744};
 745
 746/* afa_forward_type */
 747MLXSW_ITEM32(afa, forward, type, 0x00, 24, 2);
 748
 749/* afa_forward_pbs_ptr
 750 * A pointer to the PBS entry configured by PPBS register.
 751 * Reserved when in_port is set.
 752 */
 753MLXSW_ITEM32(afa, forward, pbs_ptr, 0x08, 0, 24);
 754
 755/* afa_forward_in_port
 756 * Packet is forwarded back to the ingress port.
 757 */
 758MLXSW_ITEM32(afa, forward, in_port, 0x0C, 0, 1);
 759
 760static inline void
 761mlxsw_afa_forward_pack(char *payload, enum mlxsw_afa_forward_type type,
 762                       u32 pbs_ptr, bool in_port)
 763{
 764        mlxsw_afa_forward_type_set(payload, type);
 765        mlxsw_afa_forward_pbs_ptr_set(payload, pbs_ptr);
 766        mlxsw_afa_forward_in_port_set(payload, in_port);
 767}
 768
 769int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block,
 770                               u8 local_port, bool in_port)
 771{
 772        struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref;
 773        u32 kvdl_index;
 774        char *act;
 775        int err;
 776
 777        if (in_port)
 778                return -EOPNOTSUPP;
 779        fwd_entry_ref = mlxsw_afa_fwd_entry_ref_create(block, local_port);
 780        if (IS_ERR(fwd_entry_ref))
 781                return PTR_ERR(fwd_entry_ref);
 782        kvdl_index = fwd_entry_ref->fwd_entry->kvdl_index;
 783
 784        act = mlxsw_afa_block_append_action(block, MLXSW_AFA_FORWARD_CODE,
 785                                            MLXSW_AFA_FORWARD_SIZE);
 786        if (!act) {
 787                err = -ENOBUFS;
 788                goto err_append_action;
 789        }
 790        mlxsw_afa_forward_pack(act, MLXSW_AFA_FORWARD_TYPE_PBS,
 791                               kvdl_index, in_port);
 792        return 0;
 793
 794err_append_action:
 795        mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref);
 796        return err;
 797}
 798EXPORT_SYMBOL(mlxsw_afa_block_append_fwd);
 799
 800/* Policing and Counting Action
 801 * ----------------------------
 802 * Policing and Counting action is used for binding policer and counter
 803 * to ACL rules.
 804 */
 805
 806#define MLXSW_AFA_POLCNT_CODE 0x08
 807#define MLXSW_AFA_POLCNT_SIZE 1
 808
 809enum mlxsw_afa_polcnt_counter_set_type {
 810        /* No count */
 811        MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT = 0x00,
 812        /* Count packets and bytes */
 813        MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03,
 814        /* Count only packets */
 815        MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS = 0x05,
 816};
 817
 818/* afa_polcnt_counter_set_type
 819 * Counter set type for flow counters.
 820 */
 821MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8);
 822
 823/* afa_polcnt_counter_index
 824 * Counter index for flow counters.
 825 */
 826MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24);
 827
 828static inline void
 829mlxsw_afa_polcnt_pack(char *payload,
 830                      enum mlxsw_afa_polcnt_counter_set_type set_type,
 831                      u32 counter_index)
 832{
 833        mlxsw_afa_polcnt_counter_set_type_set(payload, set_type);
 834        mlxsw_afa_polcnt_counter_index_set(payload, counter_index);
 835}
 836
 837int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block,
 838                                   u32 counter_index)
 839{
 840        char *act = mlxsw_afa_block_append_action(block,
 841                                                  MLXSW_AFA_POLCNT_CODE,
 842                                                  MLXSW_AFA_POLCNT_SIZE);
 843        if (!act)
 844                return -ENOBUFS;
 845        mlxsw_afa_polcnt_pack(act, MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES,
 846                              counter_index);
 847        return 0;
 848}
 849EXPORT_SYMBOL(mlxsw_afa_block_append_counter);
 850
 851/* Virtual Router and Forwarding Domain Action
 852 * -------------------------------------------
 853 * Virtual Switch action is used for manipulate the Virtual Router (VR),
 854 * MPLS label space and the Forwarding Identifier (FID).
 855 */
 856
 857#define MLXSW_AFA_VIRFWD_CODE 0x0E
 858#define MLXSW_AFA_VIRFWD_SIZE 1
 859
 860enum mlxsw_afa_virfwd_fid_cmd {
 861        /* Do nothing */
 862        MLXSW_AFA_VIRFWD_FID_CMD_NOOP,
 863        /* Set the Forwarding Identifier (FID) to fid */
 864        MLXSW_AFA_VIRFWD_FID_CMD_SET,
 865};
 866
 867/* afa_virfwd_fid_cmd */
 868MLXSW_ITEM32(afa, virfwd, fid_cmd, 0x08, 29, 3);
 869
 870/* afa_virfwd_fid
 871 * The FID value.
 872 */
 873MLXSW_ITEM32(afa, virfwd, fid, 0x08, 0, 16);
 874
 875static inline void mlxsw_afa_virfwd_pack(char *payload,
 876                                         enum mlxsw_afa_virfwd_fid_cmd fid_cmd,
 877                                         u16 fid)
 878{
 879        mlxsw_afa_virfwd_fid_cmd_set(payload, fid_cmd);
 880        mlxsw_afa_virfwd_fid_set(payload, fid);
 881}
 882
 883int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid)
 884{
 885        char *act = mlxsw_afa_block_append_action(block,
 886                                                  MLXSW_AFA_VIRFWD_CODE,
 887                                                  MLXSW_AFA_VIRFWD_SIZE);
 888        if (!act)
 889                return -ENOBUFS;
 890        mlxsw_afa_virfwd_pack(act, MLXSW_AFA_VIRFWD_FID_CMD_SET, fid);
 891        return 0;
 892}
 893EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set);
 894