Skip to content

Commit 4607f6d

Browse files
pmachatadavem330
authored andcommitted
mlxsw: spectrum_router: Support IPv4 underlay decap
Unlike encapsulation, which is represented by a next hop forwarding to an IPIP tunnel, decapsulation is a type of local route. It is created for local routes whose prefix corresponds to the local address of one of offloaded IPIP tunnels. When the tunnel is removed (i.e. all the encap next hops are removed), the decap offload is migrated back to a trap for resolution in slow path. This patch assumes that decap route is already present when encap route is added. A follow-up patch will fix this issue. Note that this patch only supports IPv4 underlay. Support for IPv6 underlay will be subject to follow-up work apart from this patchset. Signed-off-by: Petr Machata <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8f28a30 commit 4607f6d

File tree

3 files changed

+146
-5
lines changed

3 files changed

+146
-5
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#define _MLXSW_IPIP_H_
3737

3838
#include "spectrum_router.h"
39+
#include <net/ip_fib.h>
3940

4041
enum mlxsw_sp_ipip_type {
4142
MLXSW_SP_IPIP_TYPE_MAX,
@@ -46,6 +47,7 @@ struct mlxsw_sp_ipip_entry {
4647
struct net_device *ol_dev; /* Overlay. */
4748
struct mlxsw_sp_rif_ipip_lb *ol_lb;
4849
unsigned int ref_count; /* Number of next hops using the tunnel. */
50+
struct mlxsw_sp_fib_entry *decap_fib_entry;
4951
struct list_head ipip_list_node;
5052
};
5153

@@ -64,6 +66,11 @@ struct mlxsw_sp_ipip_ops {
6466
struct mlxsw_sp_rif_ipip_lb_config
6567
(*ol_loopback_config)(struct mlxsw_sp *mlxsw_sp,
6668
const struct net_device *ol_dev);
69+
70+
int (*fib_entry_op)(struct mlxsw_sp *mlxsw_sp,
71+
struct mlxsw_sp_ipip_entry *ipip_entry,
72+
enum mlxsw_reg_ralue_op op,
73+
u32 tunnel_index);
6774
};
6875

6976
extern const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[];

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

Lines changed: 136 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

386394
struct 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+
397410
struct 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

405419
struct 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+
10341090
static struct mlxsw_sp_ipip_entry *
10351091
mlxsw_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+
10831180
struct 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-
21922286
static bool
21932287
mlxsw_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+
30183131
static 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

35623693
static void mlxsw_sp_fib4_entry_replace(struct mlxsw_sp *mlxsw_sp,

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,8 @@ mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp *mlxsw_sp,
9797
struct mlxsw_sp_neigh_entry *neigh_entry,
9898
bool adding);
9999
bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry);
100+
union mlxsw_sp_l3addr
101+
mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
102+
const struct net_device *ol_dev);
100103

101104
#endif /* _MLXSW_ROUTER_H_*/

0 commit comments

Comments
 (0)