@@ -871,6 +871,68 @@ mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
871871 return err ;
872872}
873873
874+ static int
875+ mlx5_tc_ct_entry_replace_rule (struct mlx5_tc_ct_priv * ct_priv ,
876+ struct flow_rule * flow_rule ,
877+ struct mlx5_ct_entry * entry ,
878+ bool nat , u8 zone_restore_id )
879+ {
880+ struct mlx5_ct_zone_rule * zone_rule = & entry -> zone_rules [nat ];
881+ struct mlx5_flow_attr * attr = zone_rule -> attr , * old_attr ;
882+ struct mlx5e_mod_hdr_handle * mh ;
883+ struct mlx5_ct_fs_rule * rule ;
884+ struct mlx5_flow_spec * spec ;
885+ int err ;
886+
887+ spec = kvzalloc (sizeof (* spec ), GFP_KERNEL );
888+ if (!spec )
889+ return - ENOMEM ;
890+
891+ old_attr = mlx5_alloc_flow_attr (ct_priv -> ns_type );
892+ if (!old_attr ) {
893+ err = - ENOMEM ;
894+ goto err_attr ;
895+ }
896+ * old_attr = * attr ;
897+
898+ err = mlx5_tc_ct_entry_create_mod_hdr (ct_priv , attr , flow_rule , & mh , zone_restore_id ,
899+ nat , mlx5_tc_ct_entry_has_nat (entry ));
900+ if (err ) {
901+ ct_dbg ("Failed to create ct entry mod hdr" );
902+ goto err_mod_hdr ;
903+ }
904+
905+ mlx5_tc_ct_set_tuple_match (ct_priv , spec , flow_rule );
906+ mlx5e_tc_match_to_reg_match (spec , ZONE_TO_REG , entry -> tuple .zone , MLX5_CT_ZONE_MASK );
907+
908+ rule = ct_priv -> fs_ops -> ct_rule_add (ct_priv -> fs , spec , attr , flow_rule );
909+ if (IS_ERR (rule )) {
910+ err = PTR_ERR (rule );
911+ ct_dbg ("Failed to add replacement ct entry rule, nat: %d" , nat );
912+ goto err_rule ;
913+ }
914+
915+ ct_priv -> fs_ops -> ct_rule_del (ct_priv -> fs , zone_rule -> rule );
916+ zone_rule -> rule = rule ;
917+ mlx5_tc_ct_entry_destroy_mod_hdr (ct_priv , old_attr , zone_rule -> mh );
918+ zone_rule -> mh = mh ;
919+
920+ kfree (old_attr );
921+ kvfree (spec );
922+ ct_dbg ("Replaced ct entry rule in zone %d" , entry -> tuple .zone );
923+
924+ return 0 ;
925+
926+ err_rule :
927+ mlx5_tc_ct_entry_destroy_mod_hdr (ct_priv , zone_rule -> attr , mh );
928+ mlx5_put_label_mapping (ct_priv , attr -> ct_attr .ct_labels_id );
929+ err_mod_hdr :
930+ kfree (old_attr );
931+ err_attr :
932+ kvfree (spec );
933+ return err ;
934+ }
935+
874936static bool
875937mlx5_tc_ct_entry_valid (struct mlx5_ct_entry * entry )
876938{
@@ -1065,6 +1127,52 @@ mlx5_tc_ct_entry_add_rules(struct mlx5_tc_ct_priv *ct_priv,
10651127 return err ;
10661128}
10671129
1130+ static int
1131+ mlx5_tc_ct_entry_replace_rules (struct mlx5_tc_ct_priv * ct_priv ,
1132+ struct flow_rule * flow_rule ,
1133+ struct mlx5_ct_entry * entry ,
1134+ u8 zone_restore_id )
1135+ {
1136+ int err ;
1137+
1138+ err = mlx5_tc_ct_entry_replace_rule (ct_priv , flow_rule , entry , false,
1139+ zone_restore_id );
1140+ if (err )
1141+ return err ;
1142+
1143+ err = mlx5_tc_ct_entry_replace_rule (ct_priv , flow_rule , entry , true,
1144+ zone_restore_id );
1145+ if (err )
1146+ mlx5_tc_ct_entry_del_rule (ct_priv , entry , false);
1147+ return err ;
1148+ }
1149+
1150+ static int
1151+ mlx5_tc_ct_block_flow_offload_replace (struct mlx5_ct_ft * ft , struct flow_rule * flow_rule ,
1152+ struct mlx5_ct_entry * entry , unsigned long cookie )
1153+ {
1154+ struct mlx5_tc_ct_priv * ct_priv = ft -> ct_priv ;
1155+ int err ;
1156+
1157+ err = mlx5_tc_ct_entry_replace_rules (ct_priv , flow_rule , entry , ft -> zone_restore_id );
1158+ if (!err )
1159+ return 0 ;
1160+
1161+ /* If failed to update the entry, then look it up again under ht_lock
1162+ * protection and properly delete it.
1163+ */
1164+ spin_lock_bh (& ct_priv -> ht_lock );
1165+ entry = rhashtable_lookup_fast (& ft -> ct_entries_ht , & cookie , cts_ht_params );
1166+ if (entry ) {
1167+ rhashtable_remove_fast (& ft -> ct_entries_ht , & entry -> node , cts_ht_params );
1168+ spin_unlock_bh (& ct_priv -> ht_lock );
1169+ mlx5_tc_ct_entry_put (entry );
1170+ } else {
1171+ spin_unlock_bh (& ct_priv -> ht_lock );
1172+ }
1173+ return err ;
1174+ }
1175+
10681176static int
10691177mlx5_tc_ct_block_flow_offload_add (struct mlx5_ct_ft * ft ,
10701178 struct flow_cls_offload * flow )
@@ -1087,9 +1195,17 @@ mlx5_tc_ct_block_flow_offload_add(struct mlx5_ct_ft *ft,
10871195 spin_lock_bh (& ct_priv -> ht_lock );
10881196 entry = rhashtable_lookup_fast (& ft -> ct_entries_ht , & cookie , cts_ht_params );
10891197 if (entry && refcount_inc_not_zero (& entry -> refcnt )) {
1198+ if (entry -> restore_cookie == meta_action -> ct_metadata .cookie ) {
1199+ spin_unlock_bh (& ct_priv -> ht_lock );
1200+ mlx5_tc_ct_entry_put (entry );
1201+ return - EEXIST ;
1202+ }
1203+ entry -> restore_cookie = meta_action -> ct_metadata .cookie ;
10901204 spin_unlock_bh (& ct_priv -> ht_lock );
1205+
1206+ err = mlx5_tc_ct_block_flow_offload_replace (ft , flow_rule , entry , cookie );
10911207 mlx5_tc_ct_entry_put (entry );
1092- return - EEXIST ;
1208+ return err ;
10931209 }
10941210 spin_unlock_bh (& ct_priv -> ht_lock );
10951211
0 commit comments