Commit 4e86889b authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-ERP-sharing-multiple-masks'

Ido Schimmel says:

====================
mlxsw: spectrum: acl: Introduce ERP sharing by multiple masks

Jiri says:

The Spectrum-2 hardware has limitation number of ERPs per-region. In
order to accommodate more masks than number of ERPs, the hardware
supports to insert rules with delta bits. By that, the rules with masks
that differ in up-to 8 consecutive bits can share the same ERP.

Patches 1 and 2 fix couple of issues that would appear in existing
selftests after adding delta support

Patch 3 introduces a generic object aggregation library. Now it is
static, but it will get extended for recalculation of aggregations in
the future in order to reach more optimal aggregation.

Patch 4 just simply converts existing ERP code to use the objagg library
instead of a rhashtable.

Patches 5-9 do more or less small changes to prepare ground for the last
patch.

Patch 10 fills-up delta callbacks of objagg library and utilizes the
delta bits for rule insertion.

The last patch adds selftest to test the mlxsw Spectrum-2 delta flows.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6ab6dfa6 3b423271
......@@ -10679,6 +10679,14 @@ L: linux-nfc@lists.01.org (moderated for non-subscribers)
S: Supported
F: drivers/nfc/nxp-nci
OBJAGG
M: Jiri Pirko <jiri@mellanox.com>
L: netdev@vger.kernel.org
S: Supported
F: lib/objagg.c
F: lib/test_objagg.c
F: include/linux/objagg.h
OBJTOOL
M: Josh Poimboeuf <jpoimboe@redhat.com>
M: Peter Zijlstra <peterz@infradead.org>
......
......@@ -80,6 +80,7 @@ config MLXSW_SPECTRUM
depends on IPV6_GRE || IPV6_GRE=n
select GENERIC_ALLOCATOR
select PARMAN
select OBJAGG
select MLXFW
default m
---help---
......
......@@ -426,15 +426,17 @@ mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst,
void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
struct mlxsw_afk_key_info *key_info,
struct mlxsw_afk_element_values *values,
char *key, char *mask, int block_start, int block_end)
char *key, char *mask)
{
unsigned int blocks_count =
mlxsw_afk_key_info_blocks_count_get(key_info);
char block_mask[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE];
char block_key[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE];
const struct mlxsw_afk_element_inst *elinst;
enum mlxsw_afk_element element;
int block_index, i;
for (i = block_start; i <= block_end; i++) {
for (i = 0; i < blocks_count; i++) {
memset(block_key, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE);
memset(block_mask, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE);
......@@ -451,10 +453,18 @@ void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
values->storage.mask);
}
if (key)
mlxsw_afk->ops->encode_block(block_key, i, key);
if (mask)
mlxsw_afk->ops->encode_block(block_mask, i, mask);
mlxsw_afk->ops->encode_block(key, i, block_key);
mlxsw_afk->ops->encode_block(mask, i, block_mask);
}
}
EXPORT_SYMBOL(mlxsw_afk_encode);
void mlxsw_afk_clear(struct mlxsw_afk *mlxsw_afk, char *key,
int block_start, int block_end)
{
int i;
for (i = block_start; i <= block_end; i++)
mlxsw_afk->ops->clear_block(key, i);
}
EXPORT_SYMBOL(mlxsw_afk_clear);
......@@ -188,7 +188,8 @@ struct mlxsw_afk;
struct mlxsw_afk_ops {
const struct mlxsw_afk_block *blocks;
unsigned int blocks_count;
void (*encode_block)(char *block, int block_index, char *output);
void (*encode_block)(char *output, int block_index, char *block);
void (*clear_block)(char *output, int block_index);
};
struct mlxsw_afk *mlxsw_afk_create(unsigned int max_blocks,
......@@ -228,6 +229,8 @@ void mlxsw_afk_values_add_buf(struct mlxsw_afk_element_values *values,
void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
struct mlxsw_afk_key_info *key_info,
struct mlxsw_afk_element_values *values,
char *key, char *mask, int block_start, int block_end);
char *key, char *mask);
void mlxsw_afk_clear(struct mlxsw_afk *mlxsw_afk, char *key,
int block_start, int block_end);
#endif
......@@ -2834,8 +2834,9 @@ static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid,
u32 priority,
const char *tcam_region_info,
const char *key, u8 erp_id,
bool large_exists, u32 lkey_id,
u32 action_pointer)
u16 delta_start, u8 delta_mask,
u8 delta_value, bool large_exists,
u32 lkey_id, u32 action_pointer)
{
MLXSW_REG_ZERO(ptce3, payload);
mlxsw_reg_ptce3_v_set(payload, valid);
......@@ -2844,6 +2845,9 @@ static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid,
mlxsw_reg_ptce3_tcam_region_info_memcpy_to(payload, tcam_region_info);
mlxsw_reg_ptce3_flex2_key_blocks_memcpy_to(payload, key);
mlxsw_reg_ptce3_erp_id_set(payload, erp_id);
mlxsw_reg_ptce3_delta_start_set(payload, delta_start);
mlxsw_reg_ptce3_delta_mask_set(payload, delta_mask);
mlxsw_reg_ptce3_delta_value_set(payload, delta_value);
mlxsw_reg_ptce3_large_exists_set(payload, large_exists);
mlxsw_reg_ptce3_large_entry_key_id_set(payload, lkey_id);
mlxsw_reg_ptce3_action_pointer_set(payload, action_pointer);
......
......@@ -34,15 +34,15 @@ mlxsw_sp2_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregio
{
struct mlxsw_sp_acl_atcam_region *aregion;
struct mlxsw_sp_acl_atcam_entry *aentry;
struct mlxsw_sp_acl_erp *erp;
struct mlxsw_sp_acl_erp_mask *erp_mask;
aregion = mlxsw_sp_acl_tcam_cregion_aregion(cregion);
aentry = mlxsw_sp_acl_tcam_centry_aentry(centry);
erp = mlxsw_sp_acl_erp_get(aregion, mask, true);
if (IS_ERR(erp))
return PTR_ERR(erp);
aentry->erp = erp;
erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, true);
if (IS_ERR(erp_mask))
return PTR_ERR(erp_mask);
aentry->erp_mask = erp_mask;
return 0;
}
......@@ -57,7 +57,7 @@ mlxsw_sp2_acl_ctcam_region_entry_remove(struct mlxsw_sp_acl_ctcam_region *cregio
aregion = mlxsw_sp_acl_tcam_cregion_aregion(cregion);
aentry = mlxsw_sp_acl_tcam_centry_aentry(centry);
mlxsw_sp_acl_erp_put(aregion, aentry->erp);
mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask);
}
static const struct mlxsw_sp_acl_ctcam_region_ops
......
......@@ -14,8 +14,8 @@
#include "spectrum_acl_tcam.h"
#include "core_acl_flex_keys.h"
#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_START 6
#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_END 11
#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START 0
#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END 5
struct mlxsw_sp_acl_atcam_lkey_id_ht_key {
char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* MSB blocks */
......@@ -34,7 +34,7 @@ struct mlxsw_sp_acl_atcam_region_ops {
void (*fini)(struct mlxsw_sp_acl_atcam_region *aregion);
struct mlxsw_sp_acl_atcam_lkey_id *
(*lkey_id_get)(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_rule_info *rulei, u8 erp_id);
char *enc_key, u8 erp_id);
void (*lkey_id_put)(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_atcam_lkey_id *lkey_id);
};
......@@ -64,7 +64,7 @@ static const struct rhashtable_params mlxsw_sp_acl_atcam_entries_ht_params = {
static bool
mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry *aentry)
{
return mlxsw_sp_acl_erp_is_ctcam_erp(aentry->erp);
return mlxsw_sp_acl_erp_mask_is_ctcam(aentry->erp_mask);
}
static int
......@@ -90,8 +90,7 @@ mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region *aregion
static struct mlxsw_sp_acl_atcam_lkey_id *
mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_rule_info *rulei,
u8 erp_id)
char *enc_key, u8 erp_id)
{
struct mlxsw_sp_acl_atcam_region_generic *region_generic;
......@@ -220,8 +219,7 @@ mlxsw_sp_acl_atcam_lkey_id_destroy(struct mlxsw_sp_acl_atcam_region *aregion,
static struct mlxsw_sp_acl_atcam_lkey_id *
mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_rule_info *rulei,
u8 erp_id)
char *enc_key, u8 erp_id)
{
struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
struct mlxsw_sp_acl_tcam_region *region = aregion->region;
......@@ -230,9 +228,10 @@ mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
mlxsw_afk_encode(afk, region->key_info, &rulei->values, ht_key.enc_key,
NULL, MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_START,
MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_END);
memcpy(ht_key.enc_key, enc_key, sizeof(ht_key.enc_key));
mlxsw_afk_clear(afk, ht_key.enc_key,
MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START,
MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END);
ht_key.erp_id = erp_id;
lkey_id = rhashtable_lookup_fast(&region_12kb->lkey_ht, &ht_key,
mlxsw_sp_acl_atcam_lkey_id_ht_params);
......@@ -379,7 +378,7 @@ mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei)
{
struct mlxsw_sp_acl_tcam_region *region = aregion->region;
u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp);
u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
char ptce3_pl[MLXSW_REG_PTCE3_LEN];
u32 kvdl_index, priority;
......@@ -389,7 +388,8 @@ mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
if (err)
return err;
lkey_id = aregion->ops->lkey_id_get(aregion, rulei, erp_id);
lkey_id = aregion->ops->lkey_id_get(aregion, aentry->ht_key.enc_key,
erp_id);
if (IS_ERR(lkey_id))
return PTR_ERR(lkey_id);
aentry->lkey_id = lkey_id;
......@@ -398,6 +398,9 @@ mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE,
priority, region->tcam_region_info,
aentry->ht_key.enc_key, erp_id,
aentry->delta_info.start,
aentry->delta_info.mask,
aentry->delta_info.value,
refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
kvdl_index);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
......@@ -418,12 +421,17 @@ mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
{
struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
struct mlxsw_sp_acl_tcam_region *region = aregion->region;
u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp);
u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
char *enc_key = aentry->ht_key.enc_key;
char ptce3_pl[MLXSW_REG_PTCE3_LEN];
mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0,
region->tcam_region_info, aentry->ht_key.enc_key,
erp_id, refcount_read(&lkey_id->refcnt) != 1,
region->tcam_region_info,
enc_key, erp_id,
aentry->delta_info.start,
aentry->delta_info.mask,
aentry->delta_info.value,
refcount_read(&lkey_id->refcnt) != 1,
lkey_id->id, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
aregion->ops->lkey_id_put(aregion, lkey_id);
......@@ -438,19 +446,30 @@ __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam_region *region = aregion->region;
char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
struct mlxsw_sp_acl_erp *erp;
unsigned int blocks_count;
const struct mlxsw_sp_acl_erp_delta *delta;
struct mlxsw_sp_acl_erp_mask *erp_mask;
int err;
blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info);
mlxsw_afk_encode(afk, region->key_info, &rulei->values,
aentry->ht_key.enc_key, mask, 0, blocks_count - 1);
erp = mlxsw_sp_acl_erp_get(aregion, mask, false);
if (IS_ERR(erp))
return PTR_ERR(erp);
aentry->erp = erp;
aentry->ht_key.erp_id = mlxsw_sp_acl_erp_id(erp);
aentry->full_enc_key, mask);
erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, false);
if (IS_ERR(erp_mask))
return PTR_ERR(erp_mask);
aentry->erp_mask = erp_mask;
aentry->ht_key.erp_id = mlxsw_sp_acl_erp_mask_erp_id(erp_mask);
memcpy(aentry->ht_key.enc_key, aentry->full_enc_key,
sizeof(aentry->ht_key.enc_key));
/* Compute all needed delta information and clear the delta bits
* from the encrypted key.
*/
delta = mlxsw_sp_acl_erp_delta(aentry->erp_mask);
aentry->delta_info.start = mlxsw_sp_acl_erp_delta_start(delta);
aentry->delta_info.mask = mlxsw_sp_acl_erp_delta_mask(delta);
aentry->delta_info.value =
mlxsw_sp_acl_erp_delta_value(delta, aentry->full_enc_key);
mlxsw_sp_acl_erp_delta_clear(delta, aentry->ht_key.enc_key);
/* We can't insert identical rules into the A-TCAM, so fail and
* let the rule spill into C-TCAM
......@@ -472,7 +491,7 @@ __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
mlxsw_sp_acl_atcam_entries_ht_params);
err_rhashtable_insert:
mlxsw_sp_acl_erp_put(aregion, erp);
mlxsw_sp_acl_erp_mask_put(aregion, erp_mask);
return err;
}
......@@ -484,7 +503,7 @@ __mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry);
rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
mlxsw_sp_acl_atcam_entries_ht_params);
mlxsw_sp_acl_erp_put(aregion, aentry->erp);
mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask);
}
int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
......
......@@ -46,7 +46,6 @@ mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam_region *region = cregion->region;
struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
char ptce2_pl[MLXSW_REG_PTCE2_LEN];
unsigned int blocks_count;
char *act_set;
u32 priority;
char *mask;
......@@ -63,9 +62,7 @@ mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
centry->parman_item.index, priority);
key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl);
mask = mlxsw_reg_ptce2_mask_data(ptce2_pl);
blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info);
mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask, 0,
blocks_count - 1);
mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask);
err = cregion->ops->entry_insert(cregion, centry, mask);
if (err)
......
......@@ -98,8 +98,8 @@ static const struct mlxsw_afk_block mlxsw_sp1_afk_blocks[] = {
#define MLXSW_SP1_AFK_KEY_BLOCK_SIZE 16
static void mlxsw_sp1_afk_encode_block(char *block, int block_index,
char *output)
static void mlxsw_sp1_afk_encode_block(char *output, int block_index,
char *block)
{
unsigned int offset = block_index * MLXSW_SP1_AFK_KEY_BLOCK_SIZE;
char *output_indexed = output + offset;
......@@ -107,10 +107,19 @@ static void mlxsw_sp1_afk_encode_block(char *block, int block_index,
memcpy(output_indexed, block, MLXSW_SP1_AFK_KEY_BLOCK_SIZE);
}
static void mlxsw_sp1_afk_clear_block(char *output, int block_index)
{
unsigned int offset = block_index * MLXSW_SP1_AFK_KEY_BLOCK_SIZE;
char *output_indexed = output + offset;
memset(output_indexed, 0, MLXSW_SP1_AFK_KEY_BLOCK_SIZE);
}
const struct mlxsw_afk_ops mlxsw_sp1_afk_ops = {
.blocks = mlxsw_sp1_afk_blocks,
.blocks_count = ARRAY_SIZE(mlxsw_sp1_afk_blocks),
.encode_block = mlxsw_sp1_afk_encode_block,
.clear_block = mlxsw_sp1_afk_clear_block,
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = {
......@@ -263,10 +272,9 @@ static const struct mlxsw_sp2_afk_block_layout mlxsw_sp2_afk_blocks_layout[] = {
MLXSW_SP2_AFK_BLOCK_LAYOUT(block11, 0x00, 12),
};
static void mlxsw_sp2_afk_encode_block(char *block, int block_index,
char *output)
static void __mlxsw_sp2_afk_block_value_set(char *output, int block_index,
u64 block_value)
{
u64 block_value = mlxsw_sp2_afk_block_value_get(block);
const struct mlxsw_sp2_afk_block_layout *block_layout;
if (WARN_ON(block_index < 0 ||
......@@ -278,8 +286,22 @@ static void mlxsw_sp2_afk_encode_block(char *block, int block_index,
&block_layout->item, 0, block_value);
}
static void mlxsw_sp2_afk_encode_block(char *output, int block_index,
char *block)
{
u64 block_value = mlxsw_sp2_afk_block_value_get(block);
__mlxsw_sp2_afk_block_value_set(output, block_index, block_value);
}
static void mlxsw_sp2_afk_clear_block(char *output, int block_index)
{
__mlxsw_sp2_afk_block_value_set(output, block_index, 0);
}
const struct mlxsw_afk_ops mlxsw_sp2_afk_ops = {
.blocks = mlxsw_sp2_afk_blocks,
.blocks_count = ARRAY_SIZE(mlxsw_sp2_afk_blocks),
.encode_block = mlxsw_sp2_afk_encode_block,
.clear_block = mlxsw_sp2_afk_clear_block,
};
......@@ -154,7 +154,9 @@ struct mlxsw_sp_acl_atcam_region {
};
struct mlxsw_sp_acl_atcam_entry_ht_key {
char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* Encoded key */
char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* Encoded key,
* minus delta bits.
*/
u8 erp_id;
};
......@@ -165,9 +167,15 @@ struct mlxsw_sp_acl_atcam_chunk {
struct mlxsw_sp_acl_atcam_entry {
struct rhash_head ht_node;
struct mlxsw_sp_acl_atcam_entry_ht_key ht_key;
char full_enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* Encoded key */
struct {
u16 start;
u8 mask;
u8 value;
} delta_info;
struct mlxsw_sp_acl_ctcam_entry centry;
struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
struct mlxsw_sp_acl_erp *erp;
struct mlxsw_sp_acl_erp_mask *erp_mask;
};
static inline struct mlxsw_sp_acl_atcam_region *
......@@ -209,15 +217,27 @@ int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam *atcam);
struct mlxsw_sp_acl_erp;
struct mlxsw_sp_acl_erp_delta;
bool mlxsw_sp_acl_erp_is_ctcam_erp(const struct mlxsw_sp_acl_erp *erp);
u8 mlxsw_sp_acl_erp_id(const struct mlxsw_sp_acl_erp *erp);
struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_get(struct mlxsw_sp_acl_atcam_region *aregion,
u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta);
u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta);
u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
const char *enc_key);
void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
const char *enc_key);
struct mlxsw_sp_acl_erp_mask;
bool
mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask);
u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask);
const struct mlxsw_sp_acl_erp_delta *
mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask);
struct mlxsw_sp_acl_erp_mask *
mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
const char *mask, bool ctcam);
void mlxsw_sp_acl_erp_put(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_erp *erp);
void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_erp_mask *erp_mask);
int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion);
void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion);
int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
......
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
#ifndef _OBJAGG_H
#define _OBJAGG_H
struct objagg_ops {
size_t obj_size;
void * (*delta_create)(void *priv, void *parent_obj, void *obj);
void (*delta_destroy)(void *priv, void *delta_priv);
void * (*root_create)(void *priv, void *obj);
void (*root_destroy)(void *priv, void *root_priv);
};
struct objagg;
struct objagg_obj;
const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj);
const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj);
const void *objagg_obj_raw(const struct objagg_obj *objagg_obj);
struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj);
void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj);
struct objagg *objagg_create(const struct objagg_ops *ops, void *priv);
void objagg_destroy(struct objagg *objagg);
struct objagg_obj_stats {
unsigned int user_count;
unsigned int delta_user_count; /* includes delta object users */
};
struct objagg_obj_stats_info {
struct objagg_obj_stats stats;
struct objagg_obj *objagg_obj; /* associated object */
bool is_root;
};
struct objagg_stats {
unsigned int stats_info_count;
struct objagg_obj_stats_info stats_info[];
};
const struct objagg_stats *objagg_stats_get(struct objagg *objagg);
void objagg_stats_put(const struct objagg_stats *objagg_stats);
#endif
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM objagg
#if !defined(__TRACE_OBJAGG_H) || defined(TRACE_HEADER_MULTI_READ)
#define __TRACE_OBJAGG_H
#include <linux/tracepoint.h>
struct objagg;
struct objagg_obj;
TRACE_EVENT(objagg_create,
TP_PROTO(const struct objagg *objagg),
TP_ARGS(objagg),
TP_STRUCT__entry(
__field(const void *, objagg)
),
TP_fast_assign(
__entry->objagg = objagg;
),
TP_printk("objagg %p", __entry->objagg)
);
TRACE_EVENT(objagg_destroy,
TP_PROTO(const struct objagg *objagg),
TP_ARGS(objagg),
TP_STRUCT__entry(
__field(const void *, objagg)
),
TP_fast_assign(
__entry->objagg = objagg;
),
TP_printk("objagg %p", __entry->objagg)
);
TRACE_EVENT(objagg_obj_create,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj),
TP_ARGS(objagg, obj),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
),
TP_printk("objagg %p, obj %p", __entry->objagg, __entry->obj)
);
TRACE_EVENT(objagg_obj_destroy,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj),
TP_ARGS(objagg, obj),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
),
TP_printk("objagg %p, obj %p", __entry->objagg, __entry->obj)
);
TRACE_EVENT(objagg_obj_get,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj,
unsigned int refcount),
TP_ARGS(objagg, obj, refcount),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
__field(unsigned int, refcount)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
__entry->refcount = refcount;
),
TP_printk("objagg %p, obj %p, refcount %u",
__entry->objagg, __entry->obj, __entry->refcount)
);
TRACE_EVENT(objagg_obj_put,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj,
unsigned int refcount),
TP_ARGS(objagg, obj, refcount),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
__field(unsigned int, refcount)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
__entry->refcount = refcount;
),
TP_printk("objagg %p, obj %p, refcount %u",
__entry->objagg, __entry->obj, __entry->refcount)
);
TRACE_EVENT(objagg_obj_parent_assign,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj,
const struct objagg_obj *parent,
unsigned int parent_refcount),
TP_ARGS(objagg, obj, parent, parent_refcount),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
__field(const void *, parent)
__field(unsigned int, parent_refcount)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
__entry->parent = parent;
__entry->parent_refcount = parent_refcount;
),
TP_printk("objagg %p, obj %p, parent %p, parent_refcount %u",
__entry->objagg, __entry->obj,
__entry->parent, __entry->parent_refcount)
);
TRACE_EVENT(objagg_obj_parent_unassign,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj,
const struct objagg_obj *parent,
unsigned int parent_refcount),
TP_ARGS(objagg, obj, parent, parent_refcount),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
__field(const void *, parent)
__field(unsigned int, parent_refcount)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
__entry->parent = parent;
__entry->parent_refcount = parent_refcount;
),
TP_printk("objagg %p, obj %p, parent %p, parent_refcount %u",
__entry->objagg, __entry->obj,
__entry->parent, __entry->parent_refcount)
);
TRACE_EVENT(objagg_obj_root_create,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj),
TP_ARGS(objagg, obj),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
),
TP_printk("objagg %p, obj %p",
__entry->objagg, __entry->obj)
);
TRACE_EVENT(objagg_obj_root_destroy,
TP_PROTO(const struct objagg *objagg,
const struct objagg_obj *obj),
TP_ARGS(objagg, obj),
TP_STRUCT__entry(
__field(const void *, objagg)
__field(const void *, obj)
),
TP_fast_assign(
__entry->objagg = objagg;
__entry->obj = obj;
),
TP_printk("objagg %p, obj %p",
__entry->objagg, __entry->obj)
);
#endif /* __TRACE_OBJAGG_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
......@@ -624,3 +624,6 @@ config GENERIC_LIB_CMPDI2
config GENERIC_LIB_UCMPDI2
bool
config OBJAGG
tristate "objagg" if COMPILE_TEST
......@@ -1976,6 +1976,16 @@ config TEST_MEMCAT_P
If unsure, say N.
config TEST_OBJAGG
tristate "Perform selftest on object aggreration manager"
default n
depends on OBJAGG
help
Enable this option to test object aggregation manager on boot
(or module load).
If unsure, say N.
endif # RUNTIME_TESTING_MENU
config MEMTEST
......
......@@ -75,6 +75,7 @@ obj-$(CONFIG_TEST_PARMAN) += test_parman.o
obj-$(CONFIG_TEST_KMOD) += test_kmod.o
obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
......@@ -274,3 +275,4 @@ obj-$(CONFIG_GENERIC_LIB_LSHRDI3) += lshrdi3.o
obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o
obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o
obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o
obj-$(CONFIG_OBJAGG) += objagg.o
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,7 @@
lib_dir=$(dirname $0)/../../../../net/forwarding
ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
multiple_masks_test ctcam_edge_cases_test"
multiple_masks_test ctcam_edge_cases_test delta_simple_test"
NUM_NETIFS=2
source $lib_dir/tc_common.sh
source $lib_dir/lib.sh
......@@ -142,7 +142,7 @@ two_masks_test()
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.0.0/16 action drop
$tcflags dst_ip 192.0.0.0/8 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
......@@ -235,7 +235,7 @@ ctcam_two_atcam_masks_test()
$tcflags dst_ip 192.0.2.2 action drop
# Filter goes into A-TCAM
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.2.0/24 action drop
$tcflags dst_ip 192.0.0.0/16 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
......@@ -324,6 +324,86 @@ ctcam_edge_cases_test()
ctcam_no_atcam_masks_test
}
tp_record()
{
local tracepoint=$1
local cmd=$2
perf record -q -e $tracepoint $cmd
return $?
}
tp_check_hits()
{
local tracepoint=$1
local count=$2
perf_output=`perf script -F trace:event,trace`
hits=`echo $perf_output | grep "$tracepoint:" | wc -l`
if [[ "$count" -ne "$hits" ]]; then
return 1
fi
return 0
}
delta_simple_test()
{
# The first filter will create eRP, the second filter will fit into
# the first eRP with delta. Remove the first rule then and check that
# the eRP stays (referenced by the second filter).
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
pref 1 handle 101 flower $tcflags dst_ip 192.0.0.0/24 \
action drop"
tp_check_hits "objagg:objagg_obj_root_create" 1
check_err $? "eRP was not created"
tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
pref 2 handle 102 flower $tcflags dst_ip 192.0.2.2 \
action drop"
tp_check_hits "objagg:objagg_obj_root_create" 0
check_err $? "eRP was incorrectly created"
tp_check_hits "objagg:objagg_obj_parent_assign" 1
check_err $? "delta was not created"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
pref 1 handle 101 flower"
tp_check_hits "objagg:objagg_obj_root_destroy" 0
check_err $? "eRP was incorrectly destroyed"
tp_check_hits "objagg:objagg_obj_parent_unassign" 0
check_err $? "delta was incorrectly destroyed"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match on correct filter after the first was removed"
tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
pref 2 handle 102 flower"
tp_check_hits "objagg:objagg_obj_parent_unassign" 1
check_err $? "delta was not destroyed"
tp_check_hits "objagg:objagg_obj_root_destroy" 1
check_err $? "eRP was not destroyed"
log_test "delta simple test ($tcflags)"
}
setup_prepare()
{
h1=${NETIFS[p1]}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment