mlxsw: core_acl_flex_actions: Add police action
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>
This commit is contained in:
parent
d25b8f6ebc
commit
deee0abc70
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -838,6 +864,137 @@ err_cookie_get:
|
|||
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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -1622,6 +1805,40 @@ err_append_allocated_counter:
|
|||
}
|
||||
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),
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue