@@ -201,8 +201,10 @@ static void tree_put_node(struct fs_node *node)
201
201
202
202
static int tree_remove_node (struct fs_node * node )
203
203
{
204
- if (atomic_read (& node -> refcount ) > 1 )
205
- return - EPERM ;
204
+ if (atomic_read (& node -> refcount ) > 1 ) {
205
+ atomic_dec (& node -> refcount );
206
+ return - EEXIST ;
207
+ }
206
208
tree_put_node (node );
207
209
return 0 ;
208
210
}
@@ -365,6 +367,11 @@ static void del_rule(struct fs_node *node)
365
367
memcpy (match_value , fte -> val , sizeof (fte -> val ));
366
368
fs_get_obj (ft , fg -> node .parent );
367
369
list_del (& rule -> node .list );
370
+ if (rule -> sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO ) {
371
+ mutex_lock (& rule -> dest_attr .ft -> lock );
372
+ list_del (& rule -> next_ft );
373
+ mutex_unlock (& rule -> dest_attr .ft -> lock );
374
+ }
368
375
fte -> dests_size -- ;
369
376
if (fte -> dests_size ) {
370
377
err = mlx5_cmd_update_fte (dev , ft ,
@@ -470,6 +477,8 @@ static struct mlx5_flow_table *alloc_flow_table(int level, int max_fte,
470
477
ft -> node .type = FS_TYPE_FLOW_TABLE ;
471
478
ft -> type = table_type ;
472
479
ft -> max_fte = max_fte ;
480
+ INIT_LIST_HEAD (& ft -> fwd_rules );
481
+ mutex_init (& ft -> lock );
473
482
474
483
return ft ;
475
484
}
@@ -606,9 +615,63 @@ static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio
606
615
return err ;
607
616
}
608
617
618
+ static int mlx5_modify_rule_destination (struct mlx5_flow_rule * rule ,
619
+ struct mlx5_flow_destination * dest )
620
+ {
621
+ struct mlx5_flow_table * ft ;
622
+ struct mlx5_flow_group * fg ;
623
+ struct fs_fte * fte ;
624
+ int err = 0 ;
625
+
626
+ fs_get_obj (fte , rule -> node .parent );
627
+ if (!(fte -> action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST ))
628
+ return - EINVAL ;
629
+ lock_ref_node (& fte -> node );
630
+ fs_get_obj (fg , fte -> node .parent );
631
+ fs_get_obj (ft , fg -> node .parent );
632
+
633
+ memcpy (& rule -> dest_attr , dest , sizeof (* dest ));
634
+ err = mlx5_cmd_update_fte (get_dev (& ft -> node ),
635
+ ft , fg -> id , fte );
636
+ unlock_ref_node (& fte -> node );
637
+
638
+ return err ;
639
+ }
640
+
641
+ /* Modify/set FWD rules that point on old_next_ft to point on new_next_ft */
642
+ static int connect_fwd_rules (struct mlx5_core_dev * dev ,
643
+ struct mlx5_flow_table * new_next_ft ,
644
+ struct mlx5_flow_table * old_next_ft )
645
+ {
646
+ struct mlx5_flow_destination dest ;
647
+ struct mlx5_flow_rule * iter ;
648
+ int err = 0 ;
649
+
650
+ /* new_next_ft and old_next_ft could be NULL only
651
+ * when we create/destroy the anchor flow table.
652
+ */
653
+ if (!new_next_ft || !old_next_ft )
654
+ return 0 ;
655
+
656
+ dest .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE ;
657
+ dest .ft = new_next_ft ;
658
+
659
+ mutex_lock (& old_next_ft -> lock );
660
+ list_splice_init (& old_next_ft -> fwd_rules , & new_next_ft -> fwd_rules );
661
+ mutex_unlock (& old_next_ft -> lock );
662
+ list_for_each_entry (iter , & new_next_ft -> fwd_rules , next_ft ) {
663
+ err = mlx5_modify_rule_destination (iter , & dest );
664
+ if (err )
665
+ pr_err ("mlx5_core: failed to modify rule to point on flow table %d\n" ,
666
+ new_next_ft -> id );
667
+ }
668
+ return 0 ;
669
+ }
670
+
609
671
static int connect_flow_table (struct mlx5_core_dev * dev , struct mlx5_flow_table * ft ,
610
672
struct fs_prio * prio )
611
673
{
674
+ struct mlx5_flow_table * next_ft ;
612
675
int err = 0 ;
613
676
614
677
/* Connect_prev_fts and update_root_ft_create are mutually exclusive */
@@ -617,6 +680,11 @@ static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table
617
680
err = connect_prev_fts (dev , ft , prio );
618
681
if (err )
619
682
return err ;
683
+
684
+ next_ft = find_next_chained_ft (prio );
685
+ err = connect_fwd_rules (dev , ft , next_ft );
686
+ if (err )
687
+ return err ;
620
688
}
621
689
622
690
if (MLX5_CAP_FLOWTABLE (dev ,
@@ -767,6 +835,7 @@ static struct mlx5_flow_rule *alloc_rule(struct mlx5_flow_destination *dest)
767
835
if (!rule )
768
836
return NULL ;
769
837
838
+ INIT_LIST_HEAD (& rule -> next_ft );
770
839
rule -> node .type = FS_TYPE_FLOW_DEST ;
771
840
memcpy (& rule -> dest_attr , dest , sizeof (* dest ));
772
841
@@ -787,9 +856,14 @@ static struct mlx5_flow_rule *add_rule_fte(struct fs_fte *fte,
787
856
return ERR_PTR (- ENOMEM );
788
857
789
858
fs_get_obj (ft , fg -> node .parent );
790
- /* Add dest to dests list- added as first element after the head */
859
+ /* Add dest to dests list- we need flow tables to be in the
860
+ * end of the list for forward to next prio rules.
861
+ */
791
862
tree_init_node (& rule -> node , 1 , del_rule );
792
- list_add_tail (& rule -> node .list , & fte -> node .children );
863
+ if (dest && dest -> type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE )
864
+ list_add (& rule -> node .list , & fte -> node .children );
865
+ else
866
+ list_add_tail (& rule -> node .list , & fte -> node .children );
793
867
fte -> dests_size ++ ;
794
868
if (fte -> dests_size == 1 )
795
869
err = mlx5_cmd_create_fte (get_dev (& ft -> node ),
@@ -908,6 +982,25 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
908
982
return fg ;
909
983
}
910
984
985
+ static struct mlx5_flow_rule * find_flow_rule (struct fs_fte * fte ,
986
+ struct mlx5_flow_destination * dest )
987
+ {
988
+ struct mlx5_flow_rule * rule ;
989
+
990
+ list_for_each_entry (rule , & fte -> node .children , node .list ) {
991
+ if (rule -> dest_attr .type == dest -> type ) {
992
+ if ((dest -> type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
993
+ dest -> vport_num == rule -> dest_attr .vport_num ) ||
994
+ (dest -> type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE &&
995
+ dest -> ft == rule -> dest_attr .ft ) ||
996
+ (dest -> type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
997
+ dest -> tir_num == rule -> dest_attr .tir_num ))
998
+ return rule ;
999
+ }
1000
+ }
1001
+ return NULL ;
1002
+ }
1003
+
911
1004
static struct mlx5_flow_rule * add_rule_fg (struct mlx5_flow_group * fg ,
912
1005
u32 * match_value ,
913
1006
u8 action ,
@@ -924,6 +1017,13 @@ static struct mlx5_flow_rule *add_rule_fg(struct mlx5_flow_group *fg,
924
1017
nested_lock_ref_node (& fte -> node , FS_MUTEX_CHILD );
925
1018
if (compare_match_value (& fg -> mask , match_value , & fte -> val ) &&
926
1019
action == fte -> action && flow_tag == fte -> flow_tag ) {
1020
+ rule = find_flow_rule (fte , dest );
1021
+ if (rule ) {
1022
+ atomic_inc (& rule -> node .refcount );
1023
+ unlock_ref_node (& fte -> node );
1024
+ unlock_ref_node (& fg -> node );
1025
+ return rule ;
1026
+ }
927
1027
rule = add_rule_fte (fte , fg , dest );
928
1028
unlock_ref_node (& fte -> node );
929
1029
if (IS_ERR (rule ))
@@ -989,14 +1089,14 @@ static struct mlx5_flow_rule *add_rule_to_auto_fg(struct mlx5_flow_table *ft,
989
1089
return rule ;
990
1090
}
991
1091
992
- struct mlx5_flow_rule *
993
- mlx5_add_flow_rule (struct mlx5_flow_table * ft ,
994
- u8 match_criteria_enable ,
995
- u32 * match_criteria ,
996
- u32 * match_value ,
997
- u32 action ,
998
- u32 flow_tag ,
999
- struct mlx5_flow_destination * dest )
1092
+ static struct mlx5_flow_rule *
1093
+ _mlx5_add_flow_rule (struct mlx5_flow_table * ft ,
1094
+ u8 match_criteria_enable ,
1095
+ u32 * match_criteria ,
1096
+ u32 * match_value ,
1097
+ u32 action ,
1098
+ u32 flow_tag ,
1099
+ struct mlx5_flow_destination * dest )
1000
1100
{
1001
1101
struct mlx5_flow_group * g ;
1002
1102
struct mlx5_flow_rule * rule ;
@@ -1019,6 +1119,63 @@ mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1019
1119
unlock_ref_node (& ft -> node );
1020
1120
return rule ;
1021
1121
}
1122
+
1123
+ static bool fwd_next_prio_supported (struct mlx5_flow_table * ft )
1124
+ {
1125
+ return ((ft -> type == FS_FT_NIC_RX ) &&
1126
+ (MLX5_CAP_FLOWTABLE (get_dev (& ft -> node ), nic_rx_multi_path_tirs )));
1127
+ }
1128
+
1129
+ struct mlx5_flow_rule *
1130
+ mlx5_add_flow_rule (struct mlx5_flow_table * ft ,
1131
+ u8 match_criteria_enable ,
1132
+ u32 * match_criteria ,
1133
+ u32 * match_value ,
1134
+ u32 action ,
1135
+ u32 flow_tag ,
1136
+ struct mlx5_flow_destination * dest )
1137
+ {
1138
+ struct mlx5_flow_root_namespace * root = find_root (& ft -> node );
1139
+ struct mlx5_flow_destination gen_dest ;
1140
+ struct mlx5_flow_table * next_ft = NULL ;
1141
+ struct mlx5_flow_rule * rule = NULL ;
1142
+ u32 sw_action = action ;
1143
+ struct fs_prio * prio ;
1144
+
1145
+ fs_get_obj (prio , ft -> node .parent );
1146
+ if (action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO ) {
1147
+ if (!fwd_next_prio_supported (ft ))
1148
+ return ERR_PTR (- EOPNOTSUPP );
1149
+ if (dest )
1150
+ return ERR_PTR (- EINVAL );
1151
+ mutex_lock (& root -> chain_lock );
1152
+ next_ft = find_next_chained_ft (prio );
1153
+ if (next_ft ) {
1154
+ gen_dest .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE ;
1155
+ gen_dest .ft = next_ft ;
1156
+ dest = & gen_dest ;
1157
+ action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST ;
1158
+ } else {
1159
+ mutex_unlock (& root -> chain_lock );
1160
+ return ERR_PTR (- EOPNOTSUPP );
1161
+ }
1162
+ }
1163
+
1164
+ rule = _mlx5_add_flow_rule (ft , match_criteria_enable , match_criteria ,
1165
+ match_value , action , flow_tag , dest );
1166
+
1167
+ if (sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO ) {
1168
+ if (!IS_ERR_OR_NULL (rule ) &&
1169
+ (list_empty (& rule -> next_ft ))) {
1170
+ mutex_lock (& next_ft -> lock );
1171
+ list_add (& rule -> next_ft , & next_ft -> fwd_rules );
1172
+ mutex_unlock (& next_ft -> lock );
1173
+ rule -> sw_action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO ;
1174
+ }
1175
+ mutex_unlock (& root -> chain_lock );
1176
+ }
1177
+ return rule ;
1178
+ }
1022
1179
EXPORT_SYMBOL (mlx5_add_flow_rule );
1023
1180
1024
1181
void mlx5_del_flow_rule (struct mlx5_flow_rule * rule )
@@ -1082,6 +1239,10 @@ static int disconnect_flow_table(struct mlx5_flow_table *ft)
1082
1239
return 0 ;
1083
1240
1084
1241
next_ft = find_next_chained_ft (prio );
1242
+ err = connect_fwd_rules (dev , next_ft , ft );
1243
+ if (err )
1244
+ return err ;
1245
+
1085
1246
err = connect_prev_fts (dev , next_ft , prio );
1086
1247
if (err )
1087
1248
mlx5_core_warn (dev , "Failed to disconnect flow table %d\n" ,
0 commit comments