Skip to content

Commit

Permalink
mlxsw: core_acl_flex_actions: Add police action
Browse files Browse the repository at this point in the history
Add core functionality required to support police action in the policy
engine.

The utilized hardware policers are stored in a hash table keyed by the
flow action index. This allows to support policer sharing between
multiple ACL rules.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Petr Machata <petrm@mellanox.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Ido Schimmel authored and Jakub Kicinski committed Jul 16, 2020
1 parent d25b8f6 commit deee0ab
Show file tree
Hide file tree
Showing 2 changed files with 225 additions and 0 deletions.
217 changes: 217 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ struct mlxsw_afa {
struct rhashtable set_ht;
struct rhashtable fwd_entry_ht;
struct rhashtable cookie_ht;
struct rhashtable policer_ht;
struct idr cookie_idr;
struct list_head policer_list;
};

#define MLXSW_AFA_SET_LEN 0xA8
Expand Down Expand Up @@ -177,6 +179,21 @@ static const struct rhashtable_params mlxsw_afa_cookie_ht_params = {
.automatic_shrinking = true,
};

struct mlxsw_afa_policer {
struct rhash_head ht_node;
struct list_head list; /* Member of policer_list */
refcount_t ref_count;
u32 fa_index;
u16 policer_index;
};

static const struct rhashtable_params mlxsw_afa_policer_ht_params = {
.key_len = sizeof(u32),
.key_offset = offsetof(struct mlxsw_afa_policer, fa_index),
.head_offset = offsetof(struct mlxsw_afa_policer, ht_node),
.automatic_shrinking = true,
};

struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set,
const struct mlxsw_afa_ops *ops,
void *ops_priv)
Expand All @@ -198,12 +215,19 @@ struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set,
&mlxsw_afa_cookie_ht_params);
if (err)
goto err_cookie_rhashtable_init;
err = rhashtable_init(&mlxsw_afa->policer_ht,
&mlxsw_afa_policer_ht_params);
if (err)
goto err_policer_rhashtable_init;
idr_init(&mlxsw_afa->cookie_idr);
INIT_LIST_HEAD(&mlxsw_afa->policer_list);
mlxsw_afa->max_acts_per_set = max_acts_per_set;
mlxsw_afa->ops = ops;
mlxsw_afa->ops_priv = ops_priv;
return mlxsw_afa;

err_policer_rhashtable_init:
rhashtable_destroy(&mlxsw_afa->cookie_ht);
err_cookie_rhashtable_init:
rhashtable_destroy(&mlxsw_afa->fwd_entry_ht);
err_fwd_entry_rhashtable_init:
Expand All @@ -216,8 +240,10 @@ EXPORT_SYMBOL(mlxsw_afa_create);

void mlxsw_afa_destroy(struct mlxsw_afa *mlxsw_afa)
{
WARN_ON(!list_empty(&mlxsw_afa->policer_list));
WARN_ON(!idr_is_empty(&mlxsw_afa->cookie_idr));
idr_destroy(&mlxsw_afa->cookie_idr);
rhashtable_destroy(&mlxsw_afa->policer_ht);
rhashtable_destroy(&mlxsw_afa->cookie_ht);
rhashtable_destroy(&mlxsw_afa->fwd_entry_ht);
rhashtable_destroy(&mlxsw_afa->set_ht);
Expand Down Expand Up @@ -838,6 +864,137 @@ mlxsw_afa_cookie_ref_create(struct mlxsw_afa_block *block,
return ERR_PTR(err);
}

static struct mlxsw_afa_policer *
mlxsw_afa_policer_create(struct mlxsw_afa *mlxsw_afa, u32 fa_index,
u64 rate_bytes_ps, u32 burst,
struct netlink_ext_ack *extack)
{
struct mlxsw_afa_policer *policer;
int err;

policer = kzalloc(sizeof(*policer), GFP_KERNEL);
if (!policer)
return ERR_PTR(-ENOMEM);

err = mlxsw_afa->ops->policer_add(mlxsw_afa->ops_priv, rate_bytes_ps,
burst, &policer->policer_index,
extack);
if (err)
goto err_policer_add;

refcount_set(&policer->ref_count, 1);
policer->fa_index = fa_index;

err = rhashtable_insert_fast(&mlxsw_afa->policer_ht, &policer->ht_node,
mlxsw_afa_policer_ht_params);
if (err)
goto err_rhashtable_insert;

list_add_tail(&policer->list, &mlxsw_afa->policer_list);

return policer;

err_rhashtable_insert:
mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv,
policer->policer_index);
err_policer_add:
kfree(policer);
return ERR_PTR(err);
}

static void mlxsw_afa_policer_destroy(struct mlxsw_afa *mlxsw_afa,
struct mlxsw_afa_policer *policer)
{
list_del(&policer->list);
rhashtable_remove_fast(&mlxsw_afa->policer_ht, &policer->ht_node,
mlxsw_afa_policer_ht_params);
mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv,
policer->policer_index);
kfree(policer);
}

static struct mlxsw_afa_policer *
mlxsw_afa_policer_get(struct mlxsw_afa *mlxsw_afa, u32 fa_index,
u64 rate_bytes_ps, u32 burst,
struct netlink_ext_ack *extack)
{
struct mlxsw_afa_policer *policer;

policer = rhashtable_lookup_fast(&mlxsw_afa->policer_ht, &fa_index,
mlxsw_afa_policer_ht_params);
if (policer) {
refcount_inc(&policer->ref_count);
return policer;
}

return mlxsw_afa_policer_create(mlxsw_afa, fa_index, rate_bytes_ps,
burst, extack);
}

static void mlxsw_afa_policer_put(struct mlxsw_afa *mlxsw_afa,
struct mlxsw_afa_policer *policer)
{
if (!refcount_dec_and_test(&policer->ref_count))
return;
mlxsw_afa_policer_destroy(mlxsw_afa, policer);
}

struct mlxsw_afa_policer_ref {
struct mlxsw_afa_resource resource;
struct mlxsw_afa_policer *policer;
};

static void
mlxsw_afa_policer_ref_destroy(struct mlxsw_afa_block *block,
struct mlxsw_afa_policer_ref *policer_ref)
{
mlxsw_afa_resource_del(&policer_ref->resource);
mlxsw_afa_policer_put(block->afa, policer_ref->policer);
kfree(policer_ref);
}

static void
mlxsw_afa_policer_ref_destructor(struct mlxsw_afa_block *block,
struct mlxsw_afa_resource *resource)
{
struct mlxsw_afa_policer_ref *policer_ref;

policer_ref = container_of(resource, struct mlxsw_afa_policer_ref,
resource);
mlxsw_afa_policer_ref_destroy(block, policer_ref);
}

static struct mlxsw_afa_policer_ref *
mlxsw_afa_policer_ref_create(struct mlxsw_afa_block *block, u32 fa_index,
u64 rate_bytes_ps, u32 burst,
struct netlink_ext_ack *extack)
{
struct mlxsw_afa_policer_ref *policer_ref;
struct mlxsw_afa_policer *policer;
int err;

policer_ref = kzalloc(sizeof(*policer_ref), GFP_KERNEL);
if (!policer_ref)
return ERR_PTR(-ENOMEM);

policer = mlxsw_afa_policer_get(block->afa, fa_index, rate_bytes_ps,
burst, extack);
if (IS_ERR(policer)) {
err = PTR_ERR(policer);
goto err_policer_get;
}

policer_ref->policer = policer;
policer_ref->resource.destructor = mlxsw_afa_policer_ref_destructor;
mlxsw_afa_resource_add(block, &policer_ref->resource);

return policer_ref;

err_policer_get:
kfree(policer_ref);
return ERR_PTR(err);
}

#define MLXSW_AFA_ONE_ACTION_LEN 32
#define MLXSW_AFA_PAYLOAD_OFFSET 4

Expand Down Expand Up @@ -1551,6 +1708,19 @@ EXPORT_SYMBOL(mlxsw_afa_block_append_fwd);
#define MLXSW_AFA_POLCNT_CODE 0x08
#define MLXSW_AFA_POLCNT_SIZE 1

enum {
MLXSW_AFA_POLCNT_COUNTER,
MLXSW_AFA_POLCNT_POLICER,
};

/* afa_polcnt_c_p
* Counter or policer.
* Indicates whether the action binds a policer or a counter to the flow.
* 0: Counter
* 1: Policer
*/
MLXSW_ITEM32(afa, polcnt, c_p, 0x00, 31, 1);

enum mlxsw_afa_polcnt_counter_set_type {
/* No count */
MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT = 0x00,
Expand All @@ -1570,15 +1740,28 @@ MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8);
*/
MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24);

/* afa_polcnt_pid
* Policer ID.
* Reserved when c_p = 0
*/
MLXSW_ITEM32(afa, polcnt, pid, 0x08, 0, 14);

static inline void
mlxsw_afa_polcnt_pack(char *payload,
enum mlxsw_afa_polcnt_counter_set_type set_type,
u32 counter_index)
{
mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_COUNTER);
mlxsw_afa_polcnt_counter_set_type_set(payload, set_type);
mlxsw_afa_polcnt_counter_index_set(payload, counter_index);
}

static void mlxsw_afa_polcnt_policer_pack(char *payload, u16 policer_index)
{
mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_POLICER);
mlxsw_afa_polcnt_pid_set(payload, policer_index);
}

int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block,
u32 counter_index)
{
Expand Down Expand Up @@ -1622,6 +1805,40 @@ int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block,
}
EXPORT_SYMBOL(mlxsw_afa_block_append_counter);

int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block,
u32 fa_index, u64 rate_bytes_ps, u32 burst,
u16 *p_policer_index,
struct netlink_ext_ack *extack)
{
struct mlxsw_afa_policer_ref *policer_ref;
char *act;
int err;

policer_ref = mlxsw_afa_policer_ref_create(block, fa_index,
rate_bytes_ps,
burst, extack);
if (IS_ERR(policer_ref))
return PTR_ERR(policer_ref);
*p_policer_index = policer_ref->policer->policer_index;

act = mlxsw_afa_block_append_action_ext(block, MLXSW_AFA_POLCNT_CODE,
MLXSW_AFA_POLCNT_SIZE,
MLXSW_AFA_ACTION_TYPE_POLICE);
if (IS_ERR(act)) {
NL_SET_ERR_MSG_MOD(extack, "Cannot append police action");
err = PTR_ERR(act);
goto err_append_action;
}
mlxsw_afa_polcnt_policer_pack(act, *p_policer_index);

return 0;

err_append_action:
mlxsw_afa_policer_ref_destroy(block, policer_ref);
return err;
}
EXPORT_SYMBOL(mlxsw_afa_block_append_police);

/* Virtual Router and Forwarding Domain Action
* -------------------------------------------
* Virtual Switch action is used for manipulate the Virtual Router (VR),
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ struct mlxsw_afa_ops {
bool ingress, int *p_span_id);
void (*mirror_del)(void *priv, u8 local_in_port, int span_id,
bool ingress);
int (*policer_add)(void *priv, u64 rate_bytes_ps, u32 burst,
u16 *p_policer_index,
struct netlink_ext_ack *extack);
void (*policer_del)(void *priv, u16 policer_index);
bool dummy_first_set;
};

Expand Down Expand Up @@ -84,5 +88,9 @@ int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block,
bool rmid_valid, u32 kvdl_index);
int mlxsw_afa_block_append_l4port(struct mlxsw_afa_block *block, bool is_dport, u16 l4_port,
struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block,
u32 fa_index, u64 rate_bytes_ps, u32 burst,
u16 *p_policer_index,
struct netlink_ext_ack *extack);

#endif

0 comments on commit deee0ab

Please sign in to comment.