mlxsw: spectrum_router: Update nexthop RIF on update

The function mlxsw_sp_nexthop_rif_update() walks the list of nexthops
associated with a RIF, and updates the corresponding entries in the
switch. It is used in particular when a tunnel underlay netdevice moves
to a different VRF, and all the nexthops are migrated over to a new RIF.
The problem is that each nexthop holds a reference to its RIF, and that
is not updated. So after the old RIF is gone, further activity on these
nexthops (such as downing the underlay netdevice) dereferences a
dangling pointer.

Fix the issue by updating rif of impacted nexthops before calling
mlxsw_sp_nexthop_rif_update().

Fixes: 0c5f1cd5ba ("mlxsw: spectrum_router: Generalize __mlxsw_sp_ipip_entry_update_tunnel()")
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-11-28 13:17:14 +01:00 committed by David S. Miller
parent d97cda5f46
commit 09dbf6297f
1 changed files with 21 additions and 7 deletions

View File

@ -1370,8 +1370,9 @@ static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
}
static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif);
static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *old_rif,
struct mlxsw_sp_rif *new_rif);
static int
mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
@ -1389,17 +1390,18 @@ mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
return PTR_ERR(new_lb_rif);
ipip_entry->ol_lb = new_lb_rif;
if (keep_encap) {
list_splice_init(&old_lb_rif->common.nexthop_list,
&new_lb_rif->common.nexthop_list);
mlxsw_sp_nexthop_rif_update(mlxsw_sp, &new_lb_rif->common);
}
if (keep_encap)
mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, &old_lb_rif->common,
&new_lb_rif->common);
mlxsw_sp_rif_destroy(&old_lb_rif->common);
return 0;
}
static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif);
/**
* Update the offload related to an IPIP entry. This always updates decap, and
* in addition to that it also:
@ -3560,6 +3562,18 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
}
}
static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *old_rif,
struct mlxsw_sp_rif *new_rif)
{
struct mlxsw_sp_nexthop *nh;
list_splice_init(&old_rif->nexthop_list, &new_rif->nexthop_list);
list_for_each_entry(nh, &new_rif->nexthop_list, rif_list_node)
nh->rif = new_rif;
mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif);
}
static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif)
{