18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/kernel.h>
58c2ecf20Sopenharmony_ci#include <linux/slab.h>
68c2ecf20Sopenharmony_ci#include <linux/errno.h>
78c2ecf20Sopenharmony_ci#include <linux/list.h>
88c2ecf20Sopenharmony_ci#include <linux/string.h>
98c2ecf20Sopenharmony_ci#include <linux/rhashtable.h>
108c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
118c2ecf20Sopenharmony_ci#include <linux/mutex.h>
128c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
138c2ecf20Sopenharmony_ci#include <net/tc_act/tc_vlan.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "reg.h"
168c2ecf20Sopenharmony_ci#include "core.h"
178c2ecf20Sopenharmony_ci#include "resources.h"
188c2ecf20Sopenharmony_ci#include "spectrum.h"
198c2ecf20Sopenharmony_ci#include "core_acl_flex_keys.h"
208c2ecf20Sopenharmony_ci#include "core_acl_flex_actions.h"
218c2ecf20Sopenharmony_ci#include "spectrum_acl_tcam.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct mlxsw_sp_acl {
248c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp;
258c2ecf20Sopenharmony_ci	struct mlxsw_afk *afk;
268c2ecf20Sopenharmony_ci	struct mlxsw_sp_fid *dummy_fid;
278c2ecf20Sopenharmony_ci	struct rhashtable ruleset_ht;
288c2ecf20Sopenharmony_ci	struct list_head rules;
298c2ecf20Sopenharmony_ci	struct mutex rules_lock; /* Protects rules list */
308c2ecf20Sopenharmony_ci	struct {
318c2ecf20Sopenharmony_ci		struct delayed_work dw;
328c2ecf20Sopenharmony_ci		unsigned long interval;	/* ms */
338c2ecf20Sopenharmony_ci#define MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS 1000
348c2ecf20Sopenharmony_ci	} rule_activity_update;
358c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_tcam tcam;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return acl->afk;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_ruleset_ht_key {
448c2ecf20Sopenharmony_ci	struct mlxsw_sp_flow_block *block;
458c2ecf20Sopenharmony_ci	u32 chain_index;
468c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_ruleset {
508c2ecf20Sopenharmony_ci	struct rhash_head ht_node; /* Member of acl HT */
518c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset_ht_key ht_key;
528c2ecf20Sopenharmony_ci	struct rhashtable rule_ht;
538c2ecf20Sopenharmony_ci	unsigned int ref_count;
548c2ecf20Sopenharmony_ci	unsigned int min_prio;
558c2ecf20Sopenharmony_ci	unsigned int max_prio;
568c2ecf20Sopenharmony_ci	unsigned long priv[];
578c2ecf20Sopenharmony_ci	/* priv has to be always the last item */
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rule {
618c2ecf20Sopenharmony_ci	struct rhash_head ht_node; /* Member of rule HT */
628c2ecf20Sopenharmony_ci	struct list_head list;
638c2ecf20Sopenharmony_ci	unsigned long cookie; /* HT key */
648c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset;
658c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_rule_info *rulei;
668c2ecf20Sopenharmony_ci	u64 last_used;
678c2ecf20Sopenharmony_ci	u64 last_packets;
688c2ecf20Sopenharmony_ci	u64 last_bytes;
698c2ecf20Sopenharmony_ci	u64 last_drops;
708c2ecf20Sopenharmony_ci	unsigned long priv[];
718c2ecf20Sopenharmony_ci	/* priv has to be always the last item */
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_acl_ruleset_ht_params = {
758c2ecf20Sopenharmony_ci	.key_len = sizeof(struct mlxsw_sp_acl_ruleset_ht_key),
768c2ecf20Sopenharmony_ci	.key_offset = offsetof(struct mlxsw_sp_acl_ruleset, ht_key),
778c2ecf20Sopenharmony_ci	.head_offset = offsetof(struct mlxsw_sp_acl_ruleset, ht_node),
788c2ecf20Sopenharmony_ci	.automatic_shrinking = true,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_acl_rule_ht_params = {
828c2ecf20Sopenharmony_ci	.key_len = sizeof(unsigned long),
838c2ecf20Sopenharmony_ci	.key_offset = offsetof(struct mlxsw_sp_acl_rule, cookie),
848c2ecf20Sopenharmony_ci	.head_offset = offsetof(struct mlxsw_sp_acl_rule, ht_node),
858c2ecf20Sopenharmony_ci	.automatic_shrinking = true,
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	return mlxsw_sp->acl->dummy_fid;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic bool
948c2ecf20Sopenharmony_cimlxsw_sp_acl_ruleset_is_singular(const struct mlxsw_sp_acl_ruleset *ruleset)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	/* We hold a reference on ruleset ourselves */
978c2ecf20Sopenharmony_ci	return ruleset->ref_count == 2;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciint mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp,
1018c2ecf20Sopenharmony_ci			      struct mlxsw_sp_flow_block *block,
1028c2ecf20Sopenharmony_ci			      struct mlxsw_sp_flow_block_binding *binding)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = block->ruleset_zero;
1058c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return ops->ruleset_bind(mlxsw_sp, ruleset->priv,
1088c2ecf20Sopenharmony_ci				 binding->mlxsw_sp_port, binding->ingress);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_civoid mlxsw_sp_acl_ruleset_unbind(struct mlxsw_sp *mlxsw_sp,
1128c2ecf20Sopenharmony_ci				 struct mlxsw_sp_flow_block *block,
1138c2ecf20Sopenharmony_ci				 struct mlxsw_sp_flow_block_binding *binding)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = block->ruleset_zero;
1168c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	ops->ruleset_unbind(mlxsw_sp, ruleset->priv,
1198c2ecf20Sopenharmony_ci			    binding->mlxsw_sp_port, binding->ingress);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int
1238c2ecf20Sopenharmony_cimlxsw_sp_acl_ruleset_block_bind(struct mlxsw_sp *mlxsw_sp,
1248c2ecf20Sopenharmony_ci				struct mlxsw_sp_acl_ruleset *ruleset,
1258c2ecf20Sopenharmony_ci				struct mlxsw_sp_flow_block *block)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct mlxsw_sp_flow_block_binding *binding;
1288c2ecf20Sopenharmony_ci	int err;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	block->ruleset_zero = ruleset;
1318c2ecf20Sopenharmony_ci	list_for_each_entry(binding, &block->binding_list, list) {
1328c2ecf20Sopenharmony_ci		err = mlxsw_sp_acl_ruleset_bind(mlxsw_sp, block, binding);
1338c2ecf20Sopenharmony_ci		if (err)
1348c2ecf20Sopenharmony_ci			goto rollback;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cirollback:
1398c2ecf20Sopenharmony_ci	list_for_each_entry_continue_reverse(binding, &block->binding_list,
1408c2ecf20Sopenharmony_ci					     list)
1418c2ecf20Sopenharmony_ci		mlxsw_sp_acl_ruleset_unbind(mlxsw_sp, block, binding);
1428c2ecf20Sopenharmony_ci	block->ruleset_zero = NULL;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return err;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void
1488c2ecf20Sopenharmony_cimlxsw_sp_acl_ruleset_block_unbind(struct mlxsw_sp *mlxsw_sp,
1498c2ecf20Sopenharmony_ci				  struct mlxsw_sp_acl_ruleset *ruleset,
1508c2ecf20Sopenharmony_ci				  struct mlxsw_sp_flow_block *block)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct mlxsw_sp_flow_block_binding *binding;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	list_for_each_entry(binding, &block->binding_list, list)
1558c2ecf20Sopenharmony_ci		mlxsw_sp_acl_ruleset_unbind(mlxsw_sp, block, binding);
1568c2ecf20Sopenharmony_ci	block->ruleset_zero = NULL;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic struct mlxsw_sp_acl_ruleset *
1608c2ecf20Sopenharmony_cimlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp,
1618c2ecf20Sopenharmony_ci			    struct mlxsw_sp_flow_block *block, u32 chain_index,
1628c2ecf20Sopenharmony_ci			    const struct mlxsw_sp_acl_profile_ops *ops,
1638c2ecf20Sopenharmony_ci			    struct mlxsw_afk_element_usage *tmplt_elusage)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
1668c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset;
1678c2ecf20Sopenharmony_ci	size_t alloc_size;
1688c2ecf20Sopenharmony_ci	int err;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	alloc_size = sizeof(*ruleset) + ops->ruleset_priv_size;
1718c2ecf20Sopenharmony_ci	ruleset = kzalloc(alloc_size, GFP_KERNEL);
1728c2ecf20Sopenharmony_ci	if (!ruleset)
1738c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1748c2ecf20Sopenharmony_ci	ruleset->ref_count = 1;
1758c2ecf20Sopenharmony_ci	ruleset->ht_key.block = block;
1768c2ecf20Sopenharmony_ci	ruleset->ht_key.chain_index = chain_index;
1778c2ecf20Sopenharmony_ci	ruleset->ht_key.ops = ops;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	err = rhashtable_init(&ruleset->rule_ht, &mlxsw_sp_acl_rule_ht_params);
1808c2ecf20Sopenharmony_ci	if (err)
1818c2ecf20Sopenharmony_ci		goto err_rhashtable_init;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	err = ops->ruleset_add(mlxsw_sp, &acl->tcam, ruleset->priv,
1848c2ecf20Sopenharmony_ci			       tmplt_elusage, &ruleset->min_prio,
1858c2ecf20Sopenharmony_ci			       &ruleset->max_prio);
1868c2ecf20Sopenharmony_ci	if (err)
1878c2ecf20Sopenharmony_ci		goto err_ops_ruleset_add;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node,
1908c2ecf20Sopenharmony_ci				     mlxsw_sp_acl_ruleset_ht_params);
1918c2ecf20Sopenharmony_ci	if (err)
1928c2ecf20Sopenharmony_ci		goto err_ht_insert;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return ruleset;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cierr_ht_insert:
1978c2ecf20Sopenharmony_ci	ops->ruleset_del(mlxsw_sp, ruleset->priv);
1988c2ecf20Sopenharmony_cierr_ops_ruleset_add:
1998c2ecf20Sopenharmony_ci	rhashtable_destroy(&ruleset->rule_ht);
2008c2ecf20Sopenharmony_cierr_rhashtable_init:
2018c2ecf20Sopenharmony_ci	kfree(ruleset);
2028c2ecf20Sopenharmony_ci	return ERR_PTR(err);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp *mlxsw_sp,
2068c2ecf20Sopenharmony_ci					 struct mlxsw_sp_acl_ruleset *ruleset)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
2098c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node,
2128c2ecf20Sopenharmony_ci			       mlxsw_sp_acl_ruleset_ht_params);
2138c2ecf20Sopenharmony_ci	ops->ruleset_del(mlxsw_sp, ruleset->priv);
2148c2ecf20Sopenharmony_ci	rhashtable_destroy(&ruleset->rule_ht);
2158c2ecf20Sopenharmony_ci	kfree(ruleset);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic void mlxsw_sp_acl_ruleset_ref_inc(struct mlxsw_sp_acl_ruleset *ruleset)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	ruleset->ref_count++;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp,
2248c2ecf20Sopenharmony_ci					 struct mlxsw_sp_acl_ruleset *ruleset)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	if (--ruleset->ref_count)
2278c2ecf20Sopenharmony_ci		return;
2288c2ecf20Sopenharmony_ci	mlxsw_sp_acl_ruleset_destroy(mlxsw_sp, ruleset);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic struct mlxsw_sp_acl_ruleset *
2328c2ecf20Sopenharmony_ci__mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp_acl *acl,
2338c2ecf20Sopenharmony_ci			      struct mlxsw_sp_flow_block *block, u32 chain_index,
2348c2ecf20Sopenharmony_ci			      const struct mlxsw_sp_acl_profile_ops *ops)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset_ht_key ht_key;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	memset(&ht_key, 0, sizeof(ht_key));
2398c2ecf20Sopenharmony_ci	ht_key.block = block;
2408c2ecf20Sopenharmony_ci	ht_key.chain_index = chain_index;
2418c2ecf20Sopenharmony_ci	ht_key.ops = ops;
2428c2ecf20Sopenharmony_ci	return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
2438c2ecf20Sopenharmony_ci				      mlxsw_sp_acl_ruleset_ht_params);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_ruleset *
2478c2ecf20Sopenharmony_cimlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp,
2488c2ecf20Sopenharmony_ci			    struct mlxsw_sp_flow_block *block, u32 chain_index,
2498c2ecf20Sopenharmony_ci			    enum mlxsw_sp_acl_profile profile)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops;
2528c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
2538c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	ops = mlxsw_sp_acl_tcam_profile_ops(mlxsw_sp, profile);
2568c2ecf20Sopenharmony_ci	if (!ops)
2578c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2588c2ecf20Sopenharmony_ci	ruleset = __mlxsw_sp_acl_ruleset_lookup(acl, block, chain_index, ops);
2598c2ecf20Sopenharmony_ci	if (!ruleset)
2608c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOENT);
2618c2ecf20Sopenharmony_ci	return ruleset;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_ruleset *
2658c2ecf20Sopenharmony_cimlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
2668c2ecf20Sopenharmony_ci			 struct mlxsw_sp_flow_block *block, u32 chain_index,
2678c2ecf20Sopenharmony_ci			 enum mlxsw_sp_acl_profile profile,
2688c2ecf20Sopenharmony_ci			 struct mlxsw_afk_element_usage *tmplt_elusage)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops;
2718c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
2728c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ops = mlxsw_sp_acl_tcam_profile_ops(mlxsw_sp, profile);
2758c2ecf20Sopenharmony_ci	if (!ops)
2768c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	ruleset = __mlxsw_sp_acl_ruleset_lookup(acl, block, chain_index, ops);
2798c2ecf20Sopenharmony_ci	if (ruleset) {
2808c2ecf20Sopenharmony_ci		mlxsw_sp_acl_ruleset_ref_inc(ruleset);
2818c2ecf20Sopenharmony_ci		return ruleset;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci	return mlxsw_sp_acl_ruleset_create(mlxsw_sp, block, chain_index, ops,
2848c2ecf20Sopenharmony_ci					   tmplt_elusage);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_civoid mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
2888c2ecf20Sopenharmony_ci			      struct mlxsw_sp_acl_ruleset *ruleset)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ciu16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return ops->ruleset_group_id(ruleset->priv);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_civoid mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
3018c2ecf20Sopenharmony_ci				   unsigned int *p_min_prio,
3028c2ecf20Sopenharmony_ci				   unsigned int *p_max_prio)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	*p_min_prio = ruleset->min_prio;
3058c2ecf20Sopenharmony_ci	*p_max_prio = ruleset->max_prio;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rule_info *
3098c2ecf20Sopenharmony_cimlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
3108c2ecf20Sopenharmony_ci			  struct mlxsw_afa_block *afa_block)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_rule_info *rulei;
3138c2ecf20Sopenharmony_ci	int err;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	rulei = kzalloc(sizeof(*rulei), GFP_KERNEL);
3168c2ecf20Sopenharmony_ci	if (!rulei)
3178c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (afa_block) {
3208c2ecf20Sopenharmony_ci		rulei->act_block = afa_block;
3218c2ecf20Sopenharmony_ci		return rulei;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	rulei->act_block = mlxsw_afa_block_create(acl->mlxsw_sp->afa);
3258c2ecf20Sopenharmony_ci	if (IS_ERR(rulei->act_block)) {
3268c2ecf20Sopenharmony_ci		err = PTR_ERR(rulei->act_block);
3278c2ecf20Sopenharmony_ci		goto err_afa_block_create;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci	rulei->action_created = 1;
3308c2ecf20Sopenharmony_ci	return rulei;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cierr_afa_block_create:
3338c2ecf20Sopenharmony_ci	kfree(rulei);
3348c2ecf20Sopenharmony_ci	return ERR_PTR(err);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_civoid mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info *rulei)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	if (rulei->action_created)
3408c2ecf20Sopenharmony_ci		mlxsw_afa_block_destroy(rulei->act_block);
3418c2ecf20Sopenharmony_ci	kfree(rulei);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	return mlxsw_afa_block_commit(rulei->act_block);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_civoid mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info *rulei,
3508c2ecf20Sopenharmony_ci				 unsigned int priority)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	rulei->priority = priority;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_civoid mlxsw_sp_acl_rulei_keymask_u32(struct mlxsw_sp_acl_rule_info *rulei,
3568c2ecf20Sopenharmony_ci				    enum mlxsw_afk_element element,
3578c2ecf20Sopenharmony_ci				    u32 key_value, u32 mask_value)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	mlxsw_afk_values_add_u32(&rulei->values, element,
3608c2ecf20Sopenharmony_ci				 key_value, mask_value);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_civoid mlxsw_sp_acl_rulei_keymask_buf(struct mlxsw_sp_acl_rule_info *rulei,
3648c2ecf20Sopenharmony_ci				    enum mlxsw_afk_element element,
3658c2ecf20Sopenharmony_ci				    const char *key_value,
3668c2ecf20Sopenharmony_ci				    const char *mask_value, unsigned int len)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	mlxsw_afk_values_add_buf(&rulei->values, element,
3698c2ecf20Sopenharmony_ci				 key_value, mask_value, len);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	return mlxsw_afa_block_continue(rulei->act_block);
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei,
3788c2ecf20Sopenharmony_ci				u16 group_id)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return mlxsw_afa_block_jump(rulei->act_block, group_id);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	return mlxsw_afa_block_terminate(rulei->act_block);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei,
3898c2ecf20Sopenharmony_ci				bool ingress,
3908c2ecf20Sopenharmony_ci				const struct flow_action_cookie *fa_cookie,
3918c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	return mlxsw_afa_block_append_drop(rulei->act_block, ingress,
3948c2ecf20Sopenharmony_ci					   fa_cookie, extack);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	return mlxsw_afa_block_append_trap(rulei->act_block,
4008c2ecf20Sopenharmony_ci					   MLXSW_TRAP_ID_ACL0);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp,
4048c2ecf20Sopenharmony_ci			       struct mlxsw_sp_acl_rule_info *rulei,
4058c2ecf20Sopenharmony_ci			       struct net_device *out_dev,
4068c2ecf20Sopenharmony_ci			       struct netlink_ext_ack *extack)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
4098c2ecf20Sopenharmony_ci	u8 local_port;
4108c2ecf20Sopenharmony_ci	bool in_port;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (out_dev) {
4138c2ecf20Sopenharmony_ci		if (!mlxsw_sp_port_dev_check(out_dev)) {
4148c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Invalid output device");
4158c2ecf20Sopenharmony_ci			return -EINVAL;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci		mlxsw_sp_port = netdev_priv(out_dev);
4188c2ecf20Sopenharmony_ci		if (mlxsw_sp_port->mlxsw_sp != mlxsw_sp) {
4198c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Invalid output device");
4208c2ecf20Sopenharmony_ci			return -EINVAL;
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci		local_port = mlxsw_sp_port->local_port;
4238c2ecf20Sopenharmony_ci		in_port = false;
4248c2ecf20Sopenharmony_ci	} else {
4258c2ecf20Sopenharmony_ci		/* If out_dev is NULL, the caller wants to
4268c2ecf20Sopenharmony_ci		 * set forward to ingress port.
4278c2ecf20Sopenharmony_ci		 */
4288c2ecf20Sopenharmony_ci		local_port = 0;
4298c2ecf20Sopenharmony_ci		in_port = true;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci	return mlxsw_afa_block_append_fwd(rulei->act_block,
4328c2ecf20Sopenharmony_ci					  local_port, in_port, extack);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp,
4368c2ecf20Sopenharmony_ci				  struct mlxsw_sp_acl_rule_info *rulei,
4378c2ecf20Sopenharmony_ci				  struct mlxsw_sp_flow_block *block,
4388c2ecf20Sopenharmony_ci				  struct net_device *out_dev,
4398c2ecf20Sopenharmony_ci				  struct netlink_ext_ack *extack)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct mlxsw_sp_flow_block_binding *binding;
4428c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *in_port;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (!list_is_singular(&block->binding_list)) {
4458c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Only a single mirror source is allowed");
4468c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci	binding = list_first_entry(&block->binding_list,
4498c2ecf20Sopenharmony_ci				   struct mlxsw_sp_flow_block_binding, list);
4508c2ecf20Sopenharmony_ci	in_port = binding->mlxsw_sp_port;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	return mlxsw_afa_block_append_mirror(rulei->act_block,
4538c2ecf20Sopenharmony_ci					     in_port->local_port,
4548c2ecf20Sopenharmony_ci					     out_dev,
4558c2ecf20Sopenharmony_ci					     binding->ingress,
4568c2ecf20Sopenharmony_ci					     extack);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp,
4608c2ecf20Sopenharmony_ci				struct mlxsw_sp_acl_rule_info *rulei,
4618c2ecf20Sopenharmony_ci				u32 action, u16 vid, u16 proto, u8 prio,
4628c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	u8 ethertype;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (action == FLOW_ACTION_VLAN_MANGLE) {
4678c2ecf20Sopenharmony_ci		switch (proto) {
4688c2ecf20Sopenharmony_ci		case ETH_P_8021Q:
4698c2ecf20Sopenharmony_ci			ethertype = 0;
4708c2ecf20Sopenharmony_ci			break;
4718c2ecf20Sopenharmony_ci		case ETH_P_8021AD:
4728c2ecf20Sopenharmony_ci			ethertype = 1;
4738c2ecf20Sopenharmony_ci			break;
4748c2ecf20Sopenharmony_ci		default:
4758c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Unsupported VLAN protocol");
4768c2ecf20Sopenharmony_ci			dev_err(mlxsw_sp->bus_info->dev, "Unsupported VLAN protocol %#04x\n",
4778c2ecf20Sopenharmony_ci				proto);
4788c2ecf20Sopenharmony_ci			return -EINVAL;
4798c2ecf20Sopenharmony_ci		}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		return mlxsw_afa_block_append_vlan_modify(rulei->act_block,
4828c2ecf20Sopenharmony_ci							  vid, prio, ethertype,
4838c2ecf20Sopenharmony_ci							  extack);
4848c2ecf20Sopenharmony_ci	} else {
4858c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Unsupported VLAN action");
4868c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Unsupported VLAN action\n");
4878c2ecf20Sopenharmony_ci		return -EINVAL;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_priority(struct mlxsw_sp *mlxsw_sp,
4928c2ecf20Sopenharmony_ci				    struct mlxsw_sp_acl_rule_info *rulei,
4938c2ecf20Sopenharmony_ci				    u32 prio, struct netlink_ext_ack *extack)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	/* Even though both Linux and Spectrum switches support 16 priorities,
4968c2ecf20Sopenharmony_ci	 * spectrum_qdisc only processes the first eight priomap elements, and
4978c2ecf20Sopenharmony_ci	 * the DCB and PFC features are tied to 8 priorities as well. Therefore
4988c2ecf20Sopenharmony_ci	 * bounce attempts to prioritize packets to higher priorities.
4998c2ecf20Sopenharmony_ci	 */
5008c2ecf20Sopenharmony_ci	if (prio >= IEEE_8021QAZ_MAX_TCS) {
5018c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Only priorities 0..7 are supported");
5028c2ecf20Sopenharmony_ci		return -EINVAL;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci	return mlxsw_afa_block_append_qos_switch_prio(rulei->act_block, prio,
5058c2ecf20Sopenharmony_ci						      extack);
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cienum mlxsw_sp_acl_mangle_field {
5098c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_FIELD_IP_DSFIELD,
5108c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_FIELD_IP_DSCP,
5118c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_FIELD_IP_ECN,
5128c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_FIELD_IP_SPORT,
5138c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_FIELD_IP_DPORT,
5148c2ecf20Sopenharmony_ci};
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_mangle_action {
5178c2ecf20Sopenharmony_ci	enum flow_action_mangle_base htype;
5188c2ecf20Sopenharmony_ci	/* Offset is u32-aligned. */
5198c2ecf20Sopenharmony_ci	u32 offset;
5208c2ecf20Sopenharmony_ci	/* Mask bits are unset for the modified field. */
5218c2ecf20Sopenharmony_ci	u32 mask;
5228c2ecf20Sopenharmony_ci	/* Shift required to extract the set value. */
5238c2ecf20Sopenharmony_ci	u32 shift;
5248c2ecf20Sopenharmony_ci	enum mlxsw_sp_acl_mangle_field field;
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci#define MLXSW_SP_ACL_MANGLE_ACTION(_htype, _offset, _mask, _shift, _field) \
5288c2ecf20Sopenharmony_ci	{								\
5298c2ecf20Sopenharmony_ci		.htype = _htype,					\
5308c2ecf20Sopenharmony_ci		.offset = _offset,					\
5318c2ecf20Sopenharmony_ci		.mask = _mask,						\
5328c2ecf20Sopenharmony_ci		.shift = _shift,					\
5338c2ecf20Sopenharmony_ci		.field = MLXSW_SP_ACL_MANGLE_FIELD_##_field,		\
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci#define MLXSW_SP_ACL_MANGLE_ACTION_IP4(_offset, _mask, _shift, _field) \
5378c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION(FLOW_ACT_MANGLE_HDR_TYPE_IP4,       \
5388c2ecf20Sopenharmony_ci				   _offset, _mask, _shift, _field)
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci#define MLXSW_SP_ACL_MANGLE_ACTION_IP6(_offset, _mask, _shift, _field) \
5418c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION(FLOW_ACT_MANGLE_HDR_TYPE_IP6,       \
5428c2ecf20Sopenharmony_ci				   _offset, _mask, _shift, _field)
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci#define MLXSW_SP_ACL_MANGLE_ACTION_TCP(_offset, _mask, _shift, _field) \
5458c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION(FLOW_ACT_MANGLE_HDR_TYPE_TCP, _offset, _mask, _shift, _field)
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci#define MLXSW_SP_ACL_MANGLE_ACTION_UDP(_offset, _mask, _shift, _field) \
5488c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION(FLOW_ACT_MANGLE_HDR_TYPE_UDP, _offset, _mask, _shift, _field)
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic struct mlxsw_sp_acl_mangle_action mlxsw_sp_acl_mangle_actions[] = {
5518c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_IP4(0, 0xff00ffff, 16, IP_DSFIELD),
5528c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_IP4(0, 0xff03ffff, 18, IP_DSCP),
5538c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_IP4(0, 0xfffcffff, 16, IP_ECN),
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_IP6(0, 0xf00fffff, 20, IP_DSFIELD),
5568c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_IP6(0, 0xf03fffff, 22, IP_DSCP),
5578c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_IP6(0, 0xffcfffff, 20, IP_ECN),
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_TCP(0, 0x0000ffff, 16, IP_SPORT),
5608c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_TCP(0, 0xffff0000, 0,  IP_DPORT),
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_UDP(0, 0x0000ffff, 16, IP_SPORT),
5638c2ecf20Sopenharmony_ci	MLXSW_SP_ACL_MANGLE_ACTION_UDP(0, 0xffff0000, 0,  IP_DPORT),
5648c2ecf20Sopenharmony_ci};
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic int
5678c2ecf20Sopenharmony_cimlxsw_sp_acl_rulei_act_mangle_field(struct mlxsw_sp *mlxsw_sp,
5688c2ecf20Sopenharmony_ci				    struct mlxsw_sp_acl_rule_info *rulei,
5698c2ecf20Sopenharmony_ci				    struct mlxsw_sp_acl_mangle_action *mact,
5708c2ecf20Sopenharmony_ci				    u32 val, struct netlink_ext_ack *extack)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	switch (mact->field) {
5738c2ecf20Sopenharmony_ci	case MLXSW_SP_ACL_MANGLE_FIELD_IP_DSFIELD:
5748c2ecf20Sopenharmony_ci		return mlxsw_afa_block_append_qos_dsfield(rulei->act_block,
5758c2ecf20Sopenharmony_ci							  val, extack);
5768c2ecf20Sopenharmony_ci	case MLXSW_SP_ACL_MANGLE_FIELD_IP_DSCP:
5778c2ecf20Sopenharmony_ci		return mlxsw_afa_block_append_qos_dscp(rulei->act_block,
5788c2ecf20Sopenharmony_ci						       val, extack);
5798c2ecf20Sopenharmony_ci	case MLXSW_SP_ACL_MANGLE_FIELD_IP_ECN:
5808c2ecf20Sopenharmony_ci		return mlxsw_afa_block_append_qos_ecn(rulei->act_block,
5818c2ecf20Sopenharmony_ci						      val, extack);
5828c2ecf20Sopenharmony_ci	default:
5838c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic int mlxsw_sp1_acl_rulei_act_mangle_field(struct mlxsw_sp *mlxsw_sp,
5888c2ecf20Sopenharmony_ci						struct mlxsw_sp_acl_rule_info *rulei,
5898c2ecf20Sopenharmony_ci						struct mlxsw_sp_acl_mangle_action *mact,
5908c2ecf20Sopenharmony_ci						u32 val, struct netlink_ext_ack *extack)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	int err;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	err = mlxsw_sp_acl_rulei_act_mangle_field(mlxsw_sp, rulei, mact, val, extack);
5958c2ecf20Sopenharmony_ci	if (err != -EOPNOTSUPP)
5968c2ecf20Sopenharmony_ci		return err;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG_MOD(extack, "Unsupported mangle field");
5998c2ecf20Sopenharmony_ci	return err;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic int mlxsw_sp2_acl_rulei_act_mangle_field(struct mlxsw_sp *mlxsw_sp,
6038c2ecf20Sopenharmony_ci						struct mlxsw_sp_acl_rule_info *rulei,
6048c2ecf20Sopenharmony_ci						struct mlxsw_sp_acl_mangle_action *mact,
6058c2ecf20Sopenharmony_ci						u32 val, struct netlink_ext_ack *extack)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	int err;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	err = mlxsw_sp_acl_rulei_act_mangle_field(mlxsw_sp, rulei, mact, val, extack);
6108c2ecf20Sopenharmony_ci	if (err != -EOPNOTSUPP)
6118c2ecf20Sopenharmony_ci		return err;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	switch (mact->field) {
6148c2ecf20Sopenharmony_ci	case MLXSW_SP_ACL_MANGLE_FIELD_IP_SPORT:
6158c2ecf20Sopenharmony_ci		return mlxsw_afa_block_append_l4port(rulei->act_block, false, val, extack);
6168c2ecf20Sopenharmony_ci	case MLXSW_SP_ACL_MANGLE_FIELD_IP_DPORT:
6178c2ecf20Sopenharmony_ci		return mlxsw_afa_block_append_l4port(rulei->act_block, true, val, extack);
6188c2ecf20Sopenharmony_ci	default:
6198c2ecf20Sopenharmony_ci		break;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG_MOD(extack, "Unsupported mangle field");
6238c2ecf20Sopenharmony_ci	return err;
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
6278c2ecf20Sopenharmony_ci				  struct mlxsw_sp_acl_rule_info *rulei,
6288c2ecf20Sopenharmony_ci				  enum flow_action_mangle_base htype,
6298c2ecf20Sopenharmony_ci				  u32 offset, u32 mask, u32 val,
6308c2ecf20Sopenharmony_ci				  struct netlink_ext_ack *extack)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_rulei_ops *acl_rulei_ops = mlxsw_sp->acl_rulei_ops;
6338c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_mangle_action *mact;
6348c2ecf20Sopenharmony_ci	size_t i;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_acl_mangle_actions); ++i) {
6378c2ecf20Sopenharmony_ci		mact = &mlxsw_sp_acl_mangle_actions[i];
6388c2ecf20Sopenharmony_ci		if (mact->htype == htype &&
6398c2ecf20Sopenharmony_ci		    mact->offset == offset &&
6408c2ecf20Sopenharmony_ci		    mact->mask == mask) {
6418c2ecf20Sopenharmony_ci			val >>= mact->shift;
6428c2ecf20Sopenharmony_ci			return acl_rulei_ops->act_mangle_field(mlxsw_sp,
6438c2ecf20Sopenharmony_ci							       rulei, mact,
6448c2ecf20Sopenharmony_ci							       val, extack);
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG_MOD(extack, "Unknown mangle field");
6498c2ecf20Sopenharmony_ci	return -EINVAL;
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_police(struct mlxsw_sp *mlxsw_sp,
6538c2ecf20Sopenharmony_ci				  struct mlxsw_sp_acl_rule_info *rulei,
6548c2ecf20Sopenharmony_ci				  u32 index, u64 rate_bytes_ps,
6558c2ecf20Sopenharmony_ci				  u32 burst, struct netlink_ext_ack *extack)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	int err;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	err = mlxsw_afa_block_append_police(rulei->act_block, index,
6608c2ecf20Sopenharmony_ci					    rate_bytes_ps, burst,
6618c2ecf20Sopenharmony_ci					    &rulei->policer_index, extack);
6628c2ecf20Sopenharmony_ci	if (err)
6638c2ecf20Sopenharmony_ci		return err;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	rulei->policer_index_valid = true;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	return 0;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
6718c2ecf20Sopenharmony_ci				 struct mlxsw_sp_acl_rule_info *rulei,
6728c2ecf20Sopenharmony_ci				 struct netlink_ext_ack *extack)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	int err;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	err = mlxsw_afa_block_append_counter(rulei->act_block,
6778c2ecf20Sopenharmony_ci					     &rulei->counter_index, extack);
6788c2ecf20Sopenharmony_ci	if (err)
6798c2ecf20Sopenharmony_ci		return err;
6808c2ecf20Sopenharmony_ci	rulei->counter_valid = true;
6818c2ecf20Sopenharmony_ci	return 0;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp,
6858c2ecf20Sopenharmony_ci				   struct mlxsw_sp_acl_rule_info *rulei,
6868c2ecf20Sopenharmony_ci				   u16 fid, struct netlink_ext_ack *extack)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	return mlxsw_afa_block_append_fid_set(rulei->act_block, fid, extack);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rule *
6928c2ecf20Sopenharmony_cimlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp,
6938c2ecf20Sopenharmony_ci			 struct mlxsw_sp_acl_ruleset *ruleset,
6948c2ecf20Sopenharmony_ci			 unsigned long cookie,
6958c2ecf20Sopenharmony_ci			 struct mlxsw_afa_block *afa_block,
6968c2ecf20Sopenharmony_ci			 struct netlink_ext_ack *extack)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
6998c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_rule *rule;
7008c2ecf20Sopenharmony_ci	int err;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	mlxsw_sp_acl_ruleset_ref_inc(ruleset);
7038c2ecf20Sopenharmony_ci	rule = kzalloc(sizeof(*rule) + ops->rule_priv_size,
7048c2ecf20Sopenharmony_ci		       GFP_KERNEL);
7058c2ecf20Sopenharmony_ci	if (!rule) {
7068c2ecf20Sopenharmony_ci		err = -ENOMEM;
7078c2ecf20Sopenharmony_ci		goto err_alloc;
7088c2ecf20Sopenharmony_ci	}
7098c2ecf20Sopenharmony_ci	rule->cookie = cookie;
7108c2ecf20Sopenharmony_ci	rule->ruleset = ruleset;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	rule->rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl, afa_block);
7138c2ecf20Sopenharmony_ci	if (IS_ERR(rule->rulei)) {
7148c2ecf20Sopenharmony_ci		err = PTR_ERR(rule->rulei);
7158c2ecf20Sopenharmony_ci		goto err_rulei_create;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return rule;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cierr_rulei_create:
7218c2ecf20Sopenharmony_ci	kfree(rule);
7228c2ecf20Sopenharmony_cierr_alloc:
7238c2ecf20Sopenharmony_ci	mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
7248c2ecf20Sopenharmony_ci	return ERR_PTR(err);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_civoid mlxsw_sp_acl_rule_destroy(struct mlxsw_sp *mlxsw_sp,
7288c2ecf20Sopenharmony_ci			       struct mlxsw_sp_acl_rule *rule)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	mlxsw_sp_acl_rulei_destroy(rule->rulei);
7338c2ecf20Sopenharmony_ci	kfree(rule);
7348c2ecf20Sopenharmony_ci	mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp,
7388c2ecf20Sopenharmony_ci			  struct mlxsw_sp_acl_rule *rule)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
7418c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
7428c2ecf20Sopenharmony_ci	struct mlxsw_sp_flow_block *block = ruleset->ht_key.block;
7438c2ecf20Sopenharmony_ci	int err;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	err = ops->rule_add(mlxsw_sp, ruleset->priv, rule->priv, rule->rulei);
7468c2ecf20Sopenharmony_ci	if (err)
7478c2ecf20Sopenharmony_ci		return err;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	err = rhashtable_insert_fast(&ruleset->rule_ht, &rule->ht_node,
7508c2ecf20Sopenharmony_ci				     mlxsw_sp_acl_rule_ht_params);
7518c2ecf20Sopenharmony_ci	if (err)
7528c2ecf20Sopenharmony_ci		goto err_rhashtable_insert;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	if (!ruleset->ht_key.chain_index &&
7558c2ecf20Sopenharmony_ci	    mlxsw_sp_acl_ruleset_is_singular(ruleset)) {
7568c2ecf20Sopenharmony_ci		/* We only need ruleset with chain index 0, the implicit
7578c2ecf20Sopenharmony_ci		 * one, to be directly bound to device. The rest of the
7588c2ecf20Sopenharmony_ci		 * rulesets are bound by "Goto action set".
7598c2ecf20Sopenharmony_ci		 */
7608c2ecf20Sopenharmony_ci		err = mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp, ruleset, block);
7618c2ecf20Sopenharmony_ci		if (err)
7628c2ecf20Sopenharmony_ci			goto err_ruleset_block_bind;
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	mutex_lock(&mlxsw_sp->acl->rules_lock);
7668c2ecf20Sopenharmony_ci	list_add_tail(&rule->list, &mlxsw_sp->acl->rules);
7678c2ecf20Sopenharmony_ci	mutex_unlock(&mlxsw_sp->acl->rules_lock);
7688c2ecf20Sopenharmony_ci	block->rule_count++;
7698c2ecf20Sopenharmony_ci	block->ingress_blocker_rule_count += rule->rulei->ingress_bind_blocker;
7708c2ecf20Sopenharmony_ci	block->egress_blocker_rule_count += rule->rulei->egress_bind_blocker;
7718c2ecf20Sopenharmony_ci	return 0;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_cierr_ruleset_block_bind:
7748c2ecf20Sopenharmony_ci	rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node,
7758c2ecf20Sopenharmony_ci			       mlxsw_sp_acl_rule_ht_params);
7768c2ecf20Sopenharmony_cierr_rhashtable_insert:
7778c2ecf20Sopenharmony_ci	ops->rule_del(mlxsw_sp, rule->priv);
7788c2ecf20Sopenharmony_ci	return err;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_civoid mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp,
7828c2ecf20Sopenharmony_ci			   struct mlxsw_sp_acl_rule *rule)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
7858c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
7868c2ecf20Sopenharmony_ci	struct mlxsw_sp_flow_block *block = ruleset->ht_key.block;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	block->egress_blocker_rule_count -= rule->rulei->egress_bind_blocker;
7898c2ecf20Sopenharmony_ci	block->ingress_blocker_rule_count -= rule->rulei->ingress_bind_blocker;
7908c2ecf20Sopenharmony_ci	block->rule_count--;
7918c2ecf20Sopenharmony_ci	mutex_lock(&mlxsw_sp->acl->rules_lock);
7928c2ecf20Sopenharmony_ci	list_del(&rule->list);
7938c2ecf20Sopenharmony_ci	mutex_unlock(&mlxsw_sp->acl->rules_lock);
7948c2ecf20Sopenharmony_ci	if (!ruleset->ht_key.chain_index &&
7958c2ecf20Sopenharmony_ci	    mlxsw_sp_acl_ruleset_is_singular(ruleset))
7968c2ecf20Sopenharmony_ci		mlxsw_sp_acl_ruleset_block_unbind(mlxsw_sp, ruleset, block);
7978c2ecf20Sopenharmony_ci	rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node,
7988c2ecf20Sopenharmony_ci			       mlxsw_sp_acl_rule_ht_params);
7998c2ecf20Sopenharmony_ci	ops->rule_del(mlxsw_sp, rule->priv);
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rule_action_replace(struct mlxsw_sp *mlxsw_sp,
8038c2ecf20Sopenharmony_ci				     struct mlxsw_sp_acl_rule *rule,
8048c2ecf20Sopenharmony_ci				     struct mlxsw_afa_block *afa_block)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
8078c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
8088c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_rule_info *rulei;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	rulei = mlxsw_sp_acl_rule_rulei(rule);
8118c2ecf20Sopenharmony_ci	rulei->act_block = afa_block;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	return ops->rule_action_replace(mlxsw_sp, rule->priv, rule->rulei);
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rule *
8178c2ecf20Sopenharmony_cimlxsw_sp_acl_rule_lookup(struct mlxsw_sp *mlxsw_sp,
8188c2ecf20Sopenharmony_ci			 struct mlxsw_sp_acl_ruleset *ruleset,
8198c2ecf20Sopenharmony_ci			 unsigned long cookie)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	return rhashtable_lookup_fast(&ruleset->rule_ht, &cookie,
8228c2ecf20Sopenharmony_ci				       mlxsw_sp_acl_rule_ht_params);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rule_info *
8268c2ecf20Sopenharmony_cimlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	return rule->rulei;
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic int mlxsw_sp_acl_rule_activity_update(struct mlxsw_sp *mlxsw_sp,
8328c2ecf20Sopenharmony_ci					     struct mlxsw_sp_acl_rule *rule)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
8358c2ecf20Sopenharmony_ci	const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
8368c2ecf20Sopenharmony_ci	bool active;
8378c2ecf20Sopenharmony_ci	int err;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	err = ops->rule_activity_get(mlxsw_sp, rule->priv, &active);
8408c2ecf20Sopenharmony_ci	if (err)
8418c2ecf20Sopenharmony_ci		return err;
8428c2ecf20Sopenharmony_ci	if (active)
8438c2ecf20Sopenharmony_ci		rule->last_used = jiffies;
8448c2ecf20Sopenharmony_ci	return 0;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic int mlxsw_sp_acl_rules_activity_update(struct mlxsw_sp_acl *acl)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_rule *rule;
8508c2ecf20Sopenharmony_ci	int err;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	mutex_lock(&acl->rules_lock);
8538c2ecf20Sopenharmony_ci	list_for_each_entry(rule, &acl->rules, list) {
8548c2ecf20Sopenharmony_ci		err = mlxsw_sp_acl_rule_activity_update(acl->mlxsw_sp,
8558c2ecf20Sopenharmony_ci							rule);
8568c2ecf20Sopenharmony_ci		if (err)
8578c2ecf20Sopenharmony_ci			goto err_rule_update;
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci	mutex_unlock(&acl->rules_lock);
8608c2ecf20Sopenharmony_ci	return 0;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cierr_rule_update:
8638c2ecf20Sopenharmony_ci	mutex_unlock(&acl->rules_lock);
8648c2ecf20Sopenharmony_ci	return err;
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic void mlxsw_sp_acl_rule_activity_work_schedule(struct mlxsw_sp_acl *acl)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	unsigned long interval = acl->rule_activity_update.interval;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	mlxsw_core_schedule_dw(&acl->rule_activity_update.dw,
8728c2ecf20Sopenharmony_ci			       msecs_to_jiffies(interval));
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic void mlxsw_sp_acl_rule_activity_update_work(struct work_struct *work)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = container_of(work, struct mlxsw_sp_acl,
8788c2ecf20Sopenharmony_ci						rule_activity_update.dw.work);
8798c2ecf20Sopenharmony_ci	int err;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	err = mlxsw_sp_acl_rules_activity_update(acl);
8828c2ecf20Sopenharmony_ci	if (err)
8838c2ecf20Sopenharmony_ci		dev_err(acl->mlxsw_sp->bus_info->dev, "Could not update acl activity");
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	mlxsw_sp_acl_rule_activity_work_schedule(acl);
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ciint mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
8898c2ecf20Sopenharmony_ci				struct mlxsw_sp_acl_rule *rule,
8908c2ecf20Sopenharmony_ci				u64 *packets, u64 *bytes, u64 *drops,
8918c2ecf20Sopenharmony_ci				u64 *last_use,
8928c2ecf20Sopenharmony_ci				enum flow_action_hw_stats *used_hw_stats)
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	enum mlxsw_sp_policer_type type = MLXSW_SP_POLICER_TYPE_SINGLE_RATE;
8968c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl_rule_info *rulei;
8978c2ecf20Sopenharmony_ci	u64 current_packets = 0;
8988c2ecf20Sopenharmony_ci	u64 current_bytes = 0;
8998c2ecf20Sopenharmony_ci	u64 current_drops = 0;
9008c2ecf20Sopenharmony_ci	int err;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	rulei = mlxsw_sp_acl_rule_rulei(rule);
9038c2ecf20Sopenharmony_ci	if (rulei->counter_valid) {
9048c2ecf20Sopenharmony_ci		err = mlxsw_sp_flow_counter_get(mlxsw_sp, rulei->counter_index,
9058c2ecf20Sopenharmony_ci						&current_packets,
9068c2ecf20Sopenharmony_ci						&current_bytes);
9078c2ecf20Sopenharmony_ci		if (err)
9088c2ecf20Sopenharmony_ci			return err;
9098c2ecf20Sopenharmony_ci		*used_hw_stats = FLOW_ACTION_HW_STATS_IMMEDIATE;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci	if (rulei->policer_index_valid) {
9128c2ecf20Sopenharmony_ci		err = mlxsw_sp_policer_drops_counter_get(mlxsw_sp, type,
9138c2ecf20Sopenharmony_ci							 rulei->policer_index,
9148c2ecf20Sopenharmony_ci							 &current_drops);
9158c2ecf20Sopenharmony_ci		if (err)
9168c2ecf20Sopenharmony_ci			return err;
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci	*packets = current_packets - rule->last_packets;
9198c2ecf20Sopenharmony_ci	*bytes = current_bytes - rule->last_bytes;
9208c2ecf20Sopenharmony_ci	*drops = current_drops - rule->last_drops;
9218c2ecf20Sopenharmony_ci	*last_use = rule->last_used;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	rule->last_bytes = current_bytes;
9248c2ecf20Sopenharmony_ci	rule->last_packets = current_packets;
9258c2ecf20Sopenharmony_ci	rule->last_drops = current_drops;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return 0;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ciint mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct mlxsw_sp_fid *fid;
9338c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl;
9348c2ecf20Sopenharmony_ci	size_t alloc_size;
9358c2ecf20Sopenharmony_ci	int err;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	alloc_size = sizeof(*acl) + mlxsw_sp_acl_tcam_priv_size(mlxsw_sp);
9388c2ecf20Sopenharmony_ci	acl = kzalloc(alloc_size, GFP_KERNEL);
9398c2ecf20Sopenharmony_ci	if (!acl)
9408c2ecf20Sopenharmony_ci		return -ENOMEM;
9418c2ecf20Sopenharmony_ci	mlxsw_sp->acl = acl;
9428c2ecf20Sopenharmony_ci	acl->mlxsw_sp = mlxsw_sp;
9438c2ecf20Sopenharmony_ci	acl->afk = mlxsw_afk_create(MLXSW_CORE_RES_GET(mlxsw_sp->core,
9448c2ecf20Sopenharmony_ci						       ACL_FLEX_KEYS),
9458c2ecf20Sopenharmony_ci				    mlxsw_sp->afk_ops);
9468c2ecf20Sopenharmony_ci	if (!acl->afk) {
9478c2ecf20Sopenharmony_ci		err = -ENOMEM;
9488c2ecf20Sopenharmony_ci		goto err_afk_create;
9498c2ecf20Sopenharmony_ci	}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	err = rhashtable_init(&acl->ruleset_ht,
9528c2ecf20Sopenharmony_ci			      &mlxsw_sp_acl_ruleset_ht_params);
9538c2ecf20Sopenharmony_ci	if (err)
9548c2ecf20Sopenharmony_ci		goto err_rhashtable_init;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	fid = mlxsw_sp_fid_dummy_get(mlxsw_sp);
9578c2ecf20Sopenharmony_ci	if (IS_ERR(fid)) {
9588c2ecf20Sopenharmony_ci		err = PTR_ERR(fid);
9598c2ecf20Sopenharmony_ci		goto err_fid_get;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci	acl->dummy_fid = fid;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&acl->rules);
9648c2ecf20Sopenharmony_ci	mutex_init(&acl->rules_lock);
9658c2ecf20Sopenharmony_ci	err = mlxsw_sp_acl_tcam_init(mlxsw_sp, &acl->tcam);
9668c2ecf20Sopenharmony_ci	if (err)
9678c2ecf20Sopenharmony_ci		goto err_acl_ops_init;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	/* Create the delayed work for the rule activity_update */
9708c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&acl->rule_activity_update.dw,
9718c2ecf20Sopenharmony_ci			  mlxsw_sp_acl_rule_activity_update_work);
9728c2ecf20Sopenharmony_ci	acl->rule_activity_update.interval = MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS;
9738c2ecf20Sopenharmony_ci	mlxsw_core_schedule_dw(&acl->rule_activity_update.dw, 0);
9748c2ecf20Sopenharmony_ci	return 0;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_cierr_acl_ops_init:
9778c2ecf20Sopenharmony_ci	mutex_destroy(&acl->rules_lock);
9788c2ecf20Sopenharmony_ci	mlxsw_sp_fid_put(fid);
9798c2ecf20Sopenharmony_cierr_fid_get:
9808c2ecf20Sopenharmony_ci	rhashtable_destroy(&acl->ruleset_ht);
9818c2ecf20Sopenharmony_cierr_rhashtable_init:
9828c2ecf20Sopenharmony_ci	mlxsw_afk_destroy(acl->afk);
9838c2ecf20Sopenharmony_cierr_afk_create:
9848c2ecf20Sopenharmony_ci	kfree(acl);
9858c2ecf20Sopenharmony_ci	return err;
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_civoid mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw);
9938c2ecf20Sopenharmony_ci	mlxsw_sp_acl_tcam_fini(mlxsw_sp, &acl->tcam);
9948c2ecf20Sopenharmony_ci	mutex_destroy(&acl->rules_lock);
9958c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&acl->rules));
9968c2ecf20Sopenharmony_ci	mlxsw_sp_fid_put(acl->dummy_fid);
9978c2ecf20Sopenharmony_ci	rhashtable_destroy(&acl->ruleset_ht);
9988c2ecf20Sopenharmony_ci	mlxsw_afk_destroy(acl->afk);
9998c2ecf20Sopenharmony_ci	kfree(acl);
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ciu32 mlxsw_sp_acl_region_rehash_intrvl_get(struct mlxsw_sp *mlxsw_sp)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	return mlxsw_sp_acl_tcam_vregion_rehash_intrvl_get(mlxsw_sp,
10078c2ecf20Sopenharmony_ci							   &acl->tcam);
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ciint mlxsw_sp_acl_region_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp, u32 val)
10118c2ecf20Sopenharmony_ci{
10128c2ecf20Sopenharmony_ci	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	return mlxsw_sp_acl_tcam_vregion_rehash_intrvl_set(mlxsw_sp,
10158c2ecf20Sopenharmony_ci							   &acl->tcam, val);
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rulei_ops mlxsw_sp1_acl_rulei_ops = {
10198c2ecf20Sopenharmony_ci	.act_mangle_field = mlxsw_sp1_acl_rulei_act_mangle_field,
10208c2ecf20Sopenharmony_ci};
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistruct mlxsw_sp_acl_rulei_ops mlxsw_sp2_acl_rulei_ops = {
10238c2ecf20Sopenharmony_ci	.act_mangle_field = mlxsw_sp2_acl_rulei_act_mangle_field,
10248c2ecf20Sopenharmony_ci};
1025