mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 23:23:03 +00:00
net/mlx5e: TC, Support tc action api for police
Add support for tc action api for police. Offloading standalone police action without a tc rule and reporting stats. Signed-off-by: Roi Dayan <roid@nvidia.com> Reviewed-by: Jianbo Liu <jianbol@nvidia.com> Reviewed-by: Oz Shlomo <ozsh@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
This commit is contained in:
parent
f8e9d413a2
commit
7d1a5ce46e
@ -21,6 +21,7 @@
|
||||
#include "en/tc/sample.h"
|
||||
#include "en_accel/ipsec_rxtx.h"
|
||||
#include "en/tc/int_port.h"
|
||||
#include "en/tc/act/act.h"
|
||||
|
||||
struct mlx5e_rep_indr_block_priv {
|
||||
struct net_device *netdev;
|
||||
@ -511,6 +512,120 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5e_rep_indr_replace_act(struct mlx5e_rep_priv *rpriv,
|
||||
struct flow_offload_action *fl_act)
|
||||
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
|
||||
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
|
||||
enum mlx5_flow_namespace_type ns_type;
|
||||
struct flow_action_entry *action;
|
||||
struct mlx5e_tc_act *act;
|
||||
bool add = false;
|
||||
int i;
|
||||
|
||||
/* There is no use case currently for more than one action (e.g. pedit).
|
||||
* when there will be, need to handle cleaning multiple actions on err.
|
||||
*/
|
||||
if (!flow_offload_has_one_action(&fl_act->action))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (esw && esw->mode == MLX5_ESWITCH_OFFLOADS)
|
||||
ns_type = MLX5_FLOW_NAMESPACE_FDB;
|
||||
else
|
||||
ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
|
||||
|
||||
flow_action_for_each(i, action, &fl_act->action) {
|
||||
act = mlx5e_tc_act_get(action->id, ns_type);
|
||||
if (!act)
|
||||
continue;
|
||||
|
||||
if (!act->offload_action)
|
||||
continue;
|
||||
|
||||
if (!act->offload_action(priv, fl_act, action))
|
||||
add = true;
|
||||
}
|
||||
|
||||
return add ? 0 : -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5e_rep_indr_destroy_act(struct mlx5e_rep_priv *rpriv,
|
||||
struct flow_offload_action *fl_act)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
|
||||
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
|
||||
enum mlx5_flow_namespace_type ns_type;
|
||||
struct mlx5e_tc_act *act;
|
||||
|
||||
if (esw && esw->mode == MLX5_ESWITCH_OFFLOADS)
|
||||
ns_type = MLX5_FLOW_NAMESPACE_FDB;
|
||||
else
|
||||
ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
|
||||
|
||||
act = mlx5e_tc_act_get(fl_act->id, ns_type);
|
||||
if (!act || !act->destroy_action)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return act->destroy_action(priv, fl_act);
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5e_rep_indr_stats_act(struct mlx5e_rep_priv *rpriv,
|
||||
struct flow_offload_action *fl_act)
|
||||
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
|
||||
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
|
||||
enum mlx5_flow_namespace_type ns_type;
|
||||
struct mlx5e_tc_act *act;
|
||||
|
||||
if (esw && esw->mode == MLX5_ESWITCH_OFFLOADS)
|
||||
ns_type = MLX5_FLOW_NAMESPACE_FDB;
|
||||
else
|
||||
ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
|
||||
|
||||
act = mlx5e_tc_act_get(fl_act->id, ns_type);
|
||||
if (!act || !act->stats_action)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return act->stats_action(priv, fl_act);
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5e_rep_indr_setup_act(struct mlx5e_rep_priv *rpriv,
|
||||
struct flow_offload_action *fl_act)
|
||||
{
|
||||
switch (fl_act->command) {
|
||||
case FLOW_ACT_REPLACE:
|
||||
return mlx5e_rep_indr_replace_act(rpriv, fl_act);
|
||||
case FLOW_ACT_DESTROY:
|
||||
return mlx5e_rep_indr_destroy_act(rpriv, fl_act);
|
||||
case FLOW_ACT_STATS:
|
||||
return mlx5e_rep_indr_stats_act(rpriv, fl_act);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5e_rep_indr_no_dev_setup(struct mlx5e_rep_priv *rpriv,
|
||||
enum tc_setup_type type,
|
||||
void *data)
|
||||
{
|
||||
if (!data)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (type) {
|
||||
case TC_SETUP_ACT:
|
||||
return mlx5e_rep_indr_setup_act(rpriv, data);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int mlx5e_rep_indr_setup_cb(struct net_device *netdev, struct Qdisc *sch, void *cb_priv,
|
||||
enum tc_setup_type type, void *type_data,
|
||||
@ -518,7 +633,7 @@ int mlx5e_rep_indr_setup_cb(struct net_device *netdev, struct Qdisc *sch, void *
|
||||
void (*cleanup)(struct flow_block_cb *block_cb))
|
||||
{
|
||||
if (!netdev)
|
||||
return -EOPNOTSUPP;
|
||||
return mlx5e_rep_indr_no_dev_setup(cb_priv, type, data);
|
||||
|
||||
switch (type) {
|
||||
case TC_SETUP_BLOCK:
|
||||
|
@ -50,6 +50,16 @@ struct mlx5e_tc_act {
|
||||
bool (*is_multi_table_act)(struct mlx5e_priv *priv,
|
||||
const struct flow_action_entry *act,
|
||||
struct mlx5_flow_attr *attr);
|
||||
|
||||
int (*offload_action)(struct mlx5e_priv *priv,
|
||||
struct flow_offload_action *fl_act,
|
||||
struct flow_action_entry *act);
|
||||
|
||||
int (*destroy_action)(struct mlx5e_priv *priv,
|
||||
struct flow_offload_action *fl_act);
|
||||
|
||||
int (*stats_action)(struct mlx5e_priv *priv,
|
||||
struct flow_offload_action *fl_act);
|
||||
};
|
||||
|
||||
struct mlx5e_tc_flow_action {
|
||||
|
@ -24,14 +24,9 @@ tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
|
||||
}
|
||||
|
||||
static int
|
||||
tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
|
||||
const struct flow_action_entry *act,
|
||||
struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_attr *attr)
|
||||
fill_meter_params_from_act(const struct flow_action_entry *act,
|
||||
struct mlx5e_flow_meter_params *params)
|
||||
{
|
||||
struct mlx5e_flow_meter_params *params;
|
||||
|
||||
params = &attr->meter_attr.params;
|
||||
params->index = act->hw_index;
|
||||
if (act->police.rate_bytes_ps) {
|
||||
params->mode = MLX5_RATE_LIMIT_BPS;
|
||||
@ -46,6 +41,21 @@ tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
|
||||
const struct flow_action_entry *act,
|
||||
struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_attr *attr)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fill_meter_params_from_act(act, &attr->meter_attr.params);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
|
||||
attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
|
||||
|
||||
@ -60,8 +70,84 @@ tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
tc_act_police_offload(struct mlx5e_priv *priv,
|
||||
struct flow_offload_action *fl_act,
|
||||
struct flow_action_entry *act)
|
||||
{
|
||||
struct mlx5e_flow_meter_params params = {};
|
||||
struct mlx5e_flow_meter_handle *meter;
|
||||
int err = 0;
|
||||
|
||||
err = fill_meter_params_from_act(act, ¶ms);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
|
||||
if (IS_ERR(meter) && PTR_ERR(meter) == -ENOENT) {
|
||||
meter = mlx5e_tc_meter_replace(priv->mdev, ¶ms);
|
||||
} else if (!IS_ERR(meter)) {
|
||||
err = mlx5e_tc_meter_update(meter, ¶ms);
|
||||
mlx5e_tc_meter_put(meter);
|
||||
}
|
||||
|
||||
if (IS_ERR(meter)) {
|
||||
NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
|
||||
mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
|
||||
err = PTR_ERR(meter);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
tc_act_police_destroy(struct mlx5e_priv *priv,
|
||||
struct flow_offload_action *fl_act)
|
||||
{
|
||||
struct mlx5e_flow_meter_params params = {};
|
||||
struct mlx5e_flow_meter_handle *meter;
|
||||
|
||||
params.index = fl_act->index;
|
||||
meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
|
||||
if (IS_ERR(meter)) {
|
||||
NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
|
||||
mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
|
||||
return PTR_ERR(meter);
|
||||
}
|
||||
/* first put for the get and second for cleanup */
|
||||
mlx5e_tc_meter_put(meter);
|
||||
mlx5e_tc_meter_put(meter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tc_act_police_stats(struct mlx5e_priv *priv,
|
||||
struct flow_offload_action *fl_act)
|
||||
{
|
||||
struct mlx5e_flow_meter_params params = {};
|
||||
struct mlx5e_flow_meter_handle *meter;
|
||||
u64 bytes, packets, drops, lastuse;
|
||||
|
||||
params.index = fl_act->index;
|
||||
meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
|
||||
if (IS_ERR(meter)) {
|
||||
NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
|
||||
mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
|
||||
return PTR_ERR(meter);
|
||||
}
|
||||
|
||||
mlx5e_tc_meter_get_stats(meter, &bytes, &packets, &drops, &lastuse);
|
||||
flow_stats_update(&fl_act->stats, bytes, packets, drops, lastuse,
|
||||
FLOW_ACTION_HW_STATS_DELAYED);
|
||||
mlx5e_tc_meter_put(meter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mlx5e_tc_act mlx5e_tc_act_police = {
|
||||
.can_offload = tc_act_can_offload_police,
|
||||
.parse_action = tc_act_parse_police,
|
||||
.is_multi_table_act = tc_act_is_multi_table_act_police,
|
||||
.offload_action = tc_act_police_offload,
|
||||
.destroy_action = tc_act_police_destroy,
|
||||
.stats_action = tc_act_police_stats,
|
||||
};
|
||||
|
@ -561,3 +561,19 @@ mlx5e_flow_meters_cleanup(struct mlx5e_flow_meters *flow_meters)
|
||||
mlx5_core_dealloc_pd(flow_meters->mdev, flow_meters->pdn);
|
||||
kfree(flow_meters);
|
||||
}
|
||||
|
||||
void
|
||||
mlx5e_tc_meter_get_stats(struct mlx5e_flow_meter_handle *meter,
|
||||
u64 *bytes, u64 *packets, u64 *drops, u64 *lastuse)
|
||||
{
|
||||
u64 bytes1, packets1, lastuse1;
|
||||
u64 bytes2, packets2, lastuse2;
|
||||
|
||||
mlx5_fc_query_cached(meter->green_counter, &bytes1, &packets1, &lastuse1);
|
||||
mlx5_fc_query_cached(meter->red_counter, &bytes2, &packets2, &lastuse2);
|
||||
|
||||
*bytes = bytes1 + bytes2;
|
||||
*packets = packets1 + packets2;
|
||||
*drops = packets2;
|
||||
*lastuse = max_t(u64, lastuse1, lastuse2);
|
||||
}
|
||||
|
@ -67,4 +67,8 @@ mlx5e_flow_meters_init(struct mlx5e_priv *priv,
|
||||
void
|
||||
mlx5e_flow_meters_cleanup(struct mlx5e_flow_meters *flow_meters);
|
||||
|
||||
void
|
||||
mlx5e_tc_meter_get_stats(struct mlx5e_flow_meter_handle *meter,
|
||||
u64 *bytes, u64 *packets, u64 *drops, u64 *lastuse);
|
||||
|
||||
#endif /* __MLX5_EN_FLOW_METER_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user