Commit 3e32675c authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-Implement-periodic-ERP-rehash'

Ido Schimmel says:

====================
mlxsw: Implement periodic ERP rehash

Currently, an ERP set is created for each region according to rules
inserted and order of their insertion. However that might lead to
suboptimal ERP sets and possible unnecessary spillage into C-TCAM.
This patchset aims to fix this problem and introduces periodical checking
of used ERP sets and in case a better ERP set is possible for the given
set of rules, it rehashes the region to use the better ERP set.

Patch 1 prepares devlink params infra in order to fix the
        init/fini sequences.
Patch 2 implements hints infra in objagg library.
Patch 3 fixes a typo
Patch 4 adds number of root objects directly into objagg stats.
Patches 5-7 do split of multiple structs in Spectrum TCAM code.
Patch 8 introduces initial implementation of ERP rehash logic,
         according to objagg hints.
Patch 9 adds hints priv passing trought the layers.
Patch 10 adds multi field into PAGT reg. (new patch)
Patch 11 implements actual region rules migration in TCAM code.
Patch 12 adds a devlink param so user is able to control
         rehash interval.
Patch 13 adds couple of tracepoints in order to track
         rehash procedures.
Patch 14 adds a simple selftest to test region rehash.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a655fe9f c478d3c3
fw_load_policy [DEVICE, GENERIC]
Configuration mode: driverinit
acl_region_rehash_interval [DEVICE, DRIVER-SPECIFIC]
Sets an interval for periodic ACL region rehashes.
The value is in milliseconds, minimal value is "3000".
Value "0" disables the periodic work.
The first rehash will be run right after value is set.
Type: u32
Configuration mode: runtime
......@@ -258,6 +258,9 @@ int bnxt_dl_register(struct bnxt *bp)
netdev_err(bp->dev, "devlink_port_params_register failed");
goto err_dl_port_unreg;
}
devlink_params_publish(dl);
return 0;
err_dl_port_unreg:
......
......@@ -3981,6 +3981,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err_params_unregister;
devlink_params_publish(devlink);
pci_save_state(pdev);
return 0;
......
......@@ -1062,6 +1062,9 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
goto err_driver_init;
}
if (mlxsw_driver->params_register && !reload)
devlink_params_publish(devlink);
return 0;
err_driver_init:
......@@ -1131,6 +1134,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
return;
}
if (mlxsw_core->driver->params_unregister && !reload)
devlink_params_unpublish(devlink);
if (mlxsw_core->driver->fini)
mlxsw_core->driver->fini(mlxsw_core);
mlxsw_thermal_fini(mlxsw_core->thermal);
......
......@@ -394,4 +394,9 @@ static inline void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
#endif
enum mlxsw_devlink_param_id {
MLXSW_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL,
};
#endif
......@@ -2199,6 +2199,14 @@ MLXSW_ITEM32(reg, pagt, size, 0x00, 0, 8);
*/
MLXSW_ITEM32(reg, pagt, acl_group_id, 0x08, 0, 16);
/* reg_pagt_multi
* Multi-ACL
* 0 - This ACL is the last ACL in the multi-ACL
* 1 - This ACL is part of a multi-ACL
* Access: RW
*/
MLXSW_ITEM32_INDEXED(reg, pagt, multi, 0x30, 31, 1, 0x04, 0x00, false);
/* reg_pagt_acl_id
* ACL identifier
* Access: RW
......@@ -2212,12 +2220,13 @@ static inline void mlxsw_reg_pagt_pack(char *payload, u16 acl_group_id)
}
static inline void mlxsw_reg_pagt_acl_id_pack(char *payload, int index,
u16 acl_id)
u16 acl_id, bool multi)
{
u8 size = mlxsw_reg_pagt_size_get(payload);
if (index >= size)
mlxsw_reg_pagt_size_set(payload, index + 1);
mlxsw_reg_pagt_multi_set(payload, index, multi);
mlxsw_reg_pagt_acl_id_set(payload, index, acl_id);
}
......
......@@ -4413,6 +4413,71 @@ static void mlxsw_sp_params_unregister(struct mlxsw_core *mlxsw_core)
ARRAY_SIZE(mlxsw_sp_devlink_params));
}
static int
mlxsw_sp_params_acl_region_rehash_intrvl_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
ctx->val.vu32 = mlxsw_sp_acl_region_rehash_intrvl_get(mlxsw_sp);
return 0;
}
static int
mlxsw_sp_params_acl_region_rehash_intrvl_set(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
return mlxsw_sp_acl_region_rehash_intrvl_set(mlxsw_sp, ctx->val.vu32);
}
static const struct devlink_param mlxsw_sp2_devlink_params[] = {
DEVLINK_PARAM_DRIVER(MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL,
"acl_region_rehash_interval",
DEVLINK_PARAM_TYPE_U32,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
mlxsw_sp_params_acl_region_rehash_intrvl_get,
mlxsw_sp_params_acl_region_rehash_intrvl_set,
NULL),
};
static int mlxsw_sp2_params_register(struct mlxsw_core *mlxsw_core)
{
struct devlink *devlink = priv_to_devlink(mlxsw_core);
union devlink_param_value value;
int err;
err = mlxsw_sp_params_register(mlxsw_core);
if (err)
return err;
err = devlink_params_register(devlink, mlxsw_sp2_devlink_params,
ARRAY_SIZE(mlxsw_sp2_devlink_params));
if (err)
goto err_devlink_params_register;
value.vu32 = 0;
devlink_param_driverinit_value_set(devlink,
MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL,
value);
return 0;
err_devlink_params_register:
mlxsw_sp_params_unregister(mlxsw_core);
return err;
}
static void mlxsw_sp2_params_unregister(struct mlxsw_core *mlxsw_core)
{
devlink_params_unregister(priv_to_devlink(mlxsw_core),
mlxsw_sp2_devlink_params,
ARRAY_SIZE(mlxsw_sp2_devlink_params));
mlxsw_sp_params_unregister(mlxsw_core);
}
static struct mlxsw_driver mlxsw_sp1_driver = {
.kind = mlxsw_sp1_driver_name,
.priv_size = sizeof(struct mlxsw_sp),
......@@ -4461,8 +4526,8 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
.sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
.txhdr_construct = mlxsw_sp_txhdr_construct,
.resources_register = mlxsw_sp2_resources_register,
.params_register = mlxsw_sp_params_register,
.params_unregister = mlxsw_sp_params_unregister,
.params_register = mlxsw_sp2_params_register,
.params_unregister = mlxsw_sp2_params_unregister,
.txhdr_len = MLXSW_TXHDR_LEN,
.profile = &mlxsw_sp2_config_profile,
.res_query_enabled = true,
......
......@@ -690,6 +690,8 @@ struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp);
u32 mlxsw_sp_acl_region_rehash_intrvl_get(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_acl_region_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp, u32 val);
/* spectrum_acl_tcam.c */
struct mlxsw_sp_acl_tcam;
......@@ -704,10 +706,13 @@ struct mlxsw_sp_acl_tcam_ops {
size_t region_priv_size;
int (*region_init)(struct mlxsw_sp *mlxsw_sp, void *region_priv,
void *tcam_priv,
struct mlxsw_sp_acl_tcam_region *region);
struct mlxsw_sp_acl_tcam_region *region,
void *hints_priv);
void (*region_fini)(struct mlxsw_sp *mlxsw_sp, void *region_priv);
int (*region_associate)(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam_region *region);
void * (*region_rehash_hints_get)(void *region_priv);
void (*region_rehash_hints_put)(void *hints_priv);
size_t chunk_priv_size;
void (*chunk_init)(void *region_priv, void *chunk_priv,
unsigned int priority);
......
......@@ -112,7 +112,8 @@ mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp,
static int
mlxsw_sp1_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
void *tcam_priv,
struct mlxsw_sp_acl_tcam_region *_region)
struct mlxsw_sp_acl_tcam_region *_region,
void *hints_priv)
{
struct mlxsw_sp1_acl_tcam_region *region = region_priv;
int err;
......
......@@ -139,7 +139,8 @@ static void mlxsw_sp2_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
static int
mlxsw_sp2_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
void *tcam_priv,
struct mlxsw_sp_acl_tcam_region *_region)
struct mlxsw_sp_acl_tcam_region *_region,
void *hints_priv)
{
struct mlxsw_sp2_acl_tcam_region *region = region_priv;
struct mlxsw_sp2_acl_tcam *tcam = tcam_priv;
......@@ -147,7 +148,8 @@ mlxsw_sp2_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
region->region = _region;
return mlxsw_sp_acl_atcam_region_init(mlxsw_sp, &tcam->atcam,
&region->aregion, _region,
&region->aregion,
_region, hints_priv,
&mlxsw_sp2_acl_ctcam_region_ops);
}
......@@ -166,6 +168,18 @@ mlxsw_sp2_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_acl_atcam_region_associate(mlxsw_sp, region->id);
}
static void *mlxsw_sp2_acl_tcam_region_rehash_hints_get(void *region_priv)
{
struct mlxsw_sp2_acl_tcam_region *region = region_priv;
return mlxsw_sp_acl_atcam_rehash_hints_get(&region->aregion);
}
static void mlxsw_sp2_acl_tcam_region_rehash_hints_put(void *hints_priv)
{
mlxsw_sp_acl_atcam_rehash_hints_put(hints_priv);
}
static void mlxsw_sp2_acl_tcam_chunk_init(void *region_priv, void *chunk_priv,
unsigned int priority)
{
......@@ -243,6 +257,8 @@ const struct mlxsw_sp_acl_tcam_ops mlxsw_sp2_acl_tcam_ops = {
.region_init = mlxsw_sp2_acl_tcam_region_init,
.region_fini = mlxsw_sp2_acl_tcam_region_fini,
.region_associate = mlxsw_sp2_acl_tcam_region_associate,
.region_rehash_hints_get = mlxsw_sp2_acl_tcam_region_rehash_hints_get,
.region_rehash_hints_put = mlxsw_sp2_acl_tcam_region_rehash_hints_put,
.chunk_priv_size = sizeof(struct mlxsw_sp2_acl_tcam_chunk),
.chunk_init = mlxsw_sp2_acl_tcam_chunk_init,
.chunk_fini = mlxsw_sp2_acl_tcam_chunk_fini,
......
......@@ -640,7 +640,7 @@ mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp,
int err;
mlxsw_sp_acl_ruleset_ref_inc(ruleset);
rule = kzalloc(sizeof(*rule) + ops->rule_priv_size(mlxsw_sp),
rule = kzalloc(sizeof(*rule) + ops->rule_priv_size,
GFP_KERNEL);
if (!rule) {
err = -ENOMEM;
......@@ -912,3 +912,19 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp)
mlxsw_afk_destroy(acl->afk);
kfree(acl);
}
u32 mlxsw_sp_acl_region_rehash_intrvl_get(struct mlxsw_sp *mlxsw_sp)
{
struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
return mlxsw_sp_acl_tcam_vregion_rehash_intrvl_get(mlxsw_sp,
&acl->tcam);
}
int mlxsw_sp_acl_region_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp, u32 val)
{
struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
return mlxsw_sp_acl_tcam_vregion_rehash_intrvl_set(mlxsw_sp,
&acl->tcam, val);
}
......@@ -318,6 +318,7 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam *atcam,
struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_tcam_region *region,
void *hints_priv,
const struct mlxsw_sp_acl_ctcam_region_ops *ops)
{
int err;
......@@ -334,7 +335,7 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
err = aregion->ops->init(aregion);
if (err)
goto err_ops_init;
err = mlxsw_sp_acl_erp_region_init(aregion);
err = mlxsw_sp_acl_erp_region_init(aregion, hints_priv);
if (err)
goto err_erp_region_init;
err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &aregion->cregion,
......@@ -634,3 +635,14 @@ void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
{
mlxsw_sp_acl_erps_fini(mlxsw_sp, atcam);
}
void *
mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
{
return mlxsw_sp_acl_erp_rehash_hints_get(aregion);
}
void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv)
{
mlxsw_sp_acl_erp_rehash_hints_put(hints_priv);
}
......@@ -1200,6 +1200,32 @@ mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
return 0;
}
static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj,
const void *obj)
{
const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
const struct mlxsw_sp_acl_erp_key *key = obj;
u16 delta_start;
u8 delta_mask;
int err;
err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
&delta_start, &delta_mask);
return err ? false : true;
}
static int mlxsw_sp_acl_erp_hints_obj_cmp(const void *obj1, const void *obj2)
{
const struct mlxsw_sp_acl_erp_key *key1 = obj1;
const struct mlxsw_sp_acl_erp_key *key2 = obj2;
/* For hints purposes, two objects are considered equal
* in case the masks are the same. Does not matter what
* the "ctcam" value is.
*/
return memcmp(key1->mask, key2->mask, sizeof(key1->mask));
}
static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
void *obj)
{
......@@ -1254,12 +1280,17 @@ static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
kfree(delta);
}
static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj)
static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj,
unsigned int root_id)
{
struct mlxsw_sp_acl_atcam_region *aregion = priv;
struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
struct mlxsw_sp_acl_erp_key *key = obj;
if (!key->ctcam &&
root_id != OBJAGG_OBJ_ROOT_ID_INVALID &&
root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION)
return ERR_PTR(-ENOBUFS);
return erp_table->ops->erp_create(erp_table, key);
}
......@@ -1273,6 +1304,8 @@ static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
.obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
.delta_check = mlxsw_sp_acl_erp_delta_check,
.hints_obj_cmp = mlxsw_sp_acl_erp_hints_obj_cmp,
.delta_create = mlxsw_sp_acl_erp_delta_create,
.delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
.root_create = mlxsw_sp_acl_erp_root_create,
......@@ -1280,7 +1313,8 @@ static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
};
static struct mlxsw_sp_acl_erp_table *
mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion,
struct objagg_hints *hints)
{
struct mlxsw_sp_acl_erp_table *erp_table;
int err;
......@@ -1290,7 +1324,7 @@ mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
return ERR_PTR(-ENOMEM);
erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
aregion);
hints, aregion);
if (IS_ERR(erp_table->objagg)) {
err = PTR_ERR(erp_table->objagg);
goto err_objagg_create;
......@@ -1337,12 +1371,88 @@ mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
}
int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion)
static int
mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam_region *aregion,
struct objagg_hints *hints, bool *p_rehash_needed)
{
struct objagg *objagg = aregion->erp_table->objagg;
const struct objagg_stats *ostats;
const struct objagg_stats *hstats;
int err;
*p_rehash_needed = false;
ostats = objagg_stats_get(objagg);
if (IS_ERR(ostats)) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP stats\n");
return PTR_ERR(ostats);
}
hstats = objagg_hints_stats_get(hints);
if (IS_ERR(hstats)) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP hints stats\n");
err = PTR_ERR(hstats);
goto err_hints_stats_get;
}
/* Very basic criterion for now. */
if (hstats->root_count < ostats->root_count)
*p_rehash_needed = true;
err = 0;
objagg_stats_put(hstats);
err_hints_stats_get:
objagg_stats_put(ostats);
return err;
}
void *
mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
{
struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
struct objagg_hints *hints;
bool rehash_needed;
int err;
hints = objagg_hints_get(aregion->erp_table->objagg,
OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
if (IS_ERR(hints)) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to create ERP hints\n");
return ERR_CAST(hints);
}
err = mlxsw_sp_acl_erp_hints_check(mlxsw_sp, aregion, hints,
&rehash_needed);
if (err)
goto errout;
if (!rehash_needed) {
err = -EAGAIN;
goto errout;
}
return hints;
errout:
objagg_hints_put(hints);
return ERR_PTR(err);
}
void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv)
{
struct objagg_hints *hints = hints_priv;
objagg_hints_put(hints);
}
int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion,
void *hints_priv)
{
struct mlxsw_sp_acl_erp_table *erp_table;
struct objagg_hints *hints = hints_priv;
int err;
erp_table = mlxsw_sp_acl_erp_table_create(aregion);
erp_table = mlxsw_sp_acl_erp_table_create(aregion, hints);
if (IS_ERR(erp_table))
return PTR_ERR(erp_table);
aregion->erp_table = erp_table;
......
......@@ -17,6 +17,8 @@ struct mlxsw_sp_acl_tcam {
unsigned long *used_groups; /* bit array */
unsigned int max_groups;
unsigned int max_group_size;
struct list_head vregion_list;
u32 vregion_rehash_intrvl; /* ms */
unsigned long priv[0];
/* priv has to be always the last item */
};
......@@ -26,6 +28,11 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam *tcam);
void mlxsw_sp_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam *tcam);
u32 mlxsw_sp_acl_tcam_vregion_rehash_intrvl_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam *tcam);
int mlxsw_sp_acl_tcam_vregion_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam *tcam,
u32 val);
int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u32 *priority, bool fillup_priority);
......@@ -43,7 +50,7 @@ struct mlxsw_sp_acl_profile_ops {
struct mlxsw_sp_port *mlxsw_sp_port,
bool ingress);
u16 (*ruleset_group_id)(void *ruleset_priv);
size_t (*rule_priv_size)(struct mlxsw_sp *mlxsw_sp);
size_t rule_priv_size;
int (*rule_add)(struct mlxsw_sp *mlxsw_sp,
void *ruleset_priv, void *rule_priv,
struct mlxsw_sp_acl_rule_info *rulei);
......@@ -67,11 +74,10 @@ mlxsw_sp_acl_tcam_profile_ops(struct mlxsw_sp *mlxsw_sp,
(MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN * BITS_PER_BYTE)
struct mlxsw_sp_acl_tcam_group;
struct mlxsw_sp_acl_tcam_vregion;
struct mlxsw_sp_acl_tcam_region {
struct list_head list; /* Member of a TCAM group */
struct list_head chunk_list; /* List of chunks under this region */
struct mlxsw_sp_acl_tcam_group *group;
struct mlxsw_sp_acl_tcam_vregion *vregion;
enum mlxsw_reg_ptar_key_type key_type;
u16 id; /* ACL ID and region ID - they are same */
char tcam_region_info[MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN];
......@@ -207,6 +213,7 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam *atcam,
struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_tcam_region *region,
void *hints_priv,
const struct mlxsw_sp_acl_ctcam_region_ops *ops);
void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion);
void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion,
......@@ -230,6 +237,9 @@ int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam *atcam);
void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam *atcam);
void *
mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion);
void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv);
struct mlxsw_sp_acl_erp_delta;
......@@ -260,7 +270,11 @@ void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_erp_mask *erp_mask,
struct mlxsw_sp_acl_atcam_entry *aentry);
int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion);
void *
mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion);
void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv);
int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion,
void *hints_priv);
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,
struct mlxsw_sp_acl_atcam *atcam);
......
......@@ -6,14 +6,19 @@
struct objagg_ops {
size_t obj_size;
bool (*delta_check)(void *priv, const void *parent_obj,
const void *obj);
int (*hints_obj_cmp)(const void *obj1, const void *obj2);
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_create)(void *priv, void *obj, unsigned int root_id);
#define OBJAGG_OBJ_ROOT_ID_INVALID UINT_MAX
void (*root_destroy)(void *priv, void *root_priv);
};
struct objagg;
struct objagg_obj;
struct objagg_hints;
const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj);
const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj);
......@@ -21,7 +26,8 @@ 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);
struct objagg *objagg_create(const struct objagg_ops *ops,
struct objagg_hints *hints, void *priv);
void objagg_destroy(struct objagg *objagg);
struct objagg_obj_stats {
......@@ -36,6 +42,7 @@ struct objagg_obj_stats_info {
};
struct objagg_stats {
unsigned int root_count;
unsigned int stats_info_count;
struct objagg_obj_stats_info stats_info[];
};
......@@ -43,4 +50,14 @@ struct objagg_stats {
const struct objagg_stats *objagg_stats_get(struct objagg *objagg);
void objagg_stats_put(const struct objagg_stats *objagg_stats);
enum objagg_opt_algo_type {
OBJAGG_OPT_ALGO_SIMPLE_GREEDY,
};
struct objagg_hints *objagg_hints_get(struct objagg *objagg,
enum objagg_opt_algo_type opt_algo_type);
void objagg_hints_put(struct objagg_hints *objagg_hints);
const struct objagg_stats *
objagg_hints_stats_get(struct objagg_hints *objagg_hints);
#endif
......@@ -358,6 +358,7 @@ struct devlink_param_item {
const struct devlink_param *param;
union devlink_param_value driverinit_value;
bool driverinit_value_valid;
bool published;
};
enum devlink_param_generic_id {
......@@ -618,6 +619,8 @@ int devlink_params_register(struct devlink *devlink,
void devlink_params_unregister(struct devlink *devlink,
const struct devlink_param *params,
size_t params_count);
void devlink_params_publish(struct devlink *devlink);
void devlink_params_unpublish(struct devlink *devlink);
int devlink_port_params_register(struct devlink_port *devlink_port,
const struct devlink_param *params,
size_t params_count);
......@@ -724,6 +727,14 @@ static inline void devlink_unregister(struct devlink *devlink)
{
}
static inline void devlink_params_publish(struct devlink *devlink)
{
}
static inline void devlink_params_unpublish(struct devlink *devlink)
{
}
static inline void devlink_free(struct devlink *devlink)
{
kfree(devlink);
......
......@@ -11,6 +11,7 @@
struct mlxsw_sp;
struct mlxsw_sp_acl_atcam_region;
struct mlxsw_sp_acl_tcam_vregion;
TRACE_EVENT(mlxsw_sp_acl_atcam_entry_add_ctcam_spill,
TP_PROTO(const struct mlxsw_sp *mlxsw_sp,
......@@ -32,6 +33,66 @@ TRACE_EVENT(mlxsw_sp_acl_atcam_entry_add_ctcam_spill,
__entry->mlxsw_sp, __entry->aregion)
);
TRACE_EVENT(mlxsw_sp_acl_tcam_vregion_rehash,
TP_PROTO(const struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_acl_tcam_vregion *vregion),
TP_ARGS(mlxsw_sp, vregion),
TP_STRUCT__entry(
__field(const void *, mlxsw_sp)
__field(const void *, vregion)
),
TP_fast_assign(
__entry->mlxsw_sp = mlxsw_sp;
__entry->vregion = vregion;
),
TP_printk("mlxsw_sp %p, vregion %p",
__entry->mlxsw_sp, __entry->vregion)
);
TRACE_EVENT(mlxsw_sp_acl_tcam_vregion_migrate,
TP_PROTO(const struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_acl_tcam_vregion *vregion),
TP_ARGS(mlxsw_sp, vregion),
TP_STRUCT__entry(
__field(const void *, mlxsw_sp)
__field(const void *, vregion)
),
TP_fast_assign(
__entry->mlxsw_sp = mlxsw_sp;
__entry->vregion = vregion;
),
TP_printk("mlxsw_sp %p, vregion %p",
__entry->mlxsw_sp, __entry->vregion)
);
TRACE_EVENT(mlxsw_sp_acl_tcam_vregion_rehash_dis,
TP_PROTO(const struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_acl_tcam_vregion *vregion),
TP_ARGS(mlxsw_sp, vregion),
TP_STRUCT__entry(
__field(const void *, mlxsw_sp)
__field(const void *, vregion)
),
TP_fast_assign(
__entry->mlxsw_sp = mlxsw_sp;
__entry->vregion = vregion;
),
TP_printk("mlxsw_sp %p, vregion %p",
__entry->mlxsw_sp, __entry->vregion)
);
#endif /* _MLXSW_TRACEPOINT_H */
/* This part must be outside protection */
......
This diff is collapsed.
......@@ -87,6 +87,15 @@ static void world_obj_put(struct world *world, struct objagg *objagg,
#define MAX_KEY_ID_DIFF 5
static bool delta_check(void *priv, const void *parent_obj, const void *obj)
{
const struct tokey *parent_key = parent_obj;
const struct tokey *key = obj;
int diff = key->id - parent_key->id;
return diff >= 0 && diff <= MAX_KEY_ID_DIFF;
}
static void *delta_create(void *priv, void *parent_obj, void *obj)
{
struct tokey *parent_key = parent_obj;
......@@ -95,7 +104,7 @@ static void *delta_create(void *priv, void *parent_obj, void *obj)
int diff = key->id - parent_key->id;
struct delta *delta;
if (diff < 0 || diff > MAX_KEY_ID_DIFF)
if (!delta_check(priv, parent_obj, obj))
return ERR_PTR(-EINVAL);
delta = kzalloc(sizeof(*delta), GFP_KERNEL);
......@@ -115,7 +124,7 @@ static void delta_destroy(void *priv, void *delta_priv)
kfree(delta);
}
static void *root_create(void *priv, void *obj)
static void *root_create(void *priv, void *obj, unsigned int id)
{
struct world *world = priv;
struct tokey *key = obj;
......@@ -268,6 +277,12 @@ static int check_stats_nodelta(struct objagg *objagg)
return err;
}
static bool delta_check_dummy(void *priv, const void *parent_obj,
const void *obj)
{
return false;
}
static void *delta_create_dummy(void *priv, void *parent_obj, void *obj)
{
return ERR_PTR(-EOPNOTSUPP);
......@@ -279,6 +294,7 @@ static void delta_destroy_dummy(void *priv, void *delta_priv)
static const struct objagg_ops nodelta_ops = {
.obj_size = sizeof(struct tokey),
.delta_check = delta_check_dummy,
.delta_create = delta_create_dummy,
.delta_destroy = delta_destroy_dummy,
.root_create = root_create,
......@@ -292,7 +308,7 @@ static int test_nodelta(void)
int i;
int err;
objagg = objagg_create(&nodelta_ops, &world);
objagg = objagg_create(&nodelta_ops, NULL, &world);
if (IS_ERR(objagg))
return PTR_ERR(objagg);
......@@ -357,6 +373,7 @@ static int test_nodelta(void)
static const struct objagg_ops delta_ops = {
.obj_size = sizeof(struct tokey),
.delta_check = delta_check,
.delta_create = delta_create,
.delta_destroy = delta_destroy,
.root_create = root_create,
......@@ -793,7 +810,7 @@ static int test_delta(void)
int i;
int err;
objagg = objagg_create(&delta_ops, &world);
objagg = objagg_create(&delta_ops, NULL, &world);
if (IS_ERR(objagg))
return PTR_ERR(objagg);
......@@ -815,6 +832,170 @@ static int test_delta(void)
return err;
}
struct hints_case {
const unsigned int *key_ids;
size_t key_ids_count;
struct expect_stats expect_stats;
struct expect_stats expect_stats_hints;
};
static const unsigned int hints_case_key_ids[] = {
1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8,
};
static const struct hints_case hints_case = {
.key_ids = hints_case_key_ids,
.key_ids_count = ARRAY_SIZE(hints_case_key_ids),
.expect_stats =
EXPECT_STATS(7, ROOT(1, 2, 7), ROOT(7, 1, 4), ROOT(30, 1, 1),
DELTA(8, 3), DELTA(3, 2),
DELTA(5, 2), DELTA(6, 1)),
.expect_stats_hints =
EXPECT_STATS(7, ROOT(3, 2, 9), ROOT(1, 2, 2), ROOT(30, 1, 1),
DELTA(8, 3), DELTA(5, 2),
DELTA(6, 1), DELTA(7, 1)),
};
static void __pr_debug_stats(const struct objagg_stats *stats)
{
int i;
for (i = 0; i < stats->stats_info_count; i++)
pr_debug("Stat index %d key %u: u %d, d %d, %s\n", i,
obj_to_key_id(stats->stats_info[i].objagg_obj),
stats->stats_info[i].stats.user_count,
stats->stats_info[i].stats.delta_user_count,
stats->stats_info[i].is_root ? "root" : "noroot");
}
static void pr_debug_stats(struct objagg *objagg)
{
const struct objagg_stats *stats;
stats = objagg_stats_get(objagg);
if (IS_ERR(stats))
return;
__pr_debug_stats(stats);
objagg_stats_put(stats);
}
static void pr_debug_hints_stats(struct objagg_hints *objagg_hints)
{
const struct objagg_stats *stats;
stats = objagg_hints_stats_get(objagg_hints);
if (IS_ERR(stats))
return;
__pr_debug_stats(stats);
objagg_stats_put(stats);
}
static int check_expect_hints_stats(struct objagg_hints *objagg_hints,
const struct expect_stats *expect_stats,
const char **errmsg)
{
const struct objagg_stats *stats;
int err;
stats = objagg_hints_stats_get(objagg_hints);
if (IS_ERR(stats))
return PTR_ERR(stats);
err = __check_expect_stats(stats, expect_stats, errmsg);
objagg_stats_put(stats);
return err;
}
static int test_hints_case(const struct hints_case *hints_case)
{
struct objagg_obj *objagg_obj;
struct objagg_hints *hints;
struct world world2 = {};
struct world world = {};
struct objagg *objagg2;
struct objagg *objagg;
const char *errmsg;
int i;
int err;
objagg = objagg_create(&delta_ops, NULL, &world);
if (IS_ERR(objagg))
return PTR_ERR(objagg);
for (i = 0; i < hints_case->key_ids_count; i++) {
objagg_obj = world_obj_get(&world, objagg,
hints_case->key_ids[i]);
if (IS_ERR(objagg_obj)) {
err = PTR_ERR(objagg_obj);
goto err_world_obj_get;
}
}
pr_debug_stats(objagg);
err = check_expect_stats(objagg, &hints_case->expect_stats, &errmsg);
if (err) {
pr_err("Stats: %s\n", errmsg);
goto err_check_expect_stats;
}
hints = objagg_hints_get(objagg, OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
if (IS_ERR(hints)) {
err = PTR_ERR(hints);
goto err_hints_get;
}
pr_debug_hints_stats(hints);
err = check_expect_hints_stats(hints, &hints_case->expect_stats_hints,
&errmsg);
if (err) {
pr_err("Hints stats: %s\n", errmsg);
goto err_check_expect_hints_stats;
}
objagg2 = objagg_create(&delta_ops, hints, &world2);
if (IS_ERR(objagg))
return PTR_ERR(objagg);
for (i = 0; i < hints_case->key_ids_count; i++) {
objagg_obj = world_obj_get(&world2, objagg2,
hints_case->key_ids[i]);
if (IS_ERR(objagg_obj)) {
err = PTR_ERR(objagg_obj);
goto err_world2_obj_get;
}
}
pr_debug_stats(objagg2);
err = check_expect_stats(objagg2, &hints_case->expect_stats_hints,
&errmsg);
if (err) {
pr_err("Stats2: %s\n", errmsg);
goto err_check_expect_stats2;
}
err = 0;
err_check_expect_stats2:
err_world2_obj_get:
for (i--; i >= 0; i--)
world_obj_put(&world2, objagg, hints_case->key_ids[i]);
objagg_hints_put(hints);
objagg_destroy(objagg2);
i = hints_case->key_ids_count;
err_check_expect_hints_stats:
err_hints_get:
err_check_expect_stats:
err_world_obj_get:
for (i--; i >= 0; i--)
world_obj_put(&world, objagg, hints_case->key_ids[i]);
objagg_destroy(objagg);
return err;
}
static int test_hints(void)
{
return test_hints_case(&hints_case);
}
static int __init test_objagg_init(void)
{
int err;
......@@ -822,7 +1003,10 @@ static int __init test_objagg_init(void)
err = test_nodelta();
if (err)
return err;
return test_delta();
err = test_delta();
if (err)
return err;
return test_hints();
}
static void __exit test_objagg_exit(void)
......
......@@ -2858,6 +2858,7 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
u32 portid, u32 seq, int flags)
{
union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
const struct devlink_param *param = param_item->param;
struct devlink_param_gset_ctx ctx;
struct nlattr *param_values_list;
......@@ -2876,12 +2877,15 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
return -EOPNOTSUPP;
param_value[i] = param_item->driverinit_value;
} else {
if (!param_item->published)
continue;
ctx.cmode = i;
err = devlink_param_get(devlink, param, &ctx);
if (err)
return err;
param_value[i] = ctx.val;
}
param_value_set[i] = true;
}
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
......@@ -2916,7 +2920,7 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
goto param_nest_cancel;
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
if (!devlink_param_cmode_is_supported(param, i))
if (!param_value_set[i])
continue;
err = devlink_nl_param_value_fill_one(msg, param->type,
i, param_value[i]);
......@@ -5886,6 +5890,48 @@ void devlink_params_unregister(struct devlink *devlink,
}
EXPORT_SYMBOL_GPL(devlink_params_unregister);
/**
* devlink_params_publish - publish configuration parameters
*
* @devlink: devlink
*
* Publish previously registered configuration parameters.
*/
void devlink_params_publish(struct devlink *devlink)
{
struct devlink_param_item *param_item;
list_for_each_entry(param_item, &devlink->param_list, list) {
if (param_item->published)
continue;
param_item->published = true;
devlink_param_notify(devlink, 0, param_item,
DEVLINK_CMD_PARAM_NEW);
}
}
EXPORT_SYMBOL_GPL(devlink_params_publish);
/**
* devlink_params_unpublish - unpublish configuration parameters
*
* @devlink: devlink
*
* Unpublish previously registered configuration parameters.
*/
void devlink_params_unpublish(struct devlink *devlink)
{
struct devlink_param_item *param_item;
list_for_each_entry(param_item, &devlink->param_list, list) {
if (!param_item->published)
continue;
param_item->published = false;
devlink_param_notify(devlink, 0, param_item,
DEVLINK_CMD_PARAM_DEL);
}
}
EXPORT_SYMBOL_GPL(devlink_params_unpublish);
/**
* devlink_port_params_register - register port configuration parameters
*
......
......@@ -9,11 +9,11 @@ lib_dir=$(dirname $0)/../../../../net/forwarding
ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
multiple_masks_test ctcam_edge_cases_test delta_simple_test \
delta_two_masks_one_key_test bloom_simple_test \
bloom_complex_test bloom_delta_test"
delta_two_masks_one_key_test delta_simple_rehash_test \
bloom_simple_test bloom_complex_test bloom_delta_test"
NUM_NETIFS=2
source $lib_dir/tc_common.sh
source $lib_dir/lib.sh
source $lib_dir/devlink_lib.sh
tcflags="skip_hw"
......@@ -494,6 +494,77 @@ delta_two_masks_one_key_test()
log_test "delta two masks one key test ($tcflags)"
}
delta_simple_rehash_test()
{
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 0
check_err $? "Failed to set ACL region rehash interval"
tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_fail $? "Rehash trace was hit even when rehash should be disabled"
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 3000
check_err $? "Failed to set ACL region rehash interval"
sleep 1
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.1.0/25 action drop
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 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.3.0/24 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
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 103 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_all mlxsw:* 3
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_err $? "Rehash trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
check_err $? "Migrate trace was not hit"
tp_record_all mlxsw:* 3
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_err $? "Rehash trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
check_fail $? "Migrate trace was hit when no migration should happen"
$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 after rehash"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match on correct filter after rehash"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
log_test "delta simple rehash test ($tcflags)"
}
bloom_simple_test()
{
# Bloom filter requires that the eRP table is used. This test
......
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