forked from mirrors/linux
		
	net: add dst_cache to ovs vxlan lwtunnel
In case of UDP traffic with datagram length below MTU this give about 2% performance increase when tunneling over ipv4 and about 60% when tunneling over ipv6 Signed-off-by: Paolo Abeni <pabeni@redhat.com> Suggested-and-acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									0c1d70af92
								
							
						
					
					
						commit
						d71785ffc7
					
				
					 6 changed files with 28 additions and 8 deletions
				
			
		| 
						 | 
					@ -1775,7 +1775,7 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
 | 
				
			||||||
	/* when the ip_tunnel_info is availble, the tos used for lookup is
 | 
						/* when the ip_tunnel_info is availble, the tos used for lookup is
 | 
				
			||||||
	 * packet independent, so we can use the cache
 | 
						 * packet independent, so we can use the cache
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (dst_cache && !skb->mark && (!tos || info)) {
 | 
						if (!skb->mark && (!tos || info)) {
 | 
				
			||||||
		use_cache = true;
 | 
							use_cache = true;
 | 
				
			||||||
		rt = dst_cache_get_ip4(dst_cache, saddr);
 | 
							rt = dst_cache_get_ip4(dst_cache, saddr);
 | 
				
			||||||
		if (rt)
 | 
							if (rt)
 | 
				
			||||||
| 
						 | 
					@ -1806,13 +1806,11 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
 | 
				
			||||||
					  struct in6_addr *saddr,
 | 
										  struct in6_addr *saddr,
 | 
				
			||||||
					  struct dst_cache *dst_cache)
 | 
										  struct dst_cache *dst_cache)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool use_cache = false;
 | 
					 | 
				
			||||||
	struct dst_entry *ndst;
 | 
						struct dst_entry *ndst;
 | 
				
			||||||
	struct flowi6 fl6;
 | 
						struct flowi6 fl6;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dst_cache && !skb->mark) {
 | 
						if (!skb->mark) {
 | 
				
			||||||
		use_cache = true;
 | 
					 | 
				
			||||||
		ndst = dst_cache_get_ip6(dst_cache, saddr);
 | 
							ndst = dst_cache_get_ip6(dst_cache, saddr);
 | 
				
			||||||
		if (ndst)
 | 
							if (ndst)
 | 
				
			||||||
			return ndst;
 | 
								return ndst;
 | 
				
			||||||
| 
						 | 
					@ -1832,7 +1830,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
 | 
				
			||||||
		return ERR_PTR(err);
 | 
							return ERR_PTR(err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*saddr = fl6.saddr;
 | 
						*saddr = fl6.saddr;
 | 
				
			||||||
	if (use_cache)
 | 
						if (!skb->mark)
 | 
				
			||||||
		dst_cache_set_ip6(dst_cache, ndst, saddr);
 | 
							dst_cache_set_ip6(dst_cache, ndst, saddr);
 | 
				
			||||||
	return ndst;
 | 
						return ndst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1886,6 +1884,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
 | 
				
			||||||
static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 | 
					static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
			   struct vxlan_rdst *rdst, bool did_rsc)
 | 
								   struct vxlan_rdst *rdst, bool did_rsc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct dst_cache *dst_cache;
 | 
				
			||||||
	struct ip_tunnel_info *info;
 | 
						struct ip_tunnel_info *info;
 | 
				
			||||||
	struct vxlan_dev *vxlan = netdev_priv(dev);
 | 
						struct vxlan_dev *vxlan = netdev_priv(dev);
 | 
				
			||||||
	struct sock *sk;
 | 
						struct sock *sk;
 | 
				
			||||||
| 
						 | 
					@ -1910,6 +1909,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
		dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
 | 
							dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
 | 
				
			||||||
		vni = rdst->remote_vni;
 | 
							vni = rdst->remote_vni;
 | 
				
			||||||
		dst = &rdst->remote_ip;
 | 
							dst = &rdst->remote_ip;
 | 
				
			||||||
 | 
							dst_cache = &rdst->dst_cache;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (!info) {
 | 
							if (!info) {
 | 
				
			||||||
			WARN_ONCE(1, "%s: Missing encapsulation instructions\n",
 | 
								WARN_ONCE(1, "%s: Missing encapsulation instructions\n",
 | 
				
			||||||
| 
						 | 
					@ -1924,6 +1924,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst;
 | 
								remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst;
 | 
				
			||||||
		dst = &remote_ip;
 | 
							dst = &remote_ip;
 | 
				
			||||||
 | 
							dst_cache = &info->dst_cache;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (vxlan_addr_any(dst)) {
 | 
						if (vxlan_addr_any(dst)) {
 | 
				
			||||||
| 
						 | 
					@ -1976,7 +1977,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
		rt = vxlan_get_route(vxlan, skb,
 | 
							rt = vxlan_get_route(vxlan, skb,
 | 
				
			||||||
				     rdst ? rdst->remote_ifindex : 0, tos,
 | 
									     rdst ? rdst->remote_ifindex : 0, tos,
 | 
				
			||||||
				     dst->sin.sin_addr.s_addr, &saddr,
 | 
									     dst->sin.sin_addr.s_addr, &saddr,
 | 
				
			||||||
				     rdst ? &rdst->dst_cache : NULL, info);
 | 
									     dst_cache, info);
 | 
				
			||||||
		if (IS_ERR(rt)) {
 | 
							if (IS_ERR(rt)) {
 | 
				
			||||||
			netdev_dbg(dev, "no route to %pI4\n",
 | 
								netdev_dbg(dev, "no route to %pI4\n",
 | 
				
			||||||
				   &dst->sin.sin_addr.s_addr);
 | 
									   &dst->sin.sin_addr.s_addr);
 | 
				
			||||||
| 
						 | 
					@ -2029,7 +2030,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
		ndst = vxlan6_get_route(vxlan, skb,
 | 
							ndst = vxlan6_get_route(vxlan, skb,
 | 
				
			||||||
					rdst ? rdst->remote_ifindex : 0,
 | 
										rdst ? rdst->remote_ifindex : 0,
 | 
				
			||||||
					&dst->sin6.sin6_addr, &saddr,
 | 
										&dst->sin6.sin6_addr, &saddr,
 | 
				
			||||||
					rdst ? &rdst->dst_cache : NULL);
 | 
										dst_cache);
 | 
				
			||||||
		if (IS_ERR(ndst)) {
 | 
							if (IS_ERR(ndst)) {
 | 
				
			||||||
			netdev_dbg(dev, "no route to %pI6\n",
 | 
								netdev_dbg(dev, "no route to %pI6\n",
 | 
				
			||||||
				   &dst->sin6.sin6_addr);
 | 
									   &dst->sin6.sin6_addr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,7 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
 | 
				
			||||||
		      sizeof(a->u.tun_info) + a->u.tun_info.options_len);
 | 
							      sizeof(a->u.tun_info) + a->u.tun_info.options_len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void metadata_dst_free(struct metadata_dst *);
 | 
				
			||||||
struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags);
 | 
					struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags);
 | 
				
			||||||
struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);
 | 
					struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +58,9 @@ struct ip_tunnel_key {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ip_tunnel_info {
 | 
					struct ip_tunnel_info {
 | 
				
			||||||
	struct ip_tunnel_key	key;
 | 
						struct ip_tunnel_key	key;
 | 
				
			||||||
 | 
					#ifdef CONFIG_DST_CACHE
 | 
				
			||||||
 | 
						struct dst_cache	dst_cache;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	u8			options_len;
 | 
						u8			options_len;
 | 
				
			||||||
	u8			mode;
 | 
						u8			mode;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,7 +265,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
 | 
				
			||||||
	lwtstate_put(dst->lwtstate);
 | 
						lwtstate_put(dst->lwtstate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dst->flags & DST_METADATA)
 | 
						if (dst->flags & DST_METADATA)
 | 
				
			||||||
		kfree(dst);
 | 
							metadata_dst_free((struct metadata_dst *)dst);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		kmem_cache_free(dst->ops->kmem_cachep, dst);
 | 
							kmem_cache_free(dst->ops->kmem_cachep, dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -395,6 +395,14 @@ struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(metadata_dst_alloc);
 | 
					EXPORT_SYMBOL_GPL(metadata_dst_alloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void metadata_dst_free(struct metadata_dst *md_dst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_DST_CACHE
 | 
				
			||||||
 | 
						dst_cache_destroy(&md_dst->u.tun_info.dst_cache);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						kfree(md_dst);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags)
 | 
					struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int cpu;
 | 
						int cpu;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ config OPENVSWITCH
 | 
				
			||||||
	select LIBCRC32C
 | 
						select LIBCRC32C
 | 
				
			||||||
	select MPLS
 | 
						select MPLS
 | 
				
			||||||
	select NET_MPLS_GSO
 | 
						select NET_MPLS_GSO
 | 
				
			||||||
 | 
						select DST_CACHE
 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
	  Open vSwitch is a multilayer Ethernet switch targeted at virtualized
 | 
						  Open vSwitch is a multilayer Ethernet switch targeted at virtualized
 | 
				
			||||||
	  environments.  In addition to supporting a variety of features
 | 
						  environments.  In addition to supporting a variety of features
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1959,6 +1959,12 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
 | 
				
			||||||
	if (!tun_dst)
 | 
						if (!tun_dst)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							dst_release((struct dst_entry *)tun_dst);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
 | 
						a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
 | 
				
			||||||
			 sizeof(*ovs_tun), log);
 | 
								 sizeof(*ovs_tun), log);
 | 
				
			||||||
	if (IS_ERR(a)) {
 | 
						if (IS_ERR(a)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue