Skip to content

Commit 1012b9a

Browse files
pmachatadavem330
authored andcommitted
mlxsw: spectrum_router: Support IPv4 overlay encap
This introduces some common code for tracking of offloaded IP-in-IP tunnels, and support for offloading IPv4 overlay encapsulating routes in particular. A follow-up patch will introduce IPv6 overlay as well. Offloaded tunnels are kept in a linked list of mlxsw_sp_ipip_entry objects hooked up in mlxsw_sp_router. A network device that represents the tunnel is used as a key to look up the corresponding IPIP entry. Note that in the future, more general keying mechanism will be needed, because parts of the tunnel information can be provided by the route. IPIP entries are reference counted, because several next hops may end up using the same tunnel, and we only want to offload it once. Encapsulation path hooks into next hop handling. Routes that forward to a tunnel are now considered gateway routes, thus giving them the same treatment that other remote routes get. An IPIP next hop type is introduced. Details of individual tunnel types are kept in an array of mlxsw_sp_ipip_ops objects. If a tunnel type doesn't match any of the known tunnel types, the next-hop is not considered an IPIP next hop. The list of IPIP tunnel types is currently empty, follow-up patches will add support for GRE. Traffic to IPIP tunnel types that are not explicitly recognized by the driver traps and is handled in slow path. 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 35225e4 commit 1012b9a

File tree

2 files changed

+257
-1
lines changed

2 files changed

+257
-1
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,29 @@ enum mlxsw_sp_ipip_type {
4141
MLXSW_SP_IPIP_TYPE_MAX,
4242
};
4343

44+
struct mlxsw_sp_ipip_entry {
45+
enum mlxsw_sp_ipip_type ipipt;
46+
struct net_device *ol_dev; /* Overlay. */
47+
struct mlxsw_sp_rif_ipip_lb *ol_lb;
48+
unsigned int ref_count; /* Number of next hops using the tunnel. */
49+
struct list_head ipip_list_node;
50+
};
51+
4452
struct mlxsw_sp_ipip_ops {
4553
int dev_type;
4654
enum mlxsw_sp_l3proto ul_proto; /* Underlay. */
55+
56+
int (*nexthop_update)(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
57+
struct mlxsw_sp_ipip_entry *ipip_entry);
58+
59+
bool (*can_offload)(const struct mlxsw_sp *mlxsw_sp,
60+
const struct net_device *ol_dev,
61+
enum mlxsw_sp_l3proto ol_proto);
62+
63+
/* Return a configuration for creating an overlay loopback RIF. */
64+
struct mlxsw_sp_rif_ipip_lb_config
65+
(*ol_loopback_config)(struct mlxsw_sp *mlxsw_sp,
66+
const struct net_device *ol_dev);
4767
};
4868

4969
extern const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[];

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

Lines changed: 237 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ struct mlxsw_sp_router {
8989
struct delayed_work nexthop_probe_dw;
9090
#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
9191
struct list_head nexthop_neighs_list;
92+
struct list_head ipip_list;
9293
bool aborted;
9394
struct notifier_block fib_nb;
9495
const struct mlxsw_sp_rif_ops **rif_ops_arr;
@@ -915,6 +916,170 @@ static u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)
915916
return l3mdev_fib_table(ol_dev) ? : RT_TABLE_MAIN;
916917
}
917918

919+
static struct mlxsw_sp_rif *
920+
mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
921+
const struct mlxsw_sp_rif_params *params);
922+
923+
static struct mlxsw_sp_rif_ipip_lb *
924+
mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp *mlxsw_sp,
925+
enum mlxsw_sp_ipip_type ipipt,
926+
struct net_device *ol_dev)
927+
{
928+
struct mlxsw_sp_rif_params_ipip_lb lb_params;
929+
const struct mlxsw_sp_ipip_ops *ipip_ops;
930+
struct mlxsw_sp_rif *rif;
931+
932+
ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
933+
lb_params = (struct mlxsw_sp_rif_params_ipip_lb) {
934+
.common.dev = ol_dev,
935+
.common.lag = false,
936+
.lb_config = ipip_ops->ol_loopback_config(mlxsw_sp, ol_dev),
937+
};
938+
939+
rif = mlxsw_sp_rif_create(mlxsw_sp, &lb_params.common);
940+
if (IS_ERR(rif))
941+
return ERR_CAST(rif);
942+
return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
943+
}
944+
945+
static struct mlxsw_sp_ipip_entry *
946+
mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
947+
enum mlxsw_sp_ipip_type ipipt,
948+
struct net_device *ol_dev)
949+
{
950+
struct mlxsw_sp_ipip_entry *ipip_entry;
951+
struct mlxsw_sp_ipip_entry *ret = NULL;
952+
953+
ipip_entry = kzalloc(sizeof(*ipip_entry), GFP_KERNEL);
954+
if (!ipip_entry)
955+
return ERR_PTR(-ENOMEM);
956+
957+
ipip_entry->ol_lb = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp, ipipt,
958+
ol_dev);
959+
if (IS_ERR(ipip_entry->ol_lb)) {
960+
ret = ERR_CAST(ipip_entry->ol_lb);
961+
goto err_ol_ipip_lb_create;
962+
}
963+
964+
ipip_entry->ipipt = ipipt;
965+
ipip_entry->ol_dev = ol_dev;
966+
967+
return ipip_entry;
968+
969+
err_ol_ipip_lb_create:
970+
kfree(ipip_entry);
971+
return ret;
972+
}
973+
974+
static void
975+
mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp_ipip_entry *ipip_entry)
976+
{
977+
WARN_ON(ipip_entry->ref_count > 0);
978+
mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
979+
kfree(ipip_entry);
980+
}
981+
982+
static __be32
983+
mlxsw_sp_ipip_netdev_saddr4(const struct net_device *ol_dev)
984+
{
985+
struct ip_tunnel *tun = netdev_priv(ol_dev);
986+
987+
return tun->parms.iph.saddr;
988+
}
989+
990+
union mlxsw_sp_l3addr
991+
mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
992+
const struct net_device *ol_dev)
993+
{
994+
switch (proto) {
995+
case MLXSW_SP_L3_PROTO_IPV4:
996+
return (union mlxsw_sp_l3addr) {
997+
.addr4 = mlxsw_sp_ipip_netdev_saddr4(ol_dev),
998+
};
999+
case MLXSW_SP_L3_PROTO_IPV6:
1000+
break;
1001+
};
1002+
1003+
WARN_ON(1);
1004+
return (union mlxsw_sp_l3addr) {
1005+
.addr4 = 0,
1006+
};
1007+
}
1008+
1009+
static bool mlxsw_sp_l3addr_eq(const union mlxsw_sp_l3addr *addr1,
1010+
const union mlxsw_sp_l3addr *addr2)
1011+
{
1012+
return !memcmp(addr1, addr2, sizeof(*addr1));
1013+
}
1014+
1015+
static bool
1016+
mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,
1017+
const enum mlxsw_sp_l3proto ul_proto,
1018+
union mlxsw_sp_l3addr saddr,
1019+
u32 ul_tb_id,
1020+
struct mlxsw_sp_ipip_entry *ipip_entry)
1021+
{
1022+
u32 tun_ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1023+
enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
1024+
union mlxsw_sp_l3addr tun_saddr;
1025+
1026+
if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1027+
return false;
1028+
1029+
tun_saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
1030+
return tun_ul_tb_id == ul_tb_id &&
1031+
mlxsw_sp_l3addr_eq(&tun_saddr, &saddr);
1032+
}
1033+
1034+
static struct mlxsw_sp_ipip_entry *
1035+
mlxsw_sp_ipip_entry_get(struct mlxsw_sp *mlxsw_sp,
1036+
enum mlxsw_sp_ipip_type ipipt,
1037+
struct net_device *ol_dev)
1038+
{
1039+
u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
1040+
struct mlxsw_sp_router *router = mlxsw_sp->router;
1041+
struct mlxsw_sp_ipip_entry *ipip_entry;
1042+
enum mlxsw_sp_l3proto ul_proto;
1043+
union mlxsw_sp_l3addr saddr;
1044+
1045+
list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1046+
ipip_list_node) {
1047+
if (ipip_entry->ol_dev == ol_dev)
1048+
goto inc_ref_count;
1049+
1050+
/* The configuration where several tunnels have the same local
1051+
* address in the same underlay table needs special treatment in
1052+
* the HW. That is currently not implemented in the driver.
1053+
*/
1054+
ul_proto = router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto;
1055+
saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ol_dev);
1056+
if (mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, saddr,
1057+
ul_tb_id, ipip_entry))
1058+
return ERR_PTR(-EEXIST);
1059+
}
1060+
1061+
ipip_entry = mlxsw_sp_ipip_entry_alloc(mlxsw_sp, ipipt, ol_dev);
1062+
if (IS_ERR(ipip_entry))
1063+
return ipip_entry;
1064+
1065+
list_add_tail(&ipip_entry->ipip_list_node,
1066+
&mlxsw_sp->router->ipip_list);
1067+
1068+
inc_ref_count:
1069+
++ipip_entry->ref_count;
1070+
return ipip_entry;
1071+
}
1072+
1073+
static void
1074+
mlxsw_sp_ipip_entry_put(struct mlxsw_sp *mlxsw_sp,
1075+
struct mlxsw_sp_ipip_entry *ipip_entry)
1076+
{
1077+
if (--ipip_entry->ref_count == 0) {
1078+
list_del(&ipip_entry->ipip_list_node);
1079+
mlxsw_sp_ipip_entry_destroy(ipip_entry);
1080+
}
1081+
}
1082+
9181083
struct mlxsw_sp_neigh_key {
9191084
struct neighbour *n;
9201085
};
@@ -1654,6 +1819,7 @@ static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
16541819

16551820
enum mlxsw_sp_nexthop_type {
16561821
MLXSW_SP_NEXTHOP_TYPE_ETH,
1822+
MLXSW_SP_NEXTHOP_TYPE_IPIP,
16571823
};
16581824

16591825
struct mlxsw_sp_nexthop_key {
@@ -1683,6 +1849,7 @@ struct mlxsw_sp_nexthop {
16831849
enum mlxsw_sp_nexthop_type type;
16841850
union {
16851851
struct mlxsw_sp_neigh_entry *neigh_entry;
1852+
struct mlxsw_sp_ipip_entry *ipip_entry;
16861853
};
16871854
};
16881855

@@ -1970,6 +2137,16 @@ static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
19702137
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
19712138
}
19722139

2140+
static int mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
2141+
u32 adj_index,
2142+
struct mlxsw_sp_nexthop *nh)
2143+
{
2144+
const struct mlxsw_sp_ipip_ops *ipip_ops;
2145+
2146+
ipip_ops = mlxsw_sp->router->ipip_ops_arr[nh->ipip_entry->ipipt];
2147+
return ipip_ops->nexthop_update(mlxsw_sp, adj_index, nh->ipip_entry);
2148+
}
2149+
19732150
static int
19742151
mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
19752152
struct mlxsw_sp_nexthop_group *nh_grp,
@@ -1994,6 +2171,10 @@ mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
19942171
err = mlxsw_sp_nexthop_mac_update
19952172
(mlxsw_sp, adj_index, nh);
19962173
break;
2174+
case MLXSW_SP_NEXTHOP_TYPE_IPIP:
2175+
err = mlxsw_sp_nexthop_ipip_update
2176+
(mlxsw_sp, adj_index, nh);
2177+
break;
19972178
}
19982179
if (err)
19992180
return err;
@@ -2297,6 +2478,46 @@ static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp,
22972478
return false;
22982479
}
22992480

2481+
static int mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
2482+
enum mlxsw_sp_ipip_type ipipt,
2483+
struct mlxsw_sp_nexthop *nh,
2484+
struct net_device *ol_dev)
2485+
{
2486+
if (!nh->nh_grp->gateway || nh->ipip_entry)
2487+
return 0;
2488+
2489+
nh->ipip_entry = mlxsw_sp_ipip_entry_get(mlxsw_sp, ipipt, ol_dev);
2490+
if (IS_ERR(nh->ipip_entry))
2491+
return PTR_ERR(nh->ipip_entry);
2492+
2493+
__mlxsw_sp_nexthop_neigh_update(nh, false);
2494+
return 0;
2495+
}
2496+
2497+
static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp,
2498+
struct mlxsw_sp_nexthop *nh)
2499+
{
2500+
struct mlxsw_sp_ipip_entry *ipip_entry = nh->ipip_entry;
2501+
2502+
if (!ipip_entry)
2503+
return;
2504+
2505+
__mlxsw_sp_nexthop_neigh_update(nh, true);
2506+
mlxsw_sp_ipip_entry_put(mlxsw_sp, ipip_entry);
2507+
nh->ipip_entry = NULL;
2508+
}
2509+
2510+
static bool mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp *mlxsw_sp,
2511+
const struct fib_nh *fib_nh,
2512+
enum mlxsw_sp_ipip_type *p_ipipt)
2513+
{
2514+
struct net_device *dev = fib_nh->nh_dev;
2515+
2516+
return dev &&
2517+
fib_nh->nh_parent->fib_type == RTN_UNICAST &&
2518+
mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, p_ipipt);
2519+
}
2520+
23002521
static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp,
23012522
struct mlxsw_sp_nexthop *nh)
23022523
{
@@ -2305,17 +2526,29 @@ static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp,
23052526
mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
23062527
mlxsw_sp_nexthop_rif_fini(nh);
23072528
break;
2529+
case MLXSW_SP_NEXTHOP_TYPE_IPIP:
2530+
mlxsw_sp_nexthop_ipip_fini(mlxsw_sp, nh);
2531+
break;
23082532
}
23092533
}
23102534

23112535
static int mlxsw_sp_nexthop4_type_init(struct mlxsw_sp *mlxsw_sp,
23122536
struct mlxsw_sp_nexthop *nh,
23132537
struct fib_nh *fib_nh)
23142538
{
2539+
struct mlxsw_sp_router *router = mlxsw_sp->router;
23152540
struct net_device *dev = fib_nh->nh_dev;
2541+
enum mlxsw_sp_ipip_type ipipt;
23162542
struct mlxsw_sp_rif *rif;
23172543
int err;
23182544

2545+
if (mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fib_nh, &ipipt) &&
2546+
router->ipip_ops_arr[ipipt]->can_offload(mlxsw_sp, dev,
2547+
MLXSW_SP_L3_PROTO_IPV4)) {
2548+
nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
2549+
return mlxsw_sp_nexthop_ipip_init(mlxsw_sp, ipipt, nh, dev);
2550+
}
2551+
23192552
nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
23202553
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
23212554
if (!rif)
@@ -2421,7 +2654,8 @@ static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
24212654
static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
24222655
const struct fib_info *fi)
24232656
{
2424-
return fi->fib_nh->nh_scope == RT_SCOPE_LINK;
2657+
return fi->fib_nh->nh_scope == RT_SCOPE_LINK ||
2658+
mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fi->fib_nh, NULL);
24252659
}
24262660

24272661
static struct mlxsw_sp_nexthop_group *
@@ -5411,11 +5645,13 @@ static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
54115645
static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
54125646
{
54135647
mlxsw_sp->router->ipip_ops_arr = mlxsw_sp_ipip_ops_arr;
5648+
INIT_LIST_HEAD(&mlxsw_sp->router->ipip_list);
54145649
return 0;
54155650
}
54165651

54175652
static void mlxsw_sp_ipips_fini(struct mlxsw_sp *mlxsw_sp)
54185653
{
5654+
WARN_ON(!list_empty(&mlxsw_sp->router->ipip_list));
54195655
}
54205656

54215657
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)

0 commit comments

Comments
 (0)