Commit c5731cc5 authored by Petr Machata's avatar Petr Machata Committed by Jakub Kicinski

mlxsw: spectrum_router: After underlay moves, demote conflicting tunnels

When a GRE tunnel is bound to an underlay netdevice and that netdevice is
moved to a different VRF, that could cause two tunnels to have the same
underlay local address in the same VRF. Linux in this situation dispatches
the traffic according to the tunnel key (or lack thereof), but that cannot
be offloaded to Spectrum devices.

Detect this situation and unoffload the two impacted tunnels when it
happens.
Signed-off-by: default avatarPetr Machata <petrm@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
parent c392bccf
...@@ -1614,8 +1614,25 @@ static int ...@@ -1614,8 +1614,25 @@ static int
mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry, struct mlxsw_sp_ipip_entry *ipip_entry,
struct net_device *ul_dev, struct net_device *ul_dev,
bool *demote_this,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN;
enum mlxsw_sp_l3proto ul_proto;
union mlxsw_sp_l3addr saddr;
/* Moving underlay to a different VRF might cause local address
* conflict, and the conflicting tunnels need to be demoted.
*/
ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto;
saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
saddr, ul_tb_id,
ipip_entry)) {
*demote_this = true;
return 0;
}
return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
true, true, false, extack); true, true, false, extack);
} }
...@@ -1766,6 +1783,7 @@ static int ...@@ -1766,6 +1783,7 @@ static int
__mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry, struct mlxsw_sp_ipip_entry *ipip_entry,
struct net_device *ul_dev, struct net_device *ul_dev,
bool *demote_this,
unsigned long event, unsigned long event,
struct netdev_notifier_info *info) struct netdev_notifier_info *info)
{ {
...@@ -1780,6 +1798,7 @@ __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, ...@@ -1780,6 +1798,7 @@ __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp, return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp,
ipip_entry, ipip_entry,
ul_dev, ul_dev,
demote_this,
extack); extack);
break; break;
...@@ -1806,13 +1825,31 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, ...@@ -1806,13 +1825,31 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp,
ul_dev, ul_dev,
ipip_entry))) { ipip_entry))) {
struct mlxsw_sp_ipip_entry *prev;
bool demote_this = false;
err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry, err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry,
ul_dev, event, info); ul_dev, &demote_this,
event, info);
if (err) { if (err) {
mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp, mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp,
ul_dev); ul_dev);
return err; return err;
} }
if (demote_this) {
if (list_is_first(&ipip_entry->ipip_list_node,
&mlxsw_sp->router->ipip_list))
prev = NULL;
else
/* This can't be cached from previous iteration,
* because that entry could be gone now.
*/
prev = list_prev_entry(ipip_entry,
ipip_list_node);
mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
ipip_entry = prev;
}
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment