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>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
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>
44 #include "core_acl_flex_actions.h"
46 enum mlxsw_afa_set_type
{
47 MLXSW_AFA_SET_TYPE_NEXT
,
48 MLXSW_AFA_SET_TYPE_GOTO
,
52 * Type of the record at the end of the action set.
54 MLXSW_ITEM32(afa
, set
, type
, 0xA0, 28, 4);
56 /* afa_set_next_action_set_ptr
57 * A pointer to the next action set in the KVD Centralized database.
59 MLXSW_ITEM32(afa
, set
, next_action_set_ptr
, 0xA4, 0, 24);
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.
66 MLXSW_ITEM32(afa
, set
, goto_g
, 0xA4, 29, 1);
68 enum 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,
77 /* afa_set_goto_binding_cmd */
78 MLXSW_ITEM32(afa
, set
, goto_binding_cmd
, 0xA4, 24, 3);
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.
84 MLXSW_ITEM32(afa
, set
, goto_next_binding
, 0xA4, 0, 16);
86 /* afa_all_action_type
89 MLXSW_ITEM32(afa
, all
, action_type
, 0x00, 24, 6);
92 unsigned int max_acts_per_set
;
93 const struct mlxsw_afa_ops
*ops
;
95 struct rhashtable set_ht
;
96 struct rhashtable fwd_entry_ht
;
99 #define MLXSW_AFA_SET_LEN 0xA8
101 struct mlxsw_afa_set_ht_key
{
102 char enc_actions
[MLXSW_AFA_SET_LEN
]; /* Encoded set */
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.
113 struct mlxsw_afa_set
{
114 struct rhash_head ht_node
;
115 struct mlxsw_afa_set_ht_key ht_key
;
117 bool shared
; /* Inserted in hashtable (doesn't mean that
118 * kvdl_index is valid).
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.
130 static 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,
137 struct mlxsw_afa_fwd_entry_ht_key
{
141 struct mlxsw_afa_fwd_entry
{
142 struct rhash_head ht_node
;
143 struct mlxsw_afa_fwd_entry_ht_key ht_key
;
145 unsigned int ref_count
;
148 static 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,
155 struct mlxsw_afa
*mlxsw_afa_create(unsigned int max_acts_per_set
,
156 const struct mlxsw_afa_ops
*ops
,
159 struct mlxsw_afa
*mlxsw_afa
;
162 mlxsw_afa
= kzalloc(sizeof(*mlxsw_afa
), GFP_KERNEL
);
164 return ERR_PTR(-ENOMEM
);
165 err
= rhashtable_init(&mlxsw_afa
->set_ht
, &mlxsw_afa_set_ht_params
);
167 goto err_set_rhashtable_init
;
168 err
= rhashtable_init(&mlxsw_afa
->fwd_entry_ht
,
169 &mlxsw_afa_fwd_entry_ht_params
);
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
;
177 err_fwd_entry_rhashtable_init
:
178 rhashtable_destroy(&mlxsw_afa
->set_ht
);
179 err_set_rhashtable_init
:
183 EXPORT_SYMBOL(mlxsw_afa_create
);
185 void mlxsw_afa_destroy(struct mlxsw_afa
*mlxsw_afa
)
187 rhashtable_destroy(&mlxsw_afa
->fwd_entry_ht
);
188 rhashtable_destroy(&mlxsw_afa
->set_ht
);
191 EXPORT_SYMBOL(mlxsw_afa_destroy
);
193 static void mlxsw_afa_set_goto_set(struct mlxsw_afa_set
*set
,
194 enum mlxsw_afa_set_goto_binding_cmd cmd
,
197 char *actions
= set
->ht_key
.enc_actions
;
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
);
205 static void mlxsw_afa_set_next_set(struct mlxsw_afa_set
*set
,
206 u32 next_set_kvdl_index
)
208 char *actions
= set
->ht_key
.enc_actions
;
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
);
214 static struct mlxsw_afa_set
*mlxsw_afa_set_create(bool is_first
)
216 struct mlxsw_afa_set
*set
;
218 set
= kzalloc(sizeof(*set
), GFP_KERNEL
);
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
;
228 static void mlxsw_afa_set_destroy(struct mlxsw_afa_set
*set
)
233 static int mlxsw_afa_set_share(struct mlxsw_afa
*mlxsw_afa
,
234 struct mlxsw_afa_set
*set
)
238 err
= rhashtable_insert_fast(&mlxsw_afa
->set_ht
, &set
->ht_node
,
239 mlxsw_afa_set_ht_params
);
242 err
= mlxsw_afa
->ops
->kvdl_set_add(mlxsw_afa
->ops_priv
,
244 set
->ht_key
.enc_actions
,
245 set
->ht_key
.is_first
);
247 goto err_kvdl_set_add
;
253 rhashtable_remove_fast(&mlxsw_afa
->set_ht
, &set
->ht_node
,
254 mlxsw_afa_set_ht_params
);
258 static void mlxsw_afa_set_unshare(struct mlxsw_afa
*mlxsw_afa
,
259 struct mlxsw_afa_set
*set
)
261 mlxsw_afa
->ops
->kvdl_set_del(mlxsw_afa
->ops_priv
,
263 set
->ht_key
.is_first
);
264 rhashtable_remove_fast(&mlxsw_afa
->set_ht
, &set
->ht_node
,
265 mlxsw_afa_set_ht_params
);
269 static void mlxsw_afa_set_put(struct mlxsw_afa
*mlxsw_afa
,
270 struct mlxsw_afa_set
*set
)
272 if (--set
->ref_count
)
275 mlxsw_afa_set_unshare(mlxsw_afa
, set
);
276 mlxsw_afa_set_destroy(set
);
279 static struct mlxsw_afa_set
*mlxsw_afa_set_get(struct mlxsw_afa
*mlxsw_afa
,
280 struct mlxsw_afa_set
*orig_set
)
282 struct mlxsw_afa_set
*set
;
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.
289 set
= rhashtable_lookup_fast(&mlxsw_afa
->set_ht
, &orig_set
->ht_key
,
290 mlxsw_afa_set_ht_params
);
293 mlxsw_afa_set_put(mlxsw_afa
, orig_set
);
296 err
= mlxsw_afa_set_share(mlxsw_afa
, set
);
303 /* Block structure holds a list of action sets. One action block
304 * represents one chain of actions executed upon match of a rule.
307 struct mlxsw_afa_block
{
308 struct mlxsw_afa
*afa
;
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 resource_list
; /* List of resources held by actions
318 struct mlxsw_afa_resource
{
319 struct list_head list
;
320 void (*destructor
)(struct mlxsw_afa_block
*block
,
321 struct mlxsw_afa_resource
*resource
);
324 static void mlxsw_afa_resource_add(struct mlxsw_afa_block
*block
,
325 struct mlxsw_afa_resource
*resource
)
327 list_add(&resource
->list
, &block
->resource_list
);
330 static void mlxsw_afa_resources_destroy(struct mlxsw_afa_block
*block
)
332 struct mlxsw_afa_resource
*resource
, *tmp
;
334 list_for_each_entry_safe(resource
, tmp
, &block
->resource_list
, list
) {
335 list_del(&resource
->list
);
336 resource
->destructor(block
, resource
);
340 struct mlxsw_afa_block
*mlxsw_afa_block_create(struct mlxsw_afa
*mlxsw_afa
)
342 struct mlxsw_afa_block
*block
;
344 block
= kzalloc(sizeof(*block
), GFP_KERNEL
);
347 INIT_LIST_HEAD(&block
->resource_list
);
348 block
->afa
= mlxsw_afa
;
350 /* At least one action set is always present, so just create it here */
351 block
->first_set
= mlxsw_afa_set_create(true);
352 if (!block
->first_set
)
353 goto err_first_set_create
;
354 block
->cur_set
= block
->first_set
;
357 err_first_set_create
:
361 EXPORT_SYMBOL(mlxsw_afa_block_create
);
363 void mlxsw_afa_block_destroy(struct mlxsw_afa_block
*block
)
365 struct mlxsw_afa_set
*set
= block
->first_set
;
366 struct mlxsw_afa_set
*next_set
;
369 next_set
= set
->next
;
370 mlxsw_afa_set_put(block
->afa
, set
);
373 mlxsw_afa_resources_destroy(block
);
376 EXPORT_SYMBOL(mlxsw_afa_block_destroy
);
378 int mlxsw_afa_block_commit(struct mlxsw_afa_block
*block
)
380 struct mlxsw_afa_set
*set
= block
->cur_set
;
381 struct mlxsw_afa_set
*prev_set
;
383 block
->cur_set
= NULL
;
384 block
->finished
= true;
386 /* Go over all linked sets starting from last
387 * and try to find existing set in the hash table.
388 * In case it is not there, assign a KVD linear index
392 prev_set
= set
->prev
;
393 set
= mlxsw_afa_set_get(block
->afa
, set
);
395 /* No rollback is needed since the chain is
396 * in consistent state and mlxsw_afa_block_destroy
397 * will take care of putting it away.
401 prev_set
->next
= set
;
402 mlxsw_afa_set_next_set(prev_set
, set
->kvdl_index
);
407 block
->first_set
= set
;
410 EXPORT_SYMBOL(mlxsw_afa_block_commit
);
412 char *mlxsw_afa_block_first_set(struct mlxsw_afa_block
*block
)
414 return block
->first_set
->ht_key
.enc_actions
;
416 EXPORT_SYMBOL(mlxsw_afa_block_first_set
);
418 u32
mlxsw_afa_block_first_set_kvdl_index(struct mlxsw_afa_block
*block
)
420 return block
->first_set
->kvdl_index
;
422 EXPORT_SYMBOL(mlxsw_afa_block_first_set_kvdl_index
);
424 int mlxsw_afa_block_continue(struct mlxsw_afa_block
*block
)
428 mlxsw_afa_set_goto_set(block
->cur_set
,
429 MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE
, 0);
430 block
->finished
= true;
433 EXPORT_SYMBOL(mlxsw_afa_block_continue
);
435 int mlxsw_afa_block_jump(struct mlxsw_afa_block
*block
, u16 group_id
)
439 mlxsw_afa_set_goto_set(block
->cur_set
,
440 MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP
, group_id
);
441 block
->finished
= true;
444 EXPORT_SYMBOL(mlxsw_afa_block_jump
);
446 int mlxsw_afa_block_terminate(struct mlxsw_afa_block
*block
)
450 mlxsw_afa_set_goto_set(block
->cur_set
,
451 MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM
, 0);
452 block
->finished
= true;
455 EXPORT_SYMBOL(mlxsw_afa_block_terminate
);
457 static struct mlxsw_afa_fwd_entry
*
458 mlxsw_afa_fwd_entry_create(struct mlxsw_afa
*mlxsw_afa
, u8 local_port
)
460 struct mlxsw_afa_fwd_entry
*fwd_entry
;
463 fwd_entry
= kzalloc(sizeof(*fwd_entry
), GFP_KERNEL
);
465 return ERR_PTR(-ENOMEM
);
466 fwd_entry
->ht_key
.local_port
= local_port
;
467 fwd_entry
->ref_count
= 1;
469 err
= rhashtable_insert_fast(&mlxsw_afa
->fwd_entry_ht
,
471 mlxsw_afa_fwd_entry_ht_params
);
473 goto err_rhashtable_insert
;
475 err
= mlxsw_afa
->ops
->kvdl_fwd_entry_add(mlxsw_afa
->ops_priv
,
476 &fwd_entry
->kvdl_index
,
479 goto err_kvdl_fwd_entry_add
;
482 err_kvdl_fwd_entry_add
:
483 rhashtable_remove_fast(&mlxsw_afa
->fwd_entry_ht
, &fwd_entry
->ht_node
,
484 mlxsw_afa_fwd_entry_ht_params
);
485 err_rhashtable_insert
:
490 static void mlxsw_afa_fwd_entry_destroy(struct mlxsw_afa
*mlxsw_afa
,
491 struct mlxsw_afa_fwd_entry
*fwd_entry
)
493 mlxsw_afa
->ops
->kvdl_fwd_entry_del(mlxsw_afa
->ops_priv
,
494 fwd_entry
->kvdl_index
);
495 rhashtable_remove_fast(&mlxsw_afa
->fwd_entry_ht
, &fwd_entry
->ht_node
,
496 mlxsw_afa_fwd_entry_ht_params
);
500 static struct mlxsw_afa_fwd_entry
*
501 mlxsw_afa_fwd_entry_get(struct mlxsw_afa
*mlxsw_afa
, u8 local_port
)
503 struct mlxsw_afa_fwd_entry_ht_key ht_key
= {0};
504 struct mlxsw_afa_fwd_entry
*fwd_entry
;
506 ht_key
.local_port
= local_port
;
507 fwd_entry
= rhashtable_lookup_fast(&mlxsw_afa
->fwd_entry_ht
, &ht_key
,
508 mlxsw_afa_fwd_entry_ht_params
);
510 fwd_entry
->ref_count
++;
513 return mlxsw_afa_fwd_entry_create(mlxsw_afa
, local_port
);
516 static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa
*mlxsw_afa
,
517 struct mlxsw_afa_fwd_entry
*fwd_entry
)
519 if (--fwd_entry
->ref_count
)
521 mlxsw_afa_fwd_entry_destroy(mlxsw_afa
, fwd_entry
);
524 struct mlxsw_afa_fwd_entry_ref
{
525 struct mlxsw_afa_resource resource
;
526 struct mlxsw_afa_fwd_entry
*fwd_entry
;
530 mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block
*block
,
531 struct mlxsw_afa_fwd_entry_ref
*fwd_entry_ref
)
533 mlxsw_afa_fwd_entry_put(block
->afa
, fwd_entry_ref
->fwd_entry
);
534 kfree(fwd_entry_ref
);
538 mlxsw_afa_fwd_entry_ref_destructor(struct mlxsw_afa_block
*block
,
539 struct mlxsw_afa_resource
*resource
)
541 struct mlxsw_afa_fwd_entry_ref
*fwd_entry_ref
;
543 fwd_entry_ref
= container_of(resource
, struct mlxsw_afa_fwd_entry_ref
,
545 mlxsw_afa_fwd_entry_ref_destroy(block
, fwd_entry_ref
);
548 static struct mlxsw_afa_fwd_entry_ref
*
549 mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block
*block
, u8 local_port
)
551 struct mlxsw_afa_fwd_entry_ref
*fwd_entry_ref
;
552 struct mlxsw_afa_fwd_entry
*fwd_entry
;
555 fwd_entry_ref
= kzalloc(sizeof(*fwd_entry_ref
), GFP_KERNEL
);
557 return ERR_PTR(-ENOMEM
);
558 fwd_entry
= mlxsw_afa_fwd_entry_get(block
->afa
, local_port
);
559 if (IS_ERR(fwd_entry
)) {
560 err
= PTR_ERR(fwd_entry
);
561 goto err_fwd_entry_get
;
563 fwd_entry_ref
->fwd_entry
= fwd_entry
;
564 fwd_entry_ref
->resource
.destructor
= mlxsw_afa_fwd_entry_ref_destructor
;
565 mlxsw_afa_resource_add(block
, &fwd_entry_ref
->resource
);
566 return fwd_entry_ref
;
569 kfree(fwd_entry_ref
);
573 struct mlxsw_afa_counter
{
574 struct mlxsw_afa_resource resource
;
579 mlxsw_afa_counter_destroy(struct mlxsw_afa_block
*block
,
580 struct mlxsw_afa_counter
*counter
)
582 block
->afa
->ops
->counter_index_put(block
->afa
->ops_priv
,
583 counter
->counter_index
);
588 mlxsw_afa_counter_destructor(struct mlxsw_afa_block
*block
,
589 struct mlxsw_afa_resource
*resource
)
591 struct mlxsw_afa_counter
*counter
;
593 counter
= container_of(resource
, struct mlxsw_afa_counter
, resource
);
594 mlxsw_afa_counter_destroy(block
, counter
);
597 static struct mlxsw_afa_counter
*
598 mlxsw_afa_counter_create(struct mlxsw_afa_block
*block
)
600 struct mlxsw_afa_counter
*counter
;
603 counter
= kzalloc(sizeof(*counter
), GFP_KERNEL
);
605 return ERR_PTR(-ENOMEM
);
607 err
= block
->afa
->ops
->counter_index_get(block
->afa
->ops_priv
,
608 &counter
->counter_index
);
610 goto err_counter_index_get
;
611 counter
->resource
.destructor
= mlxsw_afa_counter_destructor
;
612 mlxsw_afa_resource_add(block
, &counter
->resource
);
615 err_counter_index_get
:
620 #define MLXSW_AFA_ONE_ACTION_LEN 32
621 #define MLXSW_AFA_PAYLOAD_OFFSET 4
623 static char *mlxsw_afa_block_append_action(struct mlxsw_afa_block
*block
,
624 u8 action_code
, u8 action_size
)
629 if (WARN_ON(block
->finished
))
631 if (block
->cur_act_index
+ action_size
>
632 block
->afa
->max_acts_per_set
) {
633 struct mlxsw_afa_set
*set
;
635 /* The appended action won't fit into the current action set,
636 * so create a new set.
638 set
= mlxsw_afa_set_create(false);
641 set
->prev
= block
->cur_set
;
642 block
->cur_act_index
= 0;
643 block
->cur_set
->next
= set
;
644 block
->cur_set
= set
;
647 actions
= block
->cur_set
->ht_key
.enc_actions
;
648 oneact
= actions
+ block
->cur_act_index
* MLXSW_AFA_ONE_ACTION_LEN
;
649 block
->cur_act_index
+= action_size
;
650 mlxsw_afa_all_action_type_set(oneact
, action_code
);
651 return oneact
+ MLXSW_AFA_PAYLOAD_OFFSET
;
656 * VLAN action is used for manipulating VLANs. It can be used to implement QinQ,
657 * VLAN translation, change of PCP bits of the VLAN tag, push, pop as swap VLANs
661 #define MLXSW_AFA_VLAN_CODE 0x02
662 #define MLXSW_AFA_VLAN_SIZE 1
664 enum mlxsw_afa_vlan_vlan_tag_cmd
{
665 MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP
,
666 MLXSW_AFA_VLAN_VLAN_TAG_CMD_PUSH_TAG
,
667 MLXSW_AFA_VLAN_VLAN_TAG_CMD_POP_TAG
,
670 enum mlxsw_afa_vlan_cmd
{
671 MLXSW_AFA_VLAN_CMD_NOP
,
672 MLXSW_AFA_VLAN_CMD_SET_OUTER
,
673 MLXSW_AFA_VLAN_CMD_SET_INNER
,
674 MLXSW_AFA_VLAN_CMD_COPY_OUTER_TO_INNER
,
675 MLXSW_AFA_VLAN_CMD_COPY_INNER_TO_OUTER
,
676 MLXSW_AFA_VLAN_CMD_SWAP
,
679 /* afa_vlan_vlan_tag_cmd
680 * Tag command: push, pop, nop VLAN header.
682 MLXSW_ITEM32(afa
, vlan
, vlan_tag_cmd
, 0x00, 29, 3);
684 /* afa_vlan_vid_cmd */
685 MLXSW_ITEM32(afa
, vlan
, vid_cmd
, 0x04, 29, 3);
688 MLXSW_ITEM32(afa
, vlan
, vid
, 0x04, 0, 12);
690 /* afa_vlan_ethertype_cmd */
691 MLXSW_ITEM32(afa
, vlan
, ethertype_cmd
, 0x08, 29, 3);
693 /* afa_vlan_ethertype
694 * Index to EtherTypes in Switch VLAN EtherType Register (SVER).
696 MLXSW_ITEM32(afa
, vlan
, ethertype
, 0x08, 24, 3);
698 /* afa_vlan_pcp_cmd */
699 MLXSW_ITEM32(afa
, vlan
, pcp_cmd
, 0x08, 13, 3);
702 MLXSW_ITEM32(afa
, vlan
, pcp
, 0x08, 8, 3);
705 mlxsw_afa_vlan_pack(char *payload
,
706 enum mlxsw_afa_vlan_vlan_tag_cmd vlan_tag_cmd
,
707 enum mlxsw_afa_vlan_cmd vid_cmd
, u16 vid
,
708 enum mlxsw_afa_vlan_cmd pcp_cmd
, u8 pcp
,
709 enum mlxsw_afa_vlan_cmd ethertype_cmd
, u8 ethertype
)
711 mlxsw_afa_vlan_vlan_tag_cmd_set(payload
, vlan_tag_cmd
);
712 mlxsw_afa_vlan_vid_cmd_set(payload
, vid_cmd
);
713 mlxsw_afa_vlan_vid_set(payload
, vid
);
714 mlxsw_afa_vlan_pcp_cmd_set(payload
, pcp_cmd
);
715 mlxsw_afa_vlan_pcp_set(payload
, pcp
);
716 mlxsw_afa_vlan_ethertype_cmd_set(payload
, ethertype_cmd
);
717 mlxsw_afa_vlan_ethertype_set(payload
, ethertype
);
720 int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block
*block
,
721 u16 vid
, u8 pcp
, u8 et
)
723 char *act
= mlxsw_afa_block_append_action(block
,
725 MLXSW_AFA_VLAN_SIZE
);
729 mlxsw_afa_vlan_pack(act
, MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP
,
730 MLXSW_AFA_VLAN_CMD_SET_OUTER
, vid
,
731 MLXSW_AFA_VLAN_CMD_SET_OUTER
, pcp
,
732 MLXSW_AFA_VLAN_CMD_SET_OUTER
, et
);
735 EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify
);
737 /* Trap / Discard Action
738 * ---------------------
739 * The Trap / Discard action enables trapping / mirroring packets to the CPU
740 * as well as discarding packets.
741 * The ACL Trap / Discard separates the forward/discard control from CPU
742 * trap control. In addition, the Trap / Discard action enables activating
743 * SPAN (port mirroring).
746 #define MLXSW_AFA_TRAPDISC_CODE 0x03
747 #define MLXSW_AFA_TRAPDISC_SIZE 1
749 enum mlxsw_afa_trapdisc_trap_action
{
750 MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP
= 0,
751 MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP
= 2,
754 /* afa_trapdisc_trap_action
757 MLXSW_ITEM32(afa
, trapdisc
, trap_action
, 0x00, 24, 4);
759 enum mlxsw_afa_trapdisc_forward_action
{
760 MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD
= 1,
761 MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD
= 3,
764 /* afa_trapdisc_forward_action
767 MLXSW_ITEM32(afa
, trapdisc
, forward_action
, 0x00, 0, 4);
769 /* afa_trapdisc_trap_id
770 * Trap ID to configure.
772 MLXSW_ITEM32(afa
, trapdisc
, trap_id
, 0x04, 0, 9);
774 /* afa_trapdisc_mirror_agent
777 MLXSW_ITEM32(afa
, trapdisc
, mirror_agent
, 0x08, 29, 3);
779 /* afa_trapdisc_mirror_enable
782 MLXSW_ITEM32(afa
, trapdisc
, mirror_enable
, 0x08, 24, 1);
785 mlxsw_afa_trapdisc_pack(char *payload
,
786 enum mlxsw_afa_trapdisc_trap_action trap_action
,
787 enum mlxsw_afa_trapdisc_forward_action forward_action
,
790 mlxsw_afa_trapdisc_trap_action_set(payload
, trap_action
);
791 mlxsw_afa_trapdisc_forward_action_set(payload
, forward_action
);
792 mlxsw_afa_trapdisc_trap_id_set(payload
, trap_id
);
796 mlxsw_afa_trapdisc_mirror_pack(char *payload
, bool mirror_enable
,
799 mlxsw_afa_trapdisc_mirror_enable_set(payload
, mirror_enable
);
800 mlxsw_afa_trapdisc_mirror_agent_set(payload
, mirror_agent
);
803 int mlxsw_afa_block_append_drop(struct mlxsw_afa_block
*block
)
805 char *act
= mlxsw_afa_block_append_action(block
,
806 MLXSW_AFA_TRAPDISC_CODE
,
807 MLXSW_AFA_TRAPDISC_SIZE
);
811 mlxsw_afa_trapdisc_pack(act
, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP
,
812 MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD
, 0);
815 EXPORT_SYMBOL(mlxsw_afa_block_append_drop
);
817 int mlxsw_afa_block_append_trap(struct mlxsw_afa_block
*block
, u16 trap_id
)
819 char *act
= mlxsw_afa_block_append_action(block
,
820 MLXSW_AFA_TRAPDISC_CODE
,
821 MLXSW_AFA_TRAPDISC_SIZE
);
825 mlxsw_afa_trapdisc_pack(act
, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP
,
826 MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD
,
830 EXPORT_SYMBOL(mlxsw_afa_block_append_trap
);
832 int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block
*block
,
835 char *act
= mlxsw_afa_block_append_action(block
,
836 MLXSW_AFA_TRAPDISC_CODE
,
837 MLXSW_AFA_TRAPDISC_SIZE
);
841 mlxsw_afa_trapdisc_pack(act
, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP
,
842 MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD
,
846 EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward
);
848 struct mlxsw_afa_mirror
{
849 struct mlxsw_afa_resource resource
;
857 mlxsw_afa_mirror_destroy(struct mlxsw_afa_block
*block
,
858 struct mlxsw_afa_mirror
*mirror
)
860 block
->afa
->ops
->mirror_del(block
->afa
->ops_priv
,
861 mirror
->local_in_port
,
862 mirror
->local_out_port
,
868 mlxsw_afa_mirror_destructor(struct mlxsw_afa_block
*block
,
869 struct mlxsw_afa_resource
*resource
)
871 struct mlxsw_afa_mirror
*mirror
;
873 mirror
= container_of(resource
, struct mlxsw_afa_mirror
, resource
);
874 mlxsw_afa_mirror_destroy(block
, mirror
);
877 static struct mlxsw_afa_mirror
*
878 mlxsw_afa_mirror_create(struct mlxsw_afa_block
*block
,
879 u8 local_in_port
, u8 local_out_port
,
882 struct mlxsw_afa_mirror
*mirror
;
885 mirror
= kzalloc(sizeof(*mirror
), GFP_KERNEL
);
887 return ERR_PTR(-ENOMEM
);
889 err
= block
->afa
->ops
->mirror_add(block
->afa
->ops_priv
,
890 local_in_port
, local_out_port
,
891 ingress
, &mirror
->span_id
);
895 mirror
->ingress
= ingress
;
896 mirror
->local_out_port
= local_out_port
;
897 mirror
->local_in_port
= local_in_port
;
898 mirror
->resource
.destructor
= mlxsw_afa_mirror_destructor
;
899 mlxsw_afa_resource_add(block
, &mirror
->resource
);
908 mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block
*block
,
911 char *act
= mlxsw_afa_block_append_action(block
,
912 MLXSW_AFA_TRAPDISC_CODE
,
913 MLXSW_AFA_TRAPDISC_SIZE
);
916 mlxsw_afa_trapdisc_pack(act
, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP
,
917 MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD
, 0);
918 mlxsw_afa_trapdisc_mirror_pack(act
, true, mirror_agent
);
923 mlxsw_afa_block_append_mirror(struct mlxsw_afa_block
*block
,
924 u8 local_in_port
, u8 local_out_port
, bool ingress
)
926 struct mlxsw_afa_mirror
*mirror
;
929 mirror
= mlxsw_afa_mirror_create(block
, local_in_port
, local_out_port
,
932 return PTR_ERR(mirror
);
934 err
= mlxsw_afa_block_append_allocated_mirror(block
, mirror
->span_id
);
936 goto err_append_allocated_mirror
;
940 err_append_allocated_mirror
:
941 mlxsw_afa_mirror_destroy(block
, mirror
);
944 EXPORT_SYMBOL(mlxsw_afa_block_append_mirror
);
948 * Forwarding Action can be used to implement Policy Based Switching (PBS)
949 * as well as OpenFlow related "Output" action.
952 #define MLXSW_AFA_FORWARD_CODE 0x07
953 #define MLXSW_AFA_FORWARD_SIZE 1
955 enum mlxsw_afa_forward_type
{
956 /* PBS, Policy Based Switching */
957 MLXSW_AFA_FORWARD_TYPE_PBS
,
958 /* Output, OpenFlow output type */
959 MLXSW_AFA_FORWARD_TYPE_OUTPUT
,
962 /* afa_forward_type */
963 MLXSW_ITEM32(afa
, forward
, type
, 0x00, 24, 2);
965 /* afa_forward_pbs_ptr
966 * A pointer to the PBS entry configured by PPBS register.
967 * Reserved when in_port is set.
969 MLXSW_ITEM32(afa
, forward
, pbs_ptr
, 0x08, 0, 24);
971 /* afa_forward_in_port
972 * Packet is forwarded back to the ingress port.
974 MLXSW_ITEM32(afa
, forward
, in_port
, 0x0C, 0, 1);
977 mlxsw_afa_forward_pack(char *payload
, enum mlxsw_afa_forward_type type
,
978 u32 pbs_ptr
, bool in_port
)
980 mlxsw_afa_forward_type_set(payload
, type
);
981 mlxsw_afa_forward_pbs_ptr_set(payload
, pbs_ptr
);
982 mlxsw_afa_forward_in_port_set(payload
, in_port
);
985 int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block
*block
,
986 u8 local_port
, bool in_port
)
988 struct mlxsw_afa_fwd_entry_ref
*fwd_entry_ref
;
995 fwd_entry_ref
= mlxsw_afa_fwd_entry_ref_create(block
, local_port
);
996 if (IS_ERR(fwd_entry_ref
))
997 return PTR_ERR(fwd_entry_ref
);
998 kvdl_index
= fwd_entry_ref
->fwd_entry
->kvdl_index
;
1000 act
= mlxsw_afa_block_append_action(block
, MLXSW_AFA_FORWARD_CODE
,
1001 MLXSW_AFA_FORWARD_SIZE
);
1004 goto err_append_action
;
1006 mlxsw_afa_forward_pack(act
, MLXSW_AFA_FORWARD_TYPE_PBS
,
1007 kvdl_index
, in_port
);
1011 mlxsw_afa_fwd_entry_ref_destroy(block
, fwd_entry_ref
);
1014 EXPORT_SYMBOL(mlxsw_afa_block_append_fwd
);
1016 /* Policing and Counting Action
1017 * ----------------------------
1018 * Policing and Counting action is used for binding policer and counter
1022 #define MLXSW_AFA_POLCNT_CODE 0x08
1023 #define MLXSW_AFA_POLCNT_SIZE 1
1025 enum mlxsw_afa_polcnt_counter_set_type
{
1027 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT
= 0x00,
1028 /* Count packets and bytes */
1029 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES
= 0x03,
1030 /* Count only packets */
1031 MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS
= 0x05,
1034 /* afa_polcnt_counter_set_type
1035 * Counter set type for flow counters.
1037 MLXSW_ITEM32(afa
, polcnt
, counter_set_type
, 0x04, 24, 8);
1039 /* afa_polcnt_counter_index
1040 * Counter index for flow counters.
1042 MLXSW_ITEM32(afa
, polcnt
, counter_index
, 0x04, 0, 24);
1045 mlxsw_afa_polcnt_pack(char *payload
,
1046 enum mlxsw_afa_polcnt_counter_set_type set_type
,
1049 mlxsw_afa_polcnt_counter_set_type_set(payload
, set_type
);
1050 mlxsw_afa_polcnt_counter_index_set(payload
, counter_index
);
1053 int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block
*block
,
1056 char *act
= mlxsw_afa_block_append_action(block
, MLXSW_AFA_POLCNT_CODE
,
1057 MLXSW_AFA_POLCNT_SIZE
);
1060 mlxsw_afa_polcnt_pack(act
, MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES
,
1064 EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter
);
1066 int mlxsw_afa_block_append_counter(struct mlxsw_afa_block
*block
,
1067 u32
*p_counter_index
)
1069 struct mlxsw_afa_counter
*counter
;
1073 counter
= mlxsw_afa_counter_create(block
);
1074 if (IS_ERR(counter
))
1075 return PTR_ERR(counter
);
1076 counter_index
= counter
->counter_index
;
1078 err
= mlxsw_afa_block_append_allocated_counter(block
, counter_index
);
1080 goto err_append_allocated_counter
;
1082 if (p_counter_index
)
1083 *p_counter_index
= counter_index
;
1086 err_append_allocated_counter
:
1087 mlxsw_afa_counter_destroy(block
, counter
);
1090 EXPORT_SYMBOL(mlxsw_afa_block_append_counter
);
1092 /* Virtual Router and Forwarding Domain Action
1093 * -------------------------------------------
1094 * Virtual Switch action is used for manipulate the Virtual Router (VR),
1095 * MPLS label space and the Forwarding Identifier (FID).
1098 #define MLXSW_AFA_VIRFWD_CODE 0x0E
1099 #define MLXSW_AFA_VIRFWD_SIZE 1
1101 enum mlxsw_afa_virfwd_fid_cmd
{
1103 MLXSW_AFA_VIRFWD_FID_CMD_NOOP
,
1104 /* Set the Forwarding Identifier (FID) to fid */
1105 MLXSW_AFA_VIRFWD_FID_CMD_SET
,
1108 /* afa_virfwd_fid_cmd */
1109 MLXSW_ITEM32(afa
, virfwd
, fid_cmd
, 0x08, 29, 3);
1114 MLXSW_ITEM32(afa
, virfwd
, fid
, 0x08, 0, 16);
1116 static inline void mlxsw_afa_virfwd_pack(char *payload
,
1117 enum mlxsw_afa_virfwd_fid_cmd fid_cmd
,
1120 mlxsw_afa_virfwd_fid_cmd_set(payload
, fid_cmd
);
1121 mlxsw_afa_virfwd_fid_set(payload
, fid
);
1124 int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block
*block
, u16 fid
)
1126 char *act
= mlxsw_afa_block_append_action(block
,
1127 MLXSW_AFA_VIRFWD_CODE
,
1128 MLXSW_AFA_VIRFWD_SIZE
);
1131 mlxsw_afa_virfwd_pack(act
, MLXSW_AFA_VIRFWD_FID_CMD_SET
, fid
);
1134 EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set
);
1136 /* MC Routing Action
1138 * The Multicast router action. Can be used by RMFT_V2 - Router Multicast
1139 * Forwarding Table Version 2 Register.
1142 #define MLXSW_AFA_MCROUTER_CODE 0x10
1143 #define MLXSW_AFA_MCROUTER_SIZE 2
1145 enum mlxsw_afa_mcrouter_rpf_action
{
1146 MLXSW_AFA_MCROUTER_RPF_ACTION_NOP
,
1147 MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP
,
1148 MLXSW_AFA_MCROUTER_RPF_ACTION_DISCARD_ERROR
,
1151 /* afa_mcrouter_rpf_action */
1152 MLXSW_ITEM32(afa
, mcrouter
, rpf_action
, 0x00, 28, 3);
1154 /* afa_mcrouter_expected_irif */
1155 MLXSW_ITEM32(afa
, mcrouter
, expected_irif
, 0x00, 0, 16);
1157 /* afa_mcrouter_min_mtu */
1158 MLXSW_ITEM32(afa
, mcrouter
, min_mtu
, 0x08, 0, 16);
1160 enum mlxsw_afa_mrouter_vrmid
{
1161 MLXSW_AFA_MCROUTER_VRMID_INVALID
,
1162 MLXSW_AFA_MCROUTER_VRMID_VALID
1165 /* afa_mcrouter_vrmid
1166 * Valid RMID: rigr_rmid_index is used as RMID
1168 MLXSW_ITEM32(afa
, mcrouter
, vrmid
, 0x0C, 31, 1);
1170 /* afa_mcrouter_rigr_rmid_index
1171 * When the vrmid field is set to invalid, the field is used as pointer to
1172 * Router Interface Group (RIGR) Table in the KVD linear.
1173 * When the vrmid is set to valid, the field is used as RMID index, ranged
1174 * from 0 to max_mid - 1. The index is to the Port Group Table.
1176 MLXSW_ITEM32(afa
, mcrouter
, rigr_rmid_index
, 0x0C, 0, 24);
1179 mlxsw_afa_mcrouter_pack(char *payload
,
1180 enum mlxsw_afa_mcrouter_rpf_action rpf_action
,
1181 u16 expected_irif
, u16 min_mtu
,
1182 enum mlxsw_afa_mrouter_vrmid vrmid
, u32 rigr_rmid_index
)
1185 mlxsw_afa_mcrouter_rpf_action_set(payload
, rpf_action
);
1186 mlxsw_afa_mcrouter_expected_irif_set(payload
, expected_irif
);
1187 mlxsw_afa_mcrouter_min_mtu_set(payload
, min_mtu
);
1188 mlxsw_afa_mcrouter_vrmid_set(payload
, vrmid
);
1189 mlxsw_afa_mcrouter_rigr_rmid_index_set(payload
, rigr_rmid_index
);
1192 int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block
*block
,
1193 u16 expected_irif
, u16 min_mtu
,
1194 bool rmid_valid
, u32 kvdl_index
)
1196 char *act
= mlxsw_afa_block_append_action(block
,
1197 MLXSW_AFA_MCROUTER_CODE
,
1198 MLXSW_AFA_MCROUTER_SIZE
);
1201 mlxsw_afa_mcrouter_pack(act
, MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP
,
1202 expected_irif
, min_mtu
, rmid_valid
, kvdl_index
);
1205 EXPORT_SYMBOL(mlxsw_afa_block_append_mcrouter
);