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

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
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -689,8 +689,10 @@ struct mlxsw_sp_acl_rule_info {
	u8 action_created:1,
	   ingress_bind_blocker:1,
	   egress_bind_blocker:1,
	   counter_valid:1;
	   counter_valid:1,
	   policer_index_valid:1;
	unsigned int counter_index;
	u16 policer_index;
};

/* spectrum_flow.c */
@@ -851,6 +853,10 @@ int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
				  enum flow_action_mangle_base htype,
				  u32 offset, u32 mask, u32 val,
				  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,
				 struct mlxsw_sp_acl_rule_info *rulei,
				 struct netlink_ext_ack *extack);
@@ -883,7 +889,8 @@ struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule);
int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
				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);

struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp);
+32 −1
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ struct mlxsw_sp_acl_rule {
	u64 last_used;
	u64 last_packets;
	u64 last_bytes;
	u64 last_drops;
	unsigned long priv[];
	/* priv has to be always the last item */
};
@@ -648,6 +649,24 @@ int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
	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,
				 struct mlxsw_sp_acl_rule_info *rulei,
				 struct netlink_ext_ack *extack)
@@ -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,
				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 mlxsw_sp_policer_type type = MLXSW_SP_POLICER_TYPE_SINGLE_RATE;
	struct mlxsw_sp_acl_rule_info *rulei;
	u64 current_packets = 0;
	u64 current_bytes = 0;
	u64 current_drops = 0;
	int err;

	rulei = mlxsw_sp_acl_rule_rulei(rule);
@@ -886,12 +908,21 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
			return err;
		*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;
	*bytes = current_bytes - rule->last_bytes;
	*drops = current_drops - rule->last_drops;
	*last_use = rule->last_used;

	rule->last_bytes = current_bytes;
	rule->last_packets = current_packets;
	rule->last_drops = current_drops;

	return 0;
}
+27 −0
Original line number Diff line number Diff line
@@ -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);
}

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 = {
	.kvdl_set_add		= mlxsw_sp1_act_kvdl_set_add,
	.kvdl_set_del		= mlxsw_sp_act_kvdl_set_del,
@@ -179,6 +202,8 @@ const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = {
	.counter_index_put	= mlxsw_sp_act_counter_index_put,
	.mirror_add		= mlxsw_sp_act_mirror_add,
	.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 = {
@@ -191,6 +216,8 @@ const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = {
	.counter_index_put	= mlxsw_sp_act_counter_index_put,
	.mirror_add		= mlxsw_sp_act_mirror_add,
	.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,
};

+28 −2
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/log2.h>
#include <net/net_namespace.h>
#include <net/flow_dissector.h>
#include <net/pkt_cls.h>
@@ -22,6 +23,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
{
	const struct flow_action_entry *act;
	int mirror_act_count = 0;
	int police_act_count = 0;
	int err, i;

	if (!flow_action_has_entries(flow_action))
@@ -180,6 +182,28 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
				return err;
			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:
			NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
			dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");
@@ -616,6 +640,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
	u64 packets;
	u64 lastuse;
	u64 bytes;
	u64 drops;
	int err;

	ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block,
@@ -629,11 +654,12 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
		return -EINVAL;

	err = mlxsw_sp_acl_rule_get_stats(mlxsw_sp, rule, &packets, &bytes,
					  &lastuse, &used_hw_stats);
					  &drops, &lastuse, &used_hw_stats);
	if (err)
		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);
	return 0;