mlxsw: spectrum_router: Use existing decap route

The local route that points at IPIP's underlay device (decap route) can
be present long before the GRE device. Thus when an encap route is
added, it's necessary to look inside the underlay FIB if the decap route
is already present. If so, the current trap offload needs to be
withdrawn and replaced with a decap offload.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Petr Machata 2017-09-02 23:49:26 +02:00 committed by David S. Miller
parent 4607f6d269
commit 1cc38fb144
1 changed files with 76 additions and 4 deletions

View File

@ -1072,6 +1072,9 @@ static void mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_kvdl_free(mlxsw_sp, fib_entry->decap.tunnel_index);
}
static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
size_t addr_len, unsigned char prefix_len);
static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry);
@ -1087,6 +1090,73 @@ mlxsw_sp_ipip_entry_demote_decap(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
}
static void
mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
struct mlxsw_sp_fib_entry *decap_fib_entry)
{
if (mlxsw_sp_fib_entry_decap_init(mlxsw_sp, decap_fib_entry,
ipip_entry))
return;
decap_fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
if (mlxsw_sp_fib_entry_update(mlxsw_sp, decap_fib_entry))
mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
}
/* Given an IPIP entry, find the corresponding decap route. */
static struct mlxsw_sp_fib_entry *
mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry)
{
static struct mlxsw_sp_fib_node *fib_node;
const struct mlxsw_sp_ipip_ops *ipip_ops;
struct mlxsw_sp_fib_entry *fib_entry;
unsigned char saddr_prefix_len;
union mlxsw_sp_l3addr saddr;
struct mlxsw_sp_fib *ul_fib;
struct mlxsw_sp_vr *ul_vr;
const void *saddrp;
size_t saddr_len;
u32 ul_tb_id;
u32 saddr4;
ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
ul_vr = mlxsw_sp_vr_find(mlxsw_sp, ul_tb_id);
if (!ul_vr)
return NULL;
ul_fib = mlxsw_sp_vr_fib(ul_vr, ipip_ops->ul_proto);
saddr = mlxsw_sp_ipip_netdev_saddr(ipip_ops->ul_proto,
ipip_entry->ol_dev);
switch (ipip_ops->ul_proto) {
case MLXSW_SP_L3_PROTO_IPV4:
saddr4 = be32_to_cpu(saddr.addr4);
saddrp = &saddr4;
saddr_len = 4;
saddr_prefix_len = 32;
break;
case MLXSW_SP_L3_PROTO_IPV6:
WARN_ON(1);
return NULL;
}
fib_node = mlxsw_sp_fib_node_lookup(ul_fib, saddrp, saddr_len,
saddr_prefix_len);
if (!fib_node || list_empty(&fib_node->entry_list))
return NULL;
fib_entry = list_first_entry(&fib_node->entry_list,
struct mlxsw_sp_fib_entry, list);
if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP)
return NULL;
return fib_entry;
}
static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_get(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_sp_ipip_type ipipt,
@ -1094,6 +1164,7 @@ mlxsw_sp_ipip_entry_get(struct mlxsw_sp *mlxsw_sp,
{
u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
struct mlxsw_sp_router *router = mlxsw_sp->router;
struct mlxsw_sp_fib_entry *decap_fib_entry;
struct mlxsw_sp_ipip_entry *ipip_entry;
enum mlxsw_sp_l3proto ul_proto;
union mlxsw_sp_l3addr saddr;
@ -1118,6 +1189,11 @@ mlxsw_sp_ipip_entry_get(struct mlxsw_sp *mlxsw_sp,
if (IS_ERR(ipip_entry))
return ipip_entry;
decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp, ipip_entry);
if (decap_fib_entry)
mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
decap_fib_entry);
list_add_tail(&ipip_entry->ipip_list_node,
&mlxsw_sp->router->ipip_list);
@ -3259,10 +3335,6 @@ static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
kfree(fib4_entry);
}
static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
size_t addr_len, unsigned char prefix_len);
static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp *mlxsw_sp,
const struct fib_entry_notifier_info *fen_info)