Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2549970 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-GRE-offloading-fixes'



Jiri Pirko says:

====================
mlxsw: GRE offloading fixes

Petr says:

This patchset fixes a couple bugs in offloading GRE tunnels in mlxsw
driver.

Patch #1 fixes a problem that local routes pointing at a GRE tunnel
device are offloaded even if that netdevice is down.

Patch #2 detects that as a result of moving a GRE netdevice to a
different VRF, two tunnels now have a conflict of local addresses,
something that the mlxsw driver can't offload.

Patch #3 fixes a FIB abort caused by forming a route pointing at a
GRE tunnel that is eligible for offloading but already onloaded.

Patch #4 fixes a problem that next hops migrated to a new RIF kept the
old RIF reference, which went dangling shortly afterwards.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 32f0160c 09dbf629
Loading
Loading
Loading
Loading
+69 −40
Original line number Original line Diff line number Diff line
@@ -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);
		mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
}
}


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 *rif);
					 struct mlxsw_sp_rif *old_rif,
					 struct mlxsw_sp_rif *new_rif);
static int
static int
mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_ipip_entry *ipip_entry,
				 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);
		return PTR_ERR(new_lb_rif);
	ipip_entry->ol_lb = new_lb_rif;
	ipip_entry->ol_lb = new_lb_rif;


	if (keep_encap) {
	if (keep_encap)
		list_splice_init(&old_lb_rif->common.nexthop_list,
		mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, &old_lb_rif->common,
				 &new_lb_rif->common.nexthop_list);
					     &new_lb_rif->common);
		mlxsw_sp_nexthop_rif_update(mlxsw_sp, &new_lb_rif->common);
	}


	mlxsw_sp_rif_destroy(&old_lb_rif->common);
	mlxsw_sp_rif_destroy(&old_lb_rif->common);


	return 0;
	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
 * Update the offload related to an IPIP entry. This always updates decap, and
 * in addition to that it also:
 * in addition to that it also:
@@ -1449,9 +1451,27 @@ static int mlxsw_sp_netdevice_ipip_ol_vrf_event(struct mlxsw_sp *mlxsw_sp,
{
{
	struct mlxsw_sp_ipip_entry *ipip_entry =
	struct mlxsw_sp_ipip_entry *ipip_entry =
		mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
		mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
	enum mlxsw_sp_l3proto ul_proto;
	union mlxsw_sp_l3addr saddr;
	u32 ul_tb_id;


	if (!ipip_entry)
	if (!ipip_entry)
		return 0;
		return 0;

	/* For flat configuration cases, moving overlay to a different VRF might
	 * cause local address conflict, and the conflicting tunnels need to be
	 * demoted.
	 */
	ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
	ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto;
	saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ol_dev);
	if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
						 saddr, ul_tb_id,
						 ipip_entry)) {
		mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
		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, false, false, extack);
						   true, false, false, extack);
}
}
@@ -3343,22 +3363,19 @@ static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev)
	return ul_dev ? (ul_dev->flags & IFF_UP) : true;
	return ul_dev ? (ul_dev->flags & IFF_UP) : true;
}
}


static int mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
				       struct mlxsw_sp_nexthop *nh,
				       struct mlxsw_sp_nexthop *nh,
				      struct net_device *ol_dev)
				       struct mlxsw_sp_ipip_entry *ipip_entry)
{
{
	bool removing;
	bool removing;


	if (!nh->nh_grp->gateway || nh->ipip_entry)
	if (!nh->nh_grp->gateway || nh->ipip_entry)
		return 0;
		return;

	nh->ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
	if (!nh->ipip_entry)
		return -ENOENT;


	removing = !mlxsw_sp_ipip_netdev_ul_up(ol_dev);
	nh->ipip_entry = ipip_entry;
	removing = !mlxsw_sp_ipip_netdev_ul_up(ipip_entry->ol_dev);
	__mlxsw_sp_nexthop_neigh_update(nh, removing);
	__mlxsw_sp_nexthop_neigh_update(nh, removing);
	return 0;
	mlxsw_sp_nexthop_rif_init(nh, &ipip_entry->ol_lb->common);
}
}


static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp,
static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp,
@@ -3403,22 +3420,22 @@ static int mlxsw_sp_nexthop4_type_init(struct mlxsw_sp *mlxsw_sp,
				       struct mlxsw_sp_nexthop *nh,
				       struct mlxsw_sp_nexthop *nh,
				       struct fib_nh *fib_nh)
				       struct fib_nh *fib_nh)
{
{
	struct mlxsw_sp_router *router = mlxsw_sp->router;
	const struct mlxsw_sp_ipip_ops *ipip_ops;
	struct net_device *dev = fib_nh->nh_dev;
	struct net_device *dev = fib_nh->nh_dev;
	enum mlxsw_sp_ipip_type ipipt;
	struct mlxsw_sp_ipip_entry *ipip_entry;
	struct mlxsw_sp_rif *rif;
	struct mlxsw_sp_rif *rif;
	int err;
	int err;


	if (mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fib_nh, &ipipt) &&
	ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
	    router->ipip_ops_arr[ipipt]->can_offload(mlxsw_sp, dev,
	if (ipip_entry) {
		ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
		if (ipip_ops->can_offload(mlxsw_sp, dev,
					  MLXSW_SP_L3_PROTO_IPV4)) {
					  MLXSW_SP_L3_PROTO_IPV4)) {
			nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
			nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
		err = mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, dev);
			mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
		if (err)
			return err;
		mlxsw_sp_nexthop_rif_init(nh, &nh->ipip_entry->ol_lb->common);
			return 0;
			return 0;
		}
		}
	}


	nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
	nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
	rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
	rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
@@ -3545,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,
static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
					   struct mlxsw_sp_rif *rif)
					   struct mlxsw_sp_rif *rif)
{
{
@@ -3996,7 +4025,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
	case RTN_LOCAL:
	case RTN_LOCAL:
		ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, dev,
		ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, dev,
						 MLXSW_SP_L3_PROTO_IPV4, dip);
						 MLXSW_SP_L3_PROTO_IPV4, dip);
		if (ipip_entry) {
		if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
			fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
			fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
			return mlxsw_sp_fib_entry_decap_init(mlxsw_sp,
			return mlxsw_sp_fib_entry_decap_init(mlxsw_sp,
							     fib_entry,
							     fib_entry,
@@ -4694,22 +4723,22 @@ static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
				       struct mlxsw_sp_nexthop *nh,
				       struct mlxsw_sp_nexthop *nh,
				       const struct rt6_info *rt)
				       const struct rt6_info *rt)
{
{
	struct mlxsw_sp_router *router = mlxsw_sp->router;
	const struct mlxsw_sp_ipip_ops *ipip_ops;
	struct mlxsw_sp_ipip_entry *ipip_entry;
	struct net_device *dev = rt->dst.dev;
	struct net_device *dev = rt->dst.dev;
	enum mlxsw_sp_ipip_type ipipt;
	struct mlxsw_sp_rif *rif;
	struct mlxsw_sp_rif *rif;
	int err;
	int err;


	if (mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, &ipipt) &&
	ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
	    router->ipip_ops_arr[ipipt]->can_offload(mlxsw_sp, dev,
	if (ipip_entry) {
		ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
		if (ipip_ops->can_offload(mlxsw_sp, dev,
					  MLXSW_SP_L3_PROTO_IPV6)) {
					  MLXSW_SP_L3_PROTO_IPV6)) {
			nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
			nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
		err = mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, dev);
			mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
		if (err)
			return err;
		mlxsw_sp_nexthop_rif_init(nh, &nh->ipip_entry->ol_lb->common);
			return 0;
			return 0;
		}
		}
	}


	nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
	nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
	rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
	rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);