Commit af11e818 authored by Ido Schimmel's avatar Ido Schimmel Committed by Jakub Kicinski

mlxsw: spectrum_acl: Offload FLOW_ACTION_POLICE

Offload action police when used with a flower classifier. The number of
dropped packets is read from the policer and reported to tc.
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Reviewed-by: default avatarJiri Pirko <jiri@mellanox.com>
Reviewed-by: default avatarPetr Machata <petrm@mellanox.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent deee0abc
...@@ -689,8 +689,10 @@ struct mlxsw_sp_acl_rule_info { ...@@ -689,8 +689,10 @@ struct mlxsw_sp_acl_rule_info {
u8 action_created:1, u8 action_created:1,
ingress_bind_blocker:1, ingress_bind_blocker:1,
egress_bind_blocker:1, egress_bind_blocker:1,
counter_valid:1; counter_valid:1,
policer_index_valid:1;
unsigned int counter_index; unsigned int counter_index;
u16 policer_index;
}; };
/* spectrum_flow.c */ /* spectrum_flow.c */
...@@ -851,6 +853,10 @@ int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp, ...@@ -851,6 +853,10 @@ int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
enum flow_action_mangle_base htype, enum flow_action_mangle_base htype,
u32 offset, u32 mask, u32 val, u32 offset, u32 mask, u32 val,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int mlxsw_sp_acl_rulei_act_police(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u32 index, u64 rate_bytes_ps,
u32 burst, struct netlink_ext_ack *extack);
int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp, int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei, struct mlxsw_sp_acl_rule_info *rulei,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
...@@ -883,7 +889,8 @@ struct mlxsw_sp_acl_rule_info * ...@@ -883,7 +889,8 @@ struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule); mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule);
int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule *rule, struct mlxsw_sp_acl_rule *rule,
u64 *packets, u64 *bytes, u64 *last_use, u64 *packets, u64 *bytes, u64 *drops,
u64 *last_use,
enum flow_action_hw_stats *used_hw_stats); enum flow_action_hw_stats *used_hw_stats);
struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp); struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp);
......
...@@ -66,6 +66,7 @@ struct mlxsw_sp_acl_rule { ...@@ -66,6 +66,7 @@ struct mlxsw_sp_acl_rule {
u64 last_used; u64 last_used;
u64 last_packets; u64 last_packets;
u64 last_bytes; u64 last_bytes;
u64 last_drops;
unsigned long priv[]; unsigned long priv[];
/* priv has to be always the last item */ /* priv has to be always the last item */
}; };
...@@ -648,6 +649,24 @@ int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp, ...@@ -648,6 +649,24 @@ int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
return -EINVAL; return -EINVAL;
} }
int mlxsw_sp_acl_rulei_act_police(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u32 index, u64 rate_bytes_ps,
u32 burst, struct netlink_ext_ack *extack)
{
int err;
err = mlxsw_afa_block_append_police(rulei->act_block, index,
rate_bytes_ps, burst,
&rulei->policer_index, extack);
if (err)
return err;
rulei->policer_index_valid = true;
return 0;
}
int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp, int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei, struct mlxsw_sp_acl_rule_info *rulei,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -868,13 +887,16 @@ static void mlxsw_sp_acl_rule_activity_update_work(struct work_struct *work) ...@@ -868,13 +887,16 @@ static void mlxsw_sp_acl_rule_activity_update_work(struct work_struct *work)
int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule *rule, struct mlxsw_sp_acl_rule *rule,
u64 *packets, u64 *bytes, u64 *last_use, u64 *packets, u64 *bytes, u64 *drops,
u64 *last_use,
enum flow_action_hw_stats *used_hw_stats) enum flow_action_hw_stats *used_hw_stats)
{ {
enum mlxsw_sp_policer_type type = MLXSW_SP_POLICER_TYPE_SINGLE_RATE;
struct mlxsw_sp_acl_rule_info *rulei; struct mlxsw_sp_acl_rule_info *rulei;
u64 current_packets = 0; u64 current_packets = 0;
u64 current_bytes = 0; u64 current_bytes = 0;
u64 current_drops = 0;
int err; int err;
rulei = mlxsw_sp_acl_rule_rulei(rule); rulei = mlxsw_sp_acl_rule_rulei(rule);
...@@ -886,12 +908,21 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, ...@@ -886,12 +908,21 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
return err; return err;
*used_hw_stats = FLOW_ACTION_HW_STATS_IMMEDIATE; *used_hw_stats = FLOW_ACTION_HW_STATS_IMMEDIATE;
} }
if (rulei->policer_index_valid) {
err = mlxsw_sp_policer_drops_counter_get(mlxsw_sp, type,
rulei->policer_index,
&current_drops);
if (err)
return err;
}
*packets = current_packets - rule->last_packets; *packets = current_packets - rule->last_packets;
*bytes = current_bytes - rule->last_bytes; *bytes = current_bytes - rule->last_bytes;
*drops = current_drops - rule->last_drops;
*last_use = rule->last_used; *last_use = rule->last_used;
rule->last_bytes = current_bytes; rule->last_bytes = current_bytes;
rule->last_packets = current_packets; rule->last_packets = current_packets;
rule->last_drops = current_drops;
return 0; return 0;
} }
......
...@@ -169,6 +169,29 @@ mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, int span_id, bool ingress) ...@@ -169,6 +169,29 @@ mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, int span_id, bool ingress)
mlxsw_sp_span_agent_put(mlxsw_sp, span_id); mlxsw_sp_span_agent_put(mlxsw_sp, span_id);
} }
static int mlxsw_sp_act_policer_add(void *priv, u64 rate_bytes_ps, u32 burst,
u16 *p_policer_index,
struct netlink_ext_ack *extack)
{
struct mlxsw_sp_policer_params params;
struct mlxsw_sp *mlxsw_sp = priv;
params.rate = rate_bytes_ps;
params.burst = burst;
params.bytes = true;
return mlxsw_sp_policer_add(mlxsw_sp,
MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
&params, extack, p_policer_index);
}
static void mlxsw_sp_act_policer_del(void *priv, u16 policer_index)
{
struct mlxsw_sp *mlxsw_sp = priv;
mlxsw_sp_policer_del(mlxsw_sp, MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
policer_index);
}
const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = {
.kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add,
.kvdl_set_del = mlxsw_sp_act_kvdl_set_del, .kvdl_set_del = mlxsw_sp_act_kvdl_set_del,
...@@ -179,6 +202,8 @@ const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { ...@@ -179,6 +202,8 @@ const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = {
.counter_index_put = mlxsw_sp_act_counter_index_put, .counter_index_put = mlxsw_sp_act_counter_index_put,
.mirror_add = mlxsw_sp_act_mirror_add, .mirror_add = mlxsw_sp_act_mirror_add,
.mirror_del = mlxsw_sp_act_mirror_del, .mirror_del = mlxsw_sp_act_mirror_del,
.policer_add = mlxsw_sp_act_policer_add,
.policer_del = mlxsw_sp_act_policer_del,
}; };
const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = {
...@@ -191,6 +216,8 @@ const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { ...@@ -191,6 +216,8 @@ const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = {
.counter_index_put = mlxsw_sp_act_counter_index_put, .counter_index_put = mlxsw_sp_act_counter_index_put,
.mirror_add = mlxsw_sp_act_mirror_add, .mirror_add = mlxsw_sp_act_mirror_add,
.mirror_del = mlxsw_sp_act_mirror_del, .mirror_del = mlxsw_sp_act_mirror_del,
.policer_add = mlxsw_sp_act_policer_add,
.policer_del = mlxsw_sp_act_policer_del,
.dummy_first_set = true, .dummy_first_set = true,
}; };
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/log2.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/flow_dissector.h> #include <net/flow_dissector.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
...@@ -22,6 +23,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, ...@@ -22,6 +23,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
{ {
const struct flow_action_entry *act; const struct flow_action_entry *act;
int mirror_act_count = 0; int mirror_act_count = 0;
int police_act_count = 0;
int err, i; int err, i;
if (!flow_action_has_entries(flow_action)) if (!flow_action_has_entries(flow_action))
...@@ -180,6 +182,28 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, ...@@ -180,6 +182,28 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
return err; return err;
break; break;
} }
case FLOW_ACTION_POLICE: {
u32 burst;
if (police_act_count++) {
NL_SET_ERR_MSG_MOD(extack, "Multiple police actions per rule are not supported");
return -EOPNOTSUPP;
}
/* The kernel might adjust the requested burst size so
* that it is not exactly a power of two. Re-adjust it
* here since the hardware only supports burst sizes
* that are a power of two.
*/
burst = roundup_pow_of_two(act->police.burst);
err = mlxsw_sp_acl_rulei_act_police(mlxsw_sp, rulei,
act->police.index,
act->police.rate_bytes_ps,
burst, extack);
if (err)
return err;
break;
}
default: default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported action"); NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n"); dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");
...@@ -616,6 +640,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp, ...@@ -616,6 +640,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
u64 packets; u64 packets;
u64 lastuse; u64 lastuse;
u64 bytes; u64 bytes;
u64 drops;
int err; int err;
ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block,
...@@ -629,11 +654,12 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp, ...@@ -629,11 +654,12 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
return -EINVAL; return -EINVAL;
err = mlxsw_sp_acl_rule_get_stats(mlxsw_sp, rule, &packets, &bytes, err = mlxsw_sp_acl_rule_get_stats(mlxsw_sp, rule, &packets, &bytes,
&lastuse, &used_hw_stats); &drops, &lastuse, &used_hw_stats);
if (err) if (err)
goto err_rule_get_stats; goto err_rule_get_stats;
flow_stats_update(&f->stats, bytes, packets, 0, lastuse, used_hw_stats); flow_stats_update(&f->stats, bytes, packets, drops, lastuse,
used_hw_stats);
mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
return 0; return 0;
......
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