77#include <linux/errno.h>
88#include <linux/rhashtable.h>
99#include <linux/list.h>
10+ #include <linux/idr.h>
11+ #include <linux/refcount.h>
12+ #include <net/flow_offload.h>
1013
1114#include "item.h"
1215#include "trap.h"
@@ -63,6 +66,8 @@ struct mlxsw_afa {
6366 void * ops_priv ;
6467 struct rhashtable set_ht ;
6568 struct rhashtable fwd_entry_ht ;
69+ struct rhashtable cookie_ht ;
70+ struct idr cookie_idr ;
6671};
6772
6873#define MLXSW_AFA_SET_LEN 0xA8
@@ -121,6 +126,55 @@ static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = {
121126 .automatic_shrinking = true,
122127};
123128
129+ struct mlxsw_afa_cookie {
130+ struct rhash_head ht_node ;
131+ refcount_t ref_count ;
132+ struct rcu_head rcu ;
133+ u32 cookie_index ;
134+ struct flow_action_cookie fa_cookie ;
135+ };
136+
137+ static u32 mlxsw_afa_cookie_hash (const struct flow_action_cookie * fa_cookie ,
138+ u32 seed )
139+ {
140+ return jhash2 ((u32 * ) fa_cookie -> cookie ,
141+ fa_cookie -> cookie_len / sizeof (u32 ), seed );
142+ }
143+
144+ static u32 mlxsw_afa_cookie_key_hashfn (const void * data , u32 len , u32 seed )
145+ {
146+ const struct flow_action_cookie * fa_cookie = data ;
147+
148+ return mlxsw_afa_cookie_hash (fa_cookie , seed );
149+ }
150+
151+ static u32 mlxsw_afa_cookie_obj_hashfn (const void * data , u32 len , u32 seed )
152+ {
153+ const struct mlxsw_afa_cookie * cookie = data ;
154+
155+ return mlxsw_afa_cookie_hash (& cookie -> fa_cookie , seed );
156+ }
157+
158+ static int mlxsw_afa_cookie_obj_cmpfn (struct rhashtable_compare_arg * arg ,
159+ const void * obj )
160+ {
161+ const struct flow_action_cookie * fa_cookie = arg -> key ;
162+ const struct mlxsw_afa_cookie * cookie = obj ;
163+
164+ if (cookie -> fa_cookie .cookie_len == fa_cookie -> cookie_len )
165+ return memcmp (cookie -> fa_cookie .cookie , fa_cookie -> cookie ,
166+ fa_cookie -> cookie_len );
167+ return 1 ;
168+ }
169+
170+ static const struct rhashtable_params mlxsw_afa_cookie_ht_params = {
171+ .head_offset = offsetof(struct mlxsw_afa_cookie , ht_node ),
172+ .hashfn = mlxsw_afa_cookie_key_hashfn ,
173+ .obj_hashfn = mlxsw_afa_cookie_obj_hashfn ,
174+ .obj_cmpfn = mlxsw_afa_cookie_obj_cmpfn ,
175+ .automatic_shrinking = true,
176+ };
177+
124178struct mlxsw_afa * mlxsw_afa_create (unsigned int max_acts_per_set ,
125179 const struct mlxsw_afa_ops * ops ,
126180 void * ops_priv )
@@ -138,11 +192,18 @@ struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set,
138192 & mlxsw_afa_fwd_entry_ht_params );
139193 if (err )
140194 goto err_fwd_entry_rhashtable_init ;
195+ err = rhashtable_init (& mlxsw_afa -> cookie_ht ,
196+ & mlxsw_afa_cookie_ht_params );
197+ if (err )
198+ goto err_cookie_rhashtable_init ;
199+ idr_init (& mlxsw_afa -> cookie_idr );
141200 mlxsw_afa -> max_acts_per_set = max_acts_per_set ;
142201 mlxsw_afa -> ops = ops ;
143202 mlxsw_afa -> ops_priv = ops_priv ;
144203 return mlxsw_afa ;
145204
205+ err_cookie_rhashtable_init :
206+ rhashtable_destroy (& mlxsw_afa -> fwd_entry_ht );
146207err_fwd_entry_rhashtable_init :
147208 rhashtable_destroy (& mlxsw_afa -> set_ht );
148209err_set_rhashtable_init :
@@ -153,6 +214,9 @@ EXPORT_SYMBOL(mlxsw_afa_create);
153214
154215void mlxsw_afa_destroy (struct mlxsw_afa * mlxsw_afa )
155216{
217+ WARN_ON (!idr_is_empty (& mlxsw_afa -> cookie_idr ));
218+ idr_destroy (& mlxsw_afa -> cookie_idr );
219+ rhashtable_destroy (& mlxsw_afa -> cookie_ht );
156220 rhashtable_destroy (& mlxsw_afa -> fwd_entry_ht );
157221 rhashtable_destroy (& mlxsw_afa -> set_ht );
158222 kfree (mlxsw_afa );
@@ -627,6 +691,135 @@ mlxsw_afa_counter_create(struct mlxsw_afa_block *block)
627691 return ERR_PTR (err );
628692}
629693
694+ /* 20 bits is a maximum that hardware can handle in trap with userdef action
695+ * and carry along with the trapped packet.
696+ */
697+ #define MLXSW_AFA_COOKIE_INDEX_BITS 20
698+ #define MLXSW_AFA_COOKIE_INDEX_MAX ((1 << MLXSW_AFA_COOKIE_INDEX_BITS) - 1)
699+
700+ static struct mlxsw_afa_cookie *
701+ mlxsw_afa_cookie_create (struct mlxsw_afa * mlxsw_afa ,
702+ const struct flow_action_cookie * fa_cookie )
703+ {
704+ struct mlxsw_afa_cookie * cookie ;
705+ u32 cookie_index ;
706+ int err ;
707+
708+ cookie = kzalloc (sizeof (* cookie ) + fa_cookie -> cookie_len , GFP_KERNEL );
709+ if (!cookie )
710+ return ERR_PTR (- ENOMEM );
711+ refcount_set (& cookie -> ref_count , 1 );
712+ memcpy (& cookie -> fa_cookie , fa_cookie ,
713+ sizeof (* fa_cookie ) + fa_cookie -> cookie_len );
714+
715+ err = rhashtable_insert_fast (& mlxsw_afa -> cookie_ht , & cookie -> ht_node ,
716+ mlxsw_afa_cookie_ht_params );
717+ if (err )
718+ goto err_rhashtable_insert ;
719+
720+ /* Start cookie indexes with 1. Leave the 0 index unused. Packets
721+ * that come from the HW which are not dropped by drop-with-cookie
722+ * action are going to pass cookie_index 0 to lookup.
723+ */
724+ cookie_index = 1 ;
725+ err = idr_alloc_u32 (& mlxsw_afa -> cookie_idr , cookie , & cookie_index ,
726+ MLXSW_AFA_COOKIE_INDEX_MAX , GFP_KERNEL );
727+ if (err )
728+ goto err_idr_alloc ;
729+ cookie -> cookie_index = cookie_index ;
730+ return cookie ;
731+
732+ err_idr_alloc :
733+ rhashtable_remove_fast (& mlxsw_afa -> cookie_ht , & cookie -> ht_node ,
734+ mlxsw_afa_cookie_ht_params );
735+ err_rhashtable_insert :
736+ kfree (cookie );
737+ return ERR_PTR (err );
738+ }
739+
740+ static void mlxsw_afa_cookie_destroy (struct mlxsw_afa * mlxsw_afa ,
741+ struct mlxsw_afa_cookie * cookie )
742+ {
743+ idr_remove (& mlxsw_afa -> cookie_idr , cookie -> cookie_index );
744+ rhashtable_remove_fast (& mlxsw_afa -> cookie_ht , & cookie -> ht_node ,
745+ mlxsw_afa_cookie_ht_params );
746+ kfree_rcu (cookie , rcu );
747+ }
748+
749+ static struct mlxsw_afa_cookie *
750+ mlxsw_afa_cookie_get (struct mlxsw_afa * mlxsw_afa ,
751+ const struct flow_action_cookie * fa_cookie )
752+ {
753+ struct mlxsw_afa_cookie * cookie ;
754+
755+ cookie = rhashtable_lookup_fast (& mlxsw_afa -> cookie_ht , fa_cookie ,
756+ mlxsw_afa_cookie_ht_params );
757+ if (cookie ) {
758+ refcount_inc (& cookie -> ref_count );
759+ return cookie ;
760+ }
761+ return mlxsw_afa_cookie_create (mlxsw_afa , fa_cookie );
762+ }
763+
764+ static void mlxsw_afa_cookie_put (struct mlxsw_afa * mlxsw_afa ,
765+ struct mlxsw_afa_cookie * cookie )
766+ {
767+ if (!refcount_dec_and_test (& cookie -> ref_count ))
768+ return ;
769+ mlxsw_afa_cookie_destroy (mlxsw_afa , cookie );
770+ }
771+
772+ struct mlxsw_afa_cookie_ref {
773+ struct mlxsw_afa_resource resource ;
774+ struct mlxsw_afa_cookie * cookie ;
775+ };
776+
777+ static void
778+ mlxsw_afa_cookie_ref_destroy (struct mlxsw_afa_block * block ,
779+ struct mlxsw_afa_cookie_ref * cookie_ref )
780+ {
781+ mlxsw_afa_resource_del (& cookie_ref -> resource );
782+ mlxsw_afa_cookie_put (block -> afa , cookie_ref -> cookie );
783+ kfree (cookie_ref );
784+ }
785+
786+ static void
787+ mlxsw_afa_cookie_ref_destructor (struct mlxsw_afa_block * block ,
788+ struct mlxsw_afa_resource * resource )
789+ {
790+ struct mlxsw_afa_cookie_ref * cookie_ref ;
791+
792+ cookie_ref = container_of (resource , struct mlxsw_afa_cookie_ref ,
793+ resource );
794+ mlxsw_afa_cookie_ref_destroy (block , cookie_ref );
795+ }
796+
797+ static struct mlxsw_afa_cookie_ref *
798+ mlxsw_afa_cookie_ref_create (struct mlxsw_afa_block * block ,
799+ const struct flow_action_cookie * fa_cookie )
800+ {
801+ struct mlxsw_afa_cookie_ref * cookie_ref ;
802+ struct mlxsw_afa_cookie * cookie ;
803+ int err ;
804+
805+ cookie_ref = kzalloc (sizeof (* cookie_ref ), GFP_KERNEL );
806+ if (!cookie_ref )
807+ return ERR_PTR (- ENOMEM );
808+ cookie = mlxsw_afa_cookie_get (block -> afa , fa_cookie );
809+ if (IS_ERR (cookie )) {
810+ err = PTR_ERR (cookie );
811+ goto err_cookie_get ;
812+ }
813+ cookie_ref -> cookie = cookie ;
814+ cookie_ref -> resource .destructor = mlxsw_afa_cookie_ref_destructor ;
815+ mlxsw_afa_resource_add (block , & cookie_ref -> resource );
816+ return cookie_ref ;
817+
818+ err_cookie_get :
819+ kfree (cookie_ref );
820+ return ERR_PTR (err );
821+ }
822+
630823#define MLXSW_AFA_ONE_ACTION_LEN 32
631824#define MLXSW_AFA_PAYLOAD_OFFSET 4
632825
@@ -839,7 +1032,8 @@ mlxsw_afa_trap_mirror_pack(char *payload, bool mirror_enable,
8391032 mlxsw_afa_trap_mirror_agent_set (payload , mirror_agent );
8401033}
8411034
842- int mlxsw_afa_block_append_drop (struct mlxsw_afa_block * block , bool ingress )
1035+ static int mlxsw_afa_block_append_drop_plain (struct mlxsw_afa_block * block ,
1036+ bool ingress )
8431037{
8441038 char * act = mlxsw_afa_block_append_action (block , MLXSW_AFA_TRAP_CODE ,
8451039 MLXSW_AFA_TRAP_SIZE );
@@ -852,6 +1046,53 @@ int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block, bool ingress)
8521046 MLXSW_TRAP_ID_DISCARD_EGRESS_ACL );
8531047 return 0 ;
8541048}
1049+
1050+ static int
1051+ mlxsw_afa_block_append_drop_with_cookie (struct mlxsw_afa_block * block ,
1052+ bool ingress ,
1053+ const struct flow_action_cookie * fa_cookie ,
1054+ struct netlink_ext_ack * extack )
1055+ {
1056+ struct mlxsw_afa_cookie_ref * cookie_ref ;
1057+ u32 cookie_index ;
1058+ char * act ;
1059+ int err ;
1060+
1061+ cookie_ref = mlxsw_afa_cookie_ref_create (block , fa_cookie );
1062+ if (IS_ERR (cookie_ref )) {
1063+ NL_SET_ERR_MSG_MOD (extack , "Cannot create cookie for drop action" );
1064+ return PTR_ERR (cookie_ref );
1065+ }
1066+ cookie_index = cookie_ref -> cookie -> cookie_index ;
1067+
1068+ act = mlxsw_afa_block_append_action (block , MLXSW_AFA_TRAPWU_CODE ,
1069+ MLXSW_AFA_TRAPWU_SIZE );
1070+ if (IS_ERR (act )) {
1071+ NL_SET_ERR_MSG_MOD (extack , "Cannot append drop with cookie action" );
1072+ err = PTR_ERR (act );
1073+ goto err_append_action ;
1074+ }
1075+ mlxsw_afa_trapwu_pack (act , MLXSW_AFA_TRAP_TRAP_ACTION_TRAP ,
1076+ MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD ,
1077+ ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL :
1078+ MLXSW_TRAP_ID_DISCARD_EGRESS_ACL ,
1079+ cookie_index );
1080+ return 0 ;
1081+
1082+ err_append_action :
1083+ mlxsw_afa_cookie_ref_destroy (block , cookie_ref );
1084+ return err ;
1085+ }
1086+
1087+ int mlxsw_afa_block_append_drop (struct mlxsw_afa_block * block , bool ingress ,
1088+ const struct flow_action_cookie * fa_cookie ,
1089+ struct netlink_ext_ack * extack )
1090+ {
1091+ return fa_cookie ?
1092+ mlxsw_afa_block_append_drop_with_cookie (block , ingress ,
1093+ fa_cookie , extack ) :
1094+ mlxsw_afa_block_append_drop_plain (block , ingress );
1095+ }
8551096EXPORT_SYMBOL (mlxsw_afa_block_append_drop );
8561097
8571098int mlxsw_afa_block_append_trap (struct mlxsw_afa_block * block , u16 trap_id )
0 commit comments