@@ -381,6 +381,14 @@ enum mlxsw_sp_fib_entry_type {
381381 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE ,
382382 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ,
383383 MLXSW_SP_FIB_ENTRY_TYPE_TRAP ,
384+
385+ /* This is a special case of local delivery, where a packet should be
386+ * decapsulated on reception. Note that there is no corresponding ENCAP,
387+ * because that's a type of next hop, not of FIB entry. (There can be
388+ * several next hops in a REMOTE entry, and some of them may be
389+ * encapsulating entries.)
390+ */
391+ MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP ,
384392};
385393
386394struct mlxsw_sp_nexthop_group ;
@@ -394,12 +402,18 @@ struct mlxsw_sp_fib_node {
394402 struct mlxsw_sp_fib_key key ;
395403};
396404
405+ struct mlxsw_sp_fib_entry_decap {
406+ struct mlxsw_sp_ipip_entry * ipip_entry ;
407+ u32 tunnel_index ;
408+ };
409+
397410struct mlxsw_sp_fib_entry {
398411 struct list_head list ;
399412 struct mlxsw_sp_fib_node * fib_node ;
400413 enum mlxsw_sp_fib_entry_type type ;
401414 struct list_head nexthop_group_node ;
402415 struct mlxsw_sp_nexthop_group * nh_group ;
416+ struct mlxsw_sp_fib_entry_decap decap ; /* Valid for decap entries. */
403417};
404418
405419struct mlxsw_sp_fib4_entry {
@@ -1031,6 +1045,48 @@ mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,
10311045 mlxsw_sp_l3addr_eq (& tun_saddr , & saddr );
10321046}
10331047
1048+ static int
1049+ mlxsw_sp_fib_entry_decap_init (struct mlxsw_sp * mlxsw_sp ,
1050+ struct mlxsw_sp_fib_entry * fib_entry ,
1051+ struct mlxsw_sp_ipip_entry * ipip_entry )
1052+ {
1053+ u32 tunnel_index ;
1054+ int err ;
1055+
1056+ err = mlxsw_sp_kvdl_alloc (mlxsw_sp , 1 , & tunnel_index );
1057+ if (err )
1058+ return err ;
1059+
1060+ ipip_entry -> decap_fib_entry = fib_entry ;
1061+ fib_entry -> decap .ipip_entry = ipip_entry ;
1062+ fib_entry -> decap .tunnel_index = tunnel_index ;
1063+ return 0 ;
1064+ }
1065+
1066+ static void mlxsw_sp_fib_entry_decap_fini (struct mlxsw_sp * mlxsw_sp ,
1067+ struct mlxsw_sp_fib_entry * fib_entry )
1068+ {
1069+ /* Unlink this node from the IPIP entry that it's the decap entry of. */
1070+ fib_entry -> decap .ipip_entry -> decap_fib_entry = NULL ;
1071+ fib_entry -> decap .ipip_entry = NULL ;
1072+ mlxsw_sp_kvdl_free (mlxsw_sp , fib_entry -> decap .tunnel_index );
1073+ }
1074+
1075+ static int mlxsw_sp_fib_entry_update (struct mlxsw_sp * mlxsw_sp ,
1076+ struct mlxsw_sp_fib_entry * fib_entry );
1077+
1078+ static void
1079+ mlxsw_sp_ipip_entry_demote_decap (struct mlxsw_sp * mlxsw_sp ,
1080+ struct mlxsw_sp_ipip_entry * ipip_entry )
1081+ {
1082+ struct mlxsw_sp_fib_entry * fib_entry = ipip_entry -> decap_fib_entry ;
1083+
1084+ mlxsw_sp_fib_entry_decap_fini (mlxsw_sp , fib_entry );
1085+ fib_entry -> type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP ;
1086+
1087+ mlxsw_sp_fib_entry_update (mlxsw_sp , fib_entry );
1088+ }
1089+
10341090static struct mlxsw_sp_ipip_entry *
10351091mlxsw_sp_ipip_entry_get (struct mlxsw_sp * mlxsw_sp ,
10361092 enum mlxsw_sp_ipip_type ipipt ,
@@ -1076,10 +1132,51 @@ mlxsw_sp_ipip_entry_put(struct mlxsw_sp *mlxsw_sp,
10761132{
10771133 if (-- ipip_entry -> ref_count == 0 ) {
10781134 list_del (& ipip_entry -> ipip_list_node );
1135+ if (ipip_entry -> decap_fib_entry )
1136+ mlxsw_sp_ipip_entry_demote_decap (mlxsw_sp , ipip_entry );
10791137 mlxsw_sp_ipip_entry_destroy (ipip_entry );
10801138 }
10811139}
10821140
1141+ static bool
1142+ mlxsw_sp_ipip_entry_matches_decap (struct mlxsw_sp * mlxsw_sp ,
1143+ const struct net_device * ul_dev ,
1144+ enum mlxsw_sp_l3proto ul_proto ,
1145+ union mlxsw_sp_l3addr ul_dip ,
1146+ struct mlxsw_sp_ipip_entry * ipip_entry )
1147+ {
1148+ u32 ul_tb_id = l3mdev_fib_table (ul_dev ) ? : RT_TABLE_MAIN ;
1149+ enum mlxsw_sp_ipip_type ipipt = ipip_entry -> ipipt ;
1150+ struct net_device * ipip_ul_dev ;
1151+
1152+ if (mlxsw_sp -> router -> ipip_ops_arr [ipipt ]-> ul_proto != ul_proto )
1153+ return false;
1154+
1155+ ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get (ipip_entry -> ol_dev );
1156+ return mlxsw_sp_ipip_entry_saddr_matches (mlxsw_sp , ul_proto , ul_dip ,
1157+ ul_tb_id , ipip_entry ) &&
1158+ (!ipip_ul_dev || ipip_ul_dev == ul_dev );
1159+ }
1160+
1161+ /* Given decap parameters, find the corresponding IPIP entry. */
1162+ static struct mlxsw_sp_ipip_entry *
1163+ mlxsw_sp_ipip_entry_find_by_decap (struct mlxsw_sp * mlxsw_sp ,
1164+ const struct net_device * ul_dev ,
1165+ enum mlxsw_sp_l3proto ul_proto ,
1166+ union mlxsw_sp_l3addr ul_dip )
1167+ {
1168+ struct mlxsw_sp_ipip_entry * ipip_entry ;
1169+
1170+ list_for_each_entry (ipip_entry , & mlxsw_sp -> router -> ipip_list ,
1171+ ipip_list_node )
1172+ if (mlxsw_sp_ipip_entry_matches_decap (mlxsw_sp , ul_dev ,
1173+ ul_proto , ul_dip ,
1174+ ipip_entry ))
1175+ return ipip_entry ;
1176+
1177+ return NULL ;
1178+ }
1179+
10831180struct mlxsw_sp_neigh_key {
10841181 struct neighbour * n ;
10851182};
@@ -2186,9 +2283,6 @@ mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
21862283 return 0 ;
21872284}
21882285
2189- static int mlxsw_sp_fib_entry_update (struct mlxsw_sp * mlxsw_sp ,
2190- struct mlxsw_sp_fib_entry * fib_entry );
2191-
21922286static bool
21932287mlxsw_sp_fib_node_entry_is_first (const struct mlxsw_sp_fib_node * fib_node ,
21942288 const struct mlxsw_sp_fib_entry * fib_entry );
@@ -2779,6 +2873,8 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
27792873 return !!nh_group -> adj_index_valid ;
27802874 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL :
27812875 return !!nh_group -> nh_rif ;
2876+ case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP :
2877+ return true;
27822878 default :
27832879 return false;
27842880 }
@@ -2810,7 +2906,8 @@ mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
28102906 struct mlxsw_sp_nexthop_group * nh_grp = fib_entry -> nh_group ;
28112907 int i ;
28122908
2813- if (fib_entry -> type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ) {
2909+ if (fib_entry -> type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ||
2910+ fib_entry -> type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP ) {
28142911 nh_grp -> nexthops -> key .fib_nh -> nh_flags |= RTNH_F_OFFLOAD ;
28152912 return ;
28162913 }
@@ -3015,6 +3112,22 @@ static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,
30153112 return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (ralue ), ralue_pl );
30163113}
30173114
3115+ static int
3116+ mlxsw_sp_fib_entry_op_ipip_decap (struct mlxsw_sp * mlxsw_sp ,
3117+ struct mlxsw_sp_fib_entry * fib_entry ,
3118+ enum mlxsw_reg_ralue_op op )
3119+ {
3120+ struct mlxsw_sp_ipip_entry * ipip_entry = fib_entry -> decap .ipip_entry ;
3121+ const struct mlxsw_sp_ipip_ops * ipip_ops ;
3122+
3123+ if (WARN_ON (!ipip_entry ))
3124+ return - EINVAL ;
3125+
3126+ ipip_ops = mlxsw_sp -> router -> ipip_ops_arr [ipip_entry -> ipipt ];
3127+ return ipip_ops -> fib_entry_op (mlxsw_sp , ipip_entry , op ,
3128+ fib_entry -> decap .tunnel_index );
3129+ }
3130+
30183131static int __mlxsw_sp_fib_entry_op (struct mlxsw_sp * mlxsw_sp ,
30193132 struct mlxsw_sp_fib_entry * fib_entry ,
30203133 enum mlxsw_reg_ralue_op op )
@@ -3026,6 +3139,9 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
30263139 return mlxsw_sp_fib_entry_op_local (mlxsw_sp , fib_entry , op );
30273140 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP :
30283141 return mlxsw_sp_fib_entry_op_trap (mlxsw_sp , fib_entry , op );
3142+ case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP :
3143+ return mlxsw_sp_fib_entry_op_ipip_decap (mlxsw_sp ,
3144+ fib_entry , op );
30293145 }
30303146 return - EINVAL ;
30313147}
@@ -3060,11 +3176,23 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
30603176 const struct fib_entry_notifier_info * fen_info ,
30613177 struct mlxsw_sp_fib_entry * fib_entry )
30623178{
3179+ union mlxsw_sp_l3addr dip = { .addr4 = htonl (fen_info -> dst ) };
3180+ struct net_device * dev = fen_info -> fi -> fib_dev ;
3181+ struct mlxsw_sp_ipip_entry * ipip_entry ;
30633182 struct fib_info * fi = fen_info -> fi ;
30643183
30653184 switch (fen_info -> type ) {
3066- case RTN_BROADCAST : /* fall through */
30673185 case RTN_LOCAL :
3186+ ipip_entry = mlxsw_sp_ipip_entry_find_by_decap (mlxsw_sp , dev ,
3187+ MLXSW_SP_L3_PROTO_IPV4 , dip );
3188+ if (ipip_entry ) {
3189+ fib_entry -> type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP ;
3190+ return mlxsw_sp_fib_entry_decap_init (mlxsw_sp ,
3191+ fib_entry ,
3192+ ipip_entry );
3193+ }
3194+ /* fall through */
3195+ case RTN_BROADCAST :
30683196 fib_entry -> type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP ;
30693197 return 0 ;
30703198 case RTN_UNREACHABLE : /* fall through */
@@ -3557,6 +3685,9 @@ mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
35573685{
35583686 mlxsw_sp_fib_node_entry_del (mlxsw_sp , & fib4_entry -> common );
35593687 mlxsw_sp_fib4_node_list_remove (fib4_entry );
3688+
3689+ if (fib4_entry -> common .type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP )
3690+ mlxsw_sp_fib_entry_decap_fini (mlxsw_sp , & fib4_entry -> common );
35603691}
35613692
35623693static void mlxsw_sp_fib4_entry_replace (struct mlxsw_sp * mlxsw_sp ,
0 commit comments