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

Commit 468dfffc authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller
Browse files

geneve: add dst caching support



use generic dst implementation for both plain geneve devices and
lwtunnels.

In case of UDP traffic with datagram length below MTU this give
about 2% performance increase for plain geneve tunnel over ipv4,
about 65% performance increase for ipv6 tunnel.

Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Suggested-and-Acked-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d71785ff
Loading
Loading
Loading
Loading
+39 −0
Original line number Original line Diff line number Diff line
@@ -72,6 +72,7 @@ struct geneve_dev {
	bool		   collect_md;
	bool		   collect_md;
	struct gro_cells   gro_cells;
	struct gro_cells   gro_cells;
	u32		   flags;
	u32		   flags;
	struct dst_cache   dst_cache;
};
};


/* Geneve device flags */
/* Geneve device flags */
@@ -297,6 +298,13 @@ static int geneve_init(struct net_device *dev)
		return err;
		return err;
	}
	}


	err = dst_cache_init(&geneve->dst_cache, GFP_KERNEL);
	if (err) {
		free_percpu(dev->tstats);
		gro_cells_destroy(&geneve->gro_cells);
		return err;
	}

	return 0;
	return 0;
}
}


@@ -304,6 +312,7 @@ static void geneve_uninit(struct net_device *dev)
{
{
	struct geneve_dev *geneve = netdev_priv(dev);
	struct geneve_dev *geneve = netdev_priv(dev);


	dst_cache_destroy(&geneve->dst_cache);
	gro_cells_destroy(&geneve->gro_cells);
	gro_cells_destroy(&geneve->gro_cells);
	free_percpu(dev->tstats);
	free_percpu(dev->tstats);
}
}
@@ -753,7 +762,9 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
				       struct ip_tunnel_info *info)
				       struct ip_tunnel_info *info)
{
{
	struct geneve_dev *geneve = netdev_priv(dev);
	struct geneve_dev *geneve = netdev_priv(dev);
	struct dst_cache *dst_cache;
	struct rtable *rt = NULL;
	struct rtable *rt = NULL;
	bool use_cache = true;
	__u8 tos;
	__u8 tos;


	memset(fl4, 0, sizeof(*fl4));
	memset(fl4, 0, sizeof(*fl4));
@@ -764,16 +775,26 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
		fl4->daddr = info->key.u.ipv4.dst;
		fl4->daddr = info->key.u.ipv4.dst;
		fl4->saddr = info->key.u.ipv4.src;
		fl4->saddr = info->key.u.ipv4.src;
		fl4->flowi4_tos = RT_TOS(info->key.tos);
		fl4->flowi4_tos = RT_TOS(info->key.tos);
		dst_cache = &info->dst_cache;
	} else {
	} else {
		tos = geneve->tos;
		tos = geneve->tos;
		if (tos == 1) {
		if (tos == 1) {
			const struct iphdr *iip = ip_hdr(skb);
			const struct iphdr *iip = ip_hdr(skb);


			tos = ip_tunnel_get_dsfield(iip, skb);
			tos = ip_tunnel_get_dsfield(iip, skb);
			use_cache = false;
		}
		}


		fl4->flowi4_tos = RT_TOS(tos);
		fl4->flowi4_tos = RT_TOS(tos);
		fl4->daddr = geneve->remote.sin.sin_addr.s_addr;
		fl4->daddr = geneve->remote.sin.sin_addr.s_addr;
		dst_cache = &geneve->dst_cache;
	}

	use_cache = use_cache && !skb->mark;
	if (use_cache) {
		rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
		if (rt)
			return rt;
	}
	}


	rt = ip_route_output_key(geneve->net, fl4);
	rt = ip_route_output_key(geneve->net, fl4);
@@ -786,6 +807,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
		ip_rt_put(rt);
		ip_rt_put(rt);
		return ERR_PTR(-ELOOP);
		return ERR_PTR(-ELOOP);
	}
	}
	if (use_cache)
		dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
	return rt;
	return rt;
}
}


@@ -798,6 +821,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
	struct geneve_dev *geneve = netdev_priv(dev);
	struct geneve_dev *geneve = netdev_priv(dev);
	struct geneve_sock *gs6 = geneve->sock6;
	struct geneve_sock *gs6 = geneve->sock6;
	struct dst_entry *dst = NULL;
	struct dst_entry *dst = NULL;
	struct dst_cache *dst_cache;
	bool use_cache = true;
	__u8 prio;
	__u8 prio;


	memset(fl6, 0, sizeof(*fl6));
	memset(fl6, 0, sizeof(*fl6));
@@ -808,16 +833,26 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
		fl6->daddr = info->key.u.ipv6.dst;
		fl6->daddr = info->key.u.ipv6.dst;
		fl6->saddr = info->key.u.ipv6.src;
		fl6->saddr = info->key.u.ipv6.src;
		fl6->flowi6_tos = RT_TOS(info->key.tos);
		fl6->flowi6_tos = RT_TOS(info->key.tos);
		dst_cache = &info->dst_cache;
	} else {
	} else {
		prio = geneve->tos;
		prio = geneve->tos;
		if (prio == 1) {
		if (prio == 1) {
			const struct iphdr *iip = ip_hdr(skb);
			const struct iphdr *iip = ip_hdr(skb);


			prio = ip_tunnel_get_dsfield(iip, skb);
			prio = ip_tunnel_get_dsfield(iip, skb);
			use_cache = false;
		}
		}


		fl6->flowi6_tos = RT_TOS(prio);
		fl6->flowi6_tos = RT_TOS(prio);
		fl6->daddr = geneve->remote.sin6.sin6_addr;
		fl6->daddr = geneve->remote.sin6.sin6_addr;
		dst_cache = &geneve->dst_cache;
	}

	use_cache = use_cache && !skb->mark;
	if (use_cache) {
		dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
		if (dst)
			return dst;
	}
	}


	if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) {
	if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) {
@@ -830,6 +865,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
		return ERR_PTR(-ELOOP);
		return ERR_PTR(-ELOOP);
	}
	}


	if (use_cache)
		dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
	return dst;
	return dst;
}
}
#endif
#endif
@@ -1272,6 +1309,8 @@ static int geneve_configure(struct net *net, struct net_device *dev,
			return -EPERM;
			return -EPERM;
	}
	}


	dst_cache_reset(&geneve->dst_cache);

	err = register_netdevice(dev);
	err = register_netdevice(dev);
	if (err)
	if (err)
		return err;
		return err;