@@ -398,6 +398,7 @@ nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer)
398
398
399
399
flow_pay -> nfp_tun_ipv4_addr = 0 ;
400
400
flow_pay -> meta .flags = 0 ;
401
+ INIT_LIST_HEAD (& flow_pay -> linked_flows );
401
402
402
403
return flow_pay ;
403
404
@@ -716,6 +717,43 @@ nfp_flower_merge_action(struct nfp_fl_payload *sub_flow1,
716
717
return 0 ;
717
718
}
718
719
720
+ /* Flow link code should only be accessed under RTNL. */
721
+ static void nfp_flower_unlink_flow (struct nfp_fl_payload_link * link )
722
+ {
723
+ list_del (& link -> merge_flow .list );
724
+ list_del (& link -> sub_flow .list );
725
+ kfree (link );
726
+ }
727
+
728
+ static void nfp_flower_unlink_flows (struct nfp_fl_payload * merge_flow ,
729
+ struct nfp_fl_payload * sub_flow )
730
+ {
731
+ struct nfp_fl_payload_link * link ;
732
+
733
+ list_for_each_entry (link , & merge_flow -> linked_flows , merge_flow .list )
734
+ if (link -> sub_flow .flow == sub_flow ) {
735
+ nfp_flower_unlink_flow (link );
736
+ return ;
737
+ }
738
+ }
739
+
740
+ static int nfp_flower_link_flows (struct nfp_fl_payload * merge_flow ,
741
+ struct nfp_fl_payload * sub_flow )
742
+ {
743
+ struct nfp_fl_payload_link * link ;
744
+
745
+ link = kmalloc (sizeof (* link ), GFP_KERNEL );
746
+ if (!link )
747
+ return - ENOMEM ;
748
+
749
+ link -> merge_flow .flow = merge_flow ;
750
+ list_add_tail (& link -> merge_flow .list , & merge_flow -> linked_flows );
751
+ link -> sub_flow .flow = sub_flow ;
752
+ list_add_tail (& link -> sub_flow .list , & sub_flow -> linked_flows );
753
+
754
+ return 0 ;
755
+ }
756
+
719
757
/**
720
758
* nfp_flower_merge_offloaded_flows() - Merge 2 existing flows to single flow.
721
759
* @app: Pointer to the APP handle
@@ -764,8 +802,19 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
764
802
if (err )
765
803
goto err_destroy_merge_flow ;
766
804
805
+ err = nfp_flower_link_flows (merge_flow , sub_flow1 );
806
+ if (err )
807
+ goto err_destroy_merge_flow ;
808
+
809
+ err = nfp_flower_link_flows (merge_flow , sub_flow2 );
810
+ if (err )
811
+ goto err_unlink_sub_flow1 ;
812
+
767
813
err = - EOPNOTSUPP ;
768
814
815
+ nfp_flower_unlink_flows (merge_flow , sub_flow2 );
816
+ err_unlink_sub_flow1 :
817
+ nfp_flower_unlink_flows (merge_flow , sub_flow1 );
769
818
err_destroy_merge_flow :
770
819
kfree (merge_flow -> action_data );
771
820
kfree (merge_flow -> mask_data );
@@ -913,6 +962,52 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
913
962
return err ;
914
963
}
915
964
965
+ static void
966
+ __nfp_flower_update_merge_stats (struct nfp_app * app ,
967
+ struct nfp_fl_payload * merge_flow )
968
+ {
969
+ struct nfp_flower_priv * priv = app -> priv ;
970
+ struct nfp_fl_payload_link * link ;
971
+ struct nfp_fl_payload * sub_flow ;
972
+ u64 pkts , bytes , used ;
973
+ u32 ctx_id ;
974
+
975
+ ctx_id = be32_to_cpu (merge_flow -> meta .host_ctx_id );
976
+ pkts = priv -> stats [ctx_id ].pkts ;
977
+ /* Do not cycle subflows if no stats to distribute. */
978
+ if (!pkts )
979
+ return ;
980
+ bytes = priv -> stats [ctx_id ].bytes ;
981
+ used = priv -> stats [ctx_id ].used ;
982
+
983
+ /* Reset stats for the merge flow. */
984
+ priv -> stats [ctx_id ].pkts = 0 ;
985
+ priv -> stats [ctx_id ].bytes = 0 ;
986
+
987
+ /* The merge flow has received stats updates from firmware.
988
+ * Distribute these stats to all subflows that form the merge.
989
+ * The stats will collected from TC via the subflows.
990
+ */
991
+ list_for_each_entry (link , & merge_flow -> linked_flows , merge_flow .list ) {
992
+ sub_flow = link -> sub_flow .flow ;
993
+ ctx_id = be32_to_cpu (sub_flow -> meta .host_ctx_id );
994
+ priv -> stats [ctx_id ].pkts += pkts ;
995
+ priv -> stats [ctx_id ].bytes += bytes ;
996
+ max_t (u64 , priv -> stats [ctx_id ].used , used );
997
+ }
998
+ }
999
+
1000
+ static void
1001
+ nfp_flower_update_merge_stats (struct nfp_app * app ,
1002
+ struct nfp_fl_payload * sub_flow )
1003
+ {
1004
+ struct nfp_fl_payload_link * link ;
1005
+
1006
+ /* Get merge flows that the subflow forms to distribute their stats. */
1007
+ list_for_each_entry (link , & sub_flow -> linked_flows , sub_flow .list )
1008
+ __nfp_flower_update_merge_stats (app , link -> merge_flow .flow );
1009
+ }
1010
+
916
1011
/**
917
1012
* nfp_flower_get_stats() - Populates flow stats obtained from hardware.
918
1013
* @app: Pointer to the APP handle
@@ -939,6 +1034,10 @@ nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev,
939
1034
ctx_id = be32_to_cpu (nfp_flow -> meta .host_ctx_id );
940
1035
941
1036
spin_lock_bh (& priv -> stats_lock );
1037
+ /* If request is for a sub_flow, update stats from merged flows. */
1038
+ if (!list_empty (& nfp_flow -> linked_flows ))
1039
+ nfp_flower_update_merge_stats (app , nfp_flow );
1040
+
942
1041
flow_stats_update (& flow -> stats , priv -> stats [ctx_id ].bytes ,
943
1042
priv -> stats [ctx_id ].pkts , priv -> stats [ctx_id ].used );
944
1043
0 commit comments