@@ -106,9 +106,19 @@ struct mlxsw_sp_fib_key {
106
106
unsigned char prefix_len ;
107
107
};
108
108
109
+ enum mlxsw_sp_fib_entry_type {
110
+ MLXSW_SP_FIB_ENTRY_TYPE_REMOTE ,
111
+ MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ,
112
+ MLXSW_SP_FIB_ENTRY_TYPE_TRAP ,
113
+ };
114
+
109
115
struct mlxsw_sp_fib_entry {
110
116
struct rhash_head ht_node ;
111
117
struct mlxsw_sp_fib_key key ;
118
+ enum mlxsw_sp_fib_entry_type type ;
119
+ u8 added :1 ;
120
+ u16 rif ; /* used for action local */
121
+ struct mlxsw_sp_vr * vr ;
112
122
};
113
123
114
124
struct mlxsw_sp_fib {
@@ -567,3 +577,238 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
567
577
{
568
578
__mlxsw_sp_router_fini (mlxsw_sp );
569
579
}
580
+
581
+ static int mlxsw_sp_fib_entry_op4_local (struct mlxsw_sp * mlxsw_sp ,
582
+ struct mlxsw_sp_fib_entry * fib_entry ,
583
+ enum mlxsw_reg_ralue_op op )
584
+ {
585
+ char ralue_pl [MLXSW_REG_RALUE_LEN ];
586
+ u32 * p_dip = (u32 * ) fib_entry -> key .addr ;
587
+ struct mlxsw_sp_vr * vr = fib_entry -> vr ;
588
+
589
+ mlxsw_reg_ralue_pack4 (ralue_pl , vr -> proto , op , vr -> id ,
590
+ fib_entry -> key .prefix_len , * p_dip );
591
+ mlxsw_reg_ralue_act_local_pack (ralue_pl ,
592
+ MLXSW_REG_RALUE_TRAP_ACTION_NOP , 0 ,
593
+ fib_entry -> rif );
594
+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (ralue ), ralue_pl );
595
+ }
596
+
597
+ static int mlxsw_sp_fib_entry_op4_trap (struct mlxsw_sp * mlxsw_sp ,
598
+ struct mlxsw_sp_fib_entry * fib_entry ,
599
+ enum mlxsw_reg_ralue_op op )
600
+ {
601
+ char ralue_pl [MLXSW_REG_RALUE_LEN ];
602
+ u32 * p_dip = (u32 * ) fib_entry -> key .addr ;
603
+ struct mlxsw_sp_vr * vr = fib_entry -> vr ;
604
+
605
+ mlxsw_reg_ralue_pack4 (ralue_pl , vr -> proto , op , vr -> id ,
606
+ fib_entry -> key .prefix_len , * p_dip );
607
+ mlxsw_reg_ralue_act_ip2me_pack (ralue_pl );
608
+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (ralue ), ralue_pl );
609
+ }
610
+
611
+ static int mlxsw_sp_fib_entry_op4 (struct mlxsw_sp * mlxsw_sp ,
612
+ struct mlxsw_sp_fib_entry * fib_entry ,
613
+ enum mlxsw_reg_ralue_op op )
614
+ {
615
+ switch (fib_entry -> type ) {
616
+ case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE :
617
+ return - EINVAL ;
618
+ case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL :
619
+ return mlxsw_sp_fib_entry_op4_local (mlxsw_sp , fib_entry , op );
620
+ case MLXSW_SP_FIB_ENTRY_TYPE_TRAP :
621
+ return mlxsw_sp_fib_entry_op4_trap (mlxsw_sp , fib_entry , op );
622
+ }
623
+ return - EINVAL ;
624
+ }
625
+
626
+ static int mlxsw_sp_fib_entry_op (struct mlxsw_sp * mlxsw_sp ,
627
+ struct mlxsw_sp_fib_entry * fib_entry ,
628
+ enum mlxsw_reg_ralue_op op )
629
+ {
630
+ switch (fib_entry -> vr -> proto ) {
631
+ case MLXSW_SP_L3_PROTO_IPV4 :
632
+ return mlxsw_sp_fib_entry_op4 (mlxsw_sp , fib_entry , op );
633
+ case MLXSW_SP_L3_PROTO_IPV6 :
634
+ return - EINVAL ;
635
+ }
636
+ return - EINVAL ;
637
+ }
638
+
639
+ static int mlxsw_sp_fib_entry_update (struct mlxsw_sp * mlxsw_sp ,
640
+ struct mlxsw_sp_fib_entry * fib_entry )
641
+ {
642
+ enum mlxsw_reg_ralue_op op ;
643
+
644
+ op = !fib_entry -> added ? MLXSW_REG_RALUE_OP_WRITE_WRITE :
645
+ MLXSW_REG_RALUE_OP_WRITE_UPDATE ;
646
+ return mlxsw_sp_fib_entry_op (mlxsw_sp , fib_entry , op );
647
+ }
648
+
649
+ static int mlxsw_sp_fib_entry_del (struct mlxsw_sp * mlxsw_sp ,
650
+ struct mlxsw_sp_fib_entry * fib_entry )
651
+ {
652
+ return mlxsw_sp_fib_entry_op (mlxsw_sp , fib_entry ,
653
+ MLXSW_REG_RALUE_OP_WRITE_DELETE );
654
+ }
655
+
656
+ struct mlxsw_sp_router_fib4_add_info {
657
+ struct switchdev_trans_item tritem ;
658
+ struct mlxsw_sp * mlxsw_sp ;
659
+ struct mlxsw_sp_fib_entry * fib_entry ;
660
+ };
661
+
662
+ static void mlxsw_sp_router_fib4_add_info_destroy (void const * data )
663
+ {
664
+ const struct mlxsw_sp_router_fib4_add_info * info = data ;
665
+ struct mlxsw_sp_fib_entry * fib_entry = info -> fib_entry ;
666
+ struct mlxsw_sp * mlxsw_sp = info -> mlxsw_sp ;
667
+
668
+ mlxsw_sp_fib_entry_destroy (fib_entry );
669
+ mlxsw_sp_vr_put (mlxsw_sp , fib_entry -> vr );
670
+ kfree (info );
671
+ }
672
+
673
+ static int
674
+ mlxsw_sp_router_fib4_entry_init (struct mlxsw_sp * mlxsw_sp ,
675
+ const struct switchdev_obj_ipv4_fib * fib4 ,
676
+ struct mlxsw_sp_fib_entry * fib_entry )
677
+ {
678
+ struct fib_info * fi = fib4 -> fi ;
679
+
680
+ if (fib4 -> type == RTN_LOCAL || fib4 -> type == RTN_BROADCAST ) {
681
+ fib_entry -> type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP ;
682
+ return 0 ;
683
+ }
684
+ if (fib4 -> type != RTN_UNICAST )
685
+ return - EINVAL ;
686
+
687
+ if (fi -> fib_scope != RT_SCOPE_UNIVERSE ) {
688
+ struct mlxsw_sp_rif * r ;
689
+
690
+ fib_entry -> type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ;
691
+ r = mlxsw_sp_rif_find_by_dev (mlxsw_sp , fi -> fib_dev );
692
+ if (!r )
693
+ return - EINVAL ;
694
+ fib_entry -> rif = r -> rif ;
695
+ return 0 ;
696
+ }
697
+ return - EINVAL ;
698
+ }
699
+
700
+ static int
701
+ mlxsw_sp_router_fib4_add_prepare (struct mlxsw_sp_port * mlxsw_sp_port ,
702
+ const struct switchdev_obj_ipv4_fib * fib4 ,
703
+ struct switchdev_trans * trans )
704
+ {
705
+ struct mlxsw_sp * mlxsw_sp = mlxsw_sp_port -> mlxsw_sp ;
706
+ struct mlxsw_sp_router_fib4_add_info * info ;
707
+ struct mlxsw_sp_fib_entry * fib_entry ;
708
+ struct mlxsw_sp_vr * vr ;
709
+ int err ;
710
+
711
+ vr = mlxsw_sp_vr_get (mlxsw_sp , fib4 -> dst_len , fib4 -> tb_id ,
712
+ MLXSW_SP_L3_PROTO_IPV4 );
713
+ if (IS_ERR (vr ))
714
+ return PTR_ERR (vr );
715
+
716
+ fib_entry = mlxsw_sp_fib_entry_create (vr -> fib , & fib4 -> dst ,
717
+ sizeof (fib4 -> dst ), fib4 -> dst_len );
718
+ if (!fib_entry ) {
719
+ err = - ENOMEM ;
720
+ goto err_fib_entry_create ;
721
+ }
722
+ fib_entry -> vr = vr ;
723
+
724
+ err = mlxsw_sp_router_fib4_entry_init (mlxsw_sp , fib4 , fib_entry );
725
+ if (err )
726
+ goto err_fib4_entry_init ;
727
+
728
+ info = kmalloc (sizeof (* info ), GFP_KERNEL );
729
+ if (!info ) {
730
+ err = - ENOMEM ;
731
+ goto err_alloc_info ;
732
+ }
733
+ info -> mlxsw_sp = mlxsw_sp ;
734
+ info -> fib_entry = fib_entry ;
735
+ switchdev_trans_item_enqueue (trans , info ,
736
+ mlxsw_sp_router_fib4_add_info_destroy ,
737
+ & info -> tritem );
738
+ return 0 ;
739
+
740
+ err_alloc_info :
741
+ err_fib4_entry_init :
742
+ mlxsw_sp_fib_entry_destroy (fib_entry );
743
+ err_fib_entry_create :
744
+ mlxsw_sp_vr_put (mlxsw_sp , vr );
745
+ return err ;
746
+ }
747
+
748
+ static int
749
+ mlxsw_sp_router_fib4_add_commit (struct mlxsw_sp_port * mlxsw_sp_port ,
750
+ const struct switchdev_obj_ipv4_fib * fib4 ,
751
+ struct switchdev_trans * trans )
752
+ {
753
+ struct mlxsw_sp * mlxsw_sp = mlxsw_sp_port -> mlxsw_sp ;
754
+ struct mlxsw_sp_router_fib4_add_info * info ;
755
+ struct mlxsw_sp_fib_entry * fib_entry ;
756
+ struct mlxsw_sp_vr * vr ;
757
+ int err ;
758
+
759
+ info = switchdev_trans_item_dequeue (trans );
760
+ fib_entry = info -> fib_entry ;
761
+ kfree (info );
762
+
763
+ vr = fib_entry -> vr ;
764
+ err = mlxsw_sp_fib_entry_insert (fib_entry -> vr -> fib , fib_entry );
765
+ if (err )
766
+ goto err_fib_entry_insert ;
767
+ err = mlxsw_sp_fib_entry_update (mlxsw_sp , fib_entry );
768
+ if (err )
769
+ goto err_fib_entry_add ;
770
+ return 0 ;
771
+
772
+ err_fib_entry_add :
773
+ mlxsw_sp_fib_entry_remove (vr -> fib , fib_entry );
774
+ err_fib_entry_insert :
775
+ mlxsw_sp_fib_entry_destroy (fib_entry );
776
+ mlxsw_sp_vr_put (mlxsw_sp , vr );
777
+ return err ;
778
+ }
779
+
780
+ int mlxsw_sp_router_fib4_add (struct mlxsw_sp_port * mlxsw_sp_port ,
781
+ const struct switchdev_obj_ipv4_fib * fib4 ,
782
+ struct switchdev_trans * trans )
783
+ {
784
+ if (switchdev_trans_ph_prepare (trans ))
785
+ return mlxsw_sp_router_fib4_add_prepare (mlxsw_sp_port ,
786
+ fib4 , trans );
787
+ return mlxsw_sp_router_fib4_add_commit (mlxsw_sp_port ,
788
+ fib4 , trans );
789
+ }
790
+
791
+ int mlxsw_sp_router_fib4_del (struct mlxsw_sp_port * mlxsw_sp_port ,
792
+ const struct switchdev_obj_ipv4_fib * fib4 )
793
+ {
794
+ struct mlxsw_sp * mlxsw_sp = mlxsw_sp_port -> mlxsw_sp ;
795
+ struct mlxsw_sp_fib_entry * fib_entry ;
796
+ struct mlxsw_sp_vr * vr ;
797
+
798
+ vr = mlxsw_sp_vr_find (mlxsw_sp , fib4 -> tb_id , MLXSW_SP_L3_PROTO_IPV4 );
799
+ if (!vr ) {
800
+ dev_warn (mlxsw_sp -> bus_info -> dev , "Failed to find virtual router for FIB4 entry being removed.\n" );
801
+ return - ENOENT ;
802
+ }
803
+ fib_entry = mlxsw_sp_fib_entry_lookup (vr -> fib , & fib4 -> dst ,
804
+ sizeof (fib4 -> dst ), fib4 -> dst_len );
805
+ if (!fib_entry ) {
806
+ dev_warn (mlxsw_sp -> bus_info -> dev , "Failed to find FIB4 entry being removed.\n" );
807
+ return PTR_ERR (vr );
808
+ }
809
+ mlxsw_sp_fib_entry_del (mlxsw_sp_port -> mlxsw_sp , fib_entry );
810
+ mlxsw_sp_fib_entry_remove (vr -> fib , fib_entry );
811
+ mlxsw_sp_fib_entry_destroy (fib_entry );
812
+ mlxsw_sp_vr_put (mlxsw_sp , vr );
813
+ return 0 ;
814
+ }
0 commit comments