@@ -610,6 +610,112 @@ nfp_flower_can_merge(struct nfp_fl_payload *sub_flow1,
610
610
return 0 ;
611
611
}
612
612
613
+ static unsigned int
614
+ nfp_flower_copy_pre_actions (char * act_dst , char * act_src , int len ,
615
+ bool * tunnel_act )
616
+ {
617
+ unsigned int act_off = 0 , act_len ;
618
+ struct nfp_fl_act_head * a ;
619
+ u8 act_id = 0 ;
620
+
621
+ while (act_off < len ) {
622
+ a = (struct nfp_fl_act_head * )& act_src [act_off ];
623
+ act_len = a -> len_lw << NFP_FL_LW_SIZ ;
624
+ act_id = a -> jump_id ;
625
+
626
+ switch (act_id ) {
627
+ case NFP_FL_ACTION_OPCODE_PRE_TUNNEL :
628
+ if (tunnel_act )
629
+ * tunnel_act = true;
630
+ case NFP_FL_ACTION_OPCODE_PRE_LAG :
631
+ memcpy (act_dst + act_off , act_src + act_off , act_len );
632
+ break ;
633
+ default :
634
+ return act_off ;
635
+ }
636
+
637
+ act_off += act_len ;
638
+ }
639
+
640
+ return act_off ;
641
+ }
642
+
643
+ static int nfp_fl_verify_post_tun_acts (char * acts , int len )
644
+ {
645
+ struct nfp_fl_act_head * a ;
646
+ unsigned int act_off = 0 ;
647
+
648
+ while (act_off < len ) {
649
+ a = (struct nfp_fl_act_head * )& acts [act_off ];
650
+ if (a -> jump_id != NFP_FL_ACTION_OPCODE_OUTPUT )
651
+ return - EOPNOTSUPP ;
652
+
653
+ act_off += a -> len_lw << NFP_FL_LW_SIZ ;
654
+ }
655
+
656
+ return 0 ;
657
+ }
658
+
659
+ static int
660
+ nfp_flower_merge_action (struct nfp_fl_payload * sub_flow1 ,
661
+ struct nfp_fl_payload * sub_flow2 ,
662
+ struct nfp_fl_payload * merge_flow )
663
+ {
664
+ unsigned int sub1_act_len , sub2_act_len , pre_off1 , pre_off2 ;
665
+ bool tunnel_act = false;
666
+ char * merge_act ;
667
+ int err ;
668
+
669
+ /* The last action of sub_flow1 must be output - do not merge this. */
670
+ sub1_act_len = sub_flow1 -> meta .act_len - sizeof (struct nfp_fl_output );
671
+ sub2_act_len = sub_flow2 -> meta .act_len ;
672
+
673
+ if (!sub2_act_len )
674
+ return - EINVAL ;
675
+
676
+ if (sub1_act_len + sub2_act_len > NFP_FL_MAX_A_SIZ )
677
+ return - EINVAL ;
678
+
679
+ /* A shortcut can only be applied if there is a single action. */
680
+ if (sub1_act_len )
681
+ merge_flow -> meta .shortcut = cpu_to_be32 (NFP_FL_SC_ACT_NULL );
682
+ else
683
+ merge_flow -> meta .shortcut = sub_flow2 -> meta .shortcut ;
684
+
685
+ merge_flow -> meta .act_len = sub1_act_len + sub2_act_len ;
686
+ merge_act = merge_flow -> action_data ;
687
+
688
+ /* Copy any pre-actions to the start of merge flow action list. */
689
+ pre_off1 = nfp_flower_copy_pre_actions (merge_act ,
690
+ sub_flow1 -> action_data ,
691
+ sub1_act_len , & tunnel_act );
692
+ merge_act += pre_off1 ;
693
+ sub1_act_len -= pre_off1 ;
694
+ pre_off2 = nfp_flower_copy_pre_actions (merge_act ,
695
+ sub_flow2 -> action_data ,
696
+ sub2_act_len , NULL );
697
+ merge_act += pre_off2 ;
698
+ sub2_act_len -= pre_off2 ;
699
+
700
+ /* FW does a tunnel push when egressing, therefore, if sub_flow 1 pushes
701
+ * a tunnel, sub_flow 2 can only have output actions for a valid merge.
702
+ */
703
+ if (tunnel_act ) {
704
+ char * post_tun_acts = & sub_flow2 -> action_data [pre_off2 ];
705
+
706
+ err = nfp_fl_verify_post_tun_acts (post_tun_acts , sub2_act_len );
707
+ if (err )
708
+ return err ;
709
+ }
710
+
711
+ /* Copy remaining actions from sub_flows 1 and 2. */
712
+ memcpy (merge_act , sub_flow1 -> action_data + pre_off1 , sub1_act_len );
713
+ merge_act += sub1_act_len ;
714
+ memcpy (merge_act , sub_flow2 -> action_data + pre_off2 , sub2_act_len );
715
+
716
+ return 0 ;
717
+ }
718
+
613
719
/**
614
720
* nfp_flower_merge_offloaded_flows() - Merge 2 existing flows to single flow.
615
721
* @app: Pointer to the APP handle
@@ -625,13 +731,47 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
625
731
struct nfp_fl_payload * sub_flow1 ,
626
732
struct nfp_fl_payload * sub_flow2 )
627
733
{
734
+ struct nfp_fl_payload * merge_flow ;
735
+ struct nfp_fl_key_ls merge_key_ls ;
628
736
int err ;
629
737
738
+ ASSERT_RTNL ();
739
+
740
+ if (sub_flow1 == sub_flow2 ||
741
+ nfp_flower_is_merge_flow (sub_flow1 ) ||
742
+ nfp_flower_is_merge_flow (sub_flow2 ))
743
+ return - EINVAL ;
744
+
630
745
err = nfp_flower_can_merge (sub_flow1 , sub_flow2 );
631
746
if (err )
632
747
return err ;
633
748
634
- return - EOPNOTSUPP ;
749
+ merge_key_ls .key_size = sub_flow1 -> meta .key_len ;
750
+
751
+ merge_flow = nfp_flower_allocate_new (& merge_key_ls );
752
+ if (!merge_flow )
753
+ return - ENOMEM ;
754
+
755
+ merge_flow -> tc_flower_cookie = (unsigned long )merge_flow ;
756
+ merge_flow -> ingress_dev = sub_flow1 -> ingress_dev ;
757
+
758
+ memcpy (merge_flow -> unmasked_data , sub_flow1 -> unmasked_data ,
759
+ sub_flow1 -> meta .key_len );
760
+ memcpy (merge_flow -> mask_data , sub_flow1 -> mask_data ,
761
+ sub_flow1 -> meta .mask_len );
762
+
763
+ err = nfp_flower_merge_action (sub_flow1 , sub_flow2 , merge_flow );
764
+ if (err )
765
+ goto err_destroy_merge_flow ;
766
+
767
+ err = - EOPNOTSUPP ;
768
+
769
+ err_destroy_merge_flow :
770
+ kfree (merge_flow -> action_data );
771
+ kfree (merge_flow -> mask_data );
772
+ kfree (merge_flow -> unmasked_data );
773
+ kfree (merge_flow );
774
+ return err ;
635
775
}
636
776
637
777
/**
0 commit comments