net: unify dst caching for tunnel devices
Subsystems (5)
Paolo Abeni
maintainerv2 cover net: unify dst caching for tunnel devices
This patch series try to unify the dst cache implementations currently present in the kernel, namely in ip_tunnel.c and ip6_tunnel.c, introducing a new generic implementation, replacing the existing ones, and then using the new implementation in other tunnel devices which currently lack it.
The new dst implementation is compiled, as built-in, only if any device using it is enabled.
Caching the dst for the tunnel remote address gives small, but measurable, performance improvement when tunneling over ipv4 (in the 2%-4% range) and significant ones when tunneling over ipv6 (roughly 60% when no fragmentation/segmentation take place and the tunnel local address is not specified).
v2:
- move the vxlan dst_cache usage inside the device lookup functions
- fix usage after free for lwt tunnel moving the dst cache storage inside the dst_metadata,
- sparse codying style cleanup
Paolo Abeni (7):
net: add dst_cache support
net: replace dst_cache ip6_tunnel implementation with the generic one
ip_tunnel: replace dst_cache with generic implementation
net: use dst_cache for vxlan device
net: add dst_cache to ovs vxlan lwtunnel
geneve: add dst caching support
net/ipv4: add dst cache support for gre lwtunnels
drivers/net/geneve.c | 39 ++++++++++ drivers/net/vxlan.c | 56 ++++++++++++-- include/net/dst_cache.h | 97 ++++++++++++++++++++++++ include/net/dst_metadata.h | 1 + include/net/ip6_tunnel.h | 14 +--- include/net/ip_tunnels.h | 12 ++- include/net/vxlan.h | 1 + net/Kconfig | 4 + net/core/Makefile | 1 + net/core/dst.c | 10 ++- net/core/dst_cache.c | 168 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/Kconfig | 1 + net/ipv4/ip_gre.c | 13 +++- net/ipv4/ip_tunnel.c | 78 ++++--------------- net/ipv6/Kconfig | 1 + net/ipv6/ip6_gre.c | 12 +-- net/ipv6/ip6_tunnel.c | 103 ++----------------------- net/ipv6/ip6_vti.c | 2 +- net/ipv6/sit.c | 17 +++-- net/openvswitch/Kconfig | 1 + net/openvswitch/flow_netlink.c | 6 ++ 21 files changed, 429 insertions(+), 208 deletions(-) create mode 100644 include/net/dst_cache.h create mode 100644 net/core/dst_cache.c
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 1/7 net: add dst_cache support
This patch add a generic, lockless dst cache implementation. The need for lock is avoided updating the dst cache fields only in per cpu scope, and requiring that the cache manipulation functions are invoked with the local bh disabled.
The refresh_ts and reset_ts fields are used to ensure the cache consistency in case of cuncurrent cache update (dst_cache_set*) and reset operation (dst_cache_reset).
Consider the following scenario:
CPU1: CPU2:
<cache lookup with emtpy cache: it fails>
<get dst via uncached route lookup>
<related configuration changes> dst_cache_reset()
dst_cache_set()
The dst entry set passed to dst_cache_set() should not be used for later dst cache lookup, because it's obtained using old configuration values.
Since the refresh_ts is updated only on dst_cache lookup, the cached value in the above scenario will be discarded on the next lookup.
---
v2: protect lookup functions against uninitalized cache access
--- include/net/dst_cache.h | 97 ++++++++++++++++++++++++++++ net/Kconfig | 4 ++ net/core/Makefile | 1 + net/core/dst_cache.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 include/net/dst_cache.h create mode 100644 net/core/dst_cache.c
include/net/dst_cache.h new file +97 -0
@@ -0,0 +1,97 @@ +#ifndef _NET_DST_CACHE_H +#define _NET_DST_CACHE_H + +#include <linux/jiffies.h> +#include <net/dst.h> +#if IS_ENABLED (CONFIG_IPV6 ) +#include <net/ip6_fib.h> +#endif + +struct dst_cache { +struct dst_cache_pcpu __percpu *cache; +unsigned long reset_ts; +}; + +/** +* dst_cache_get - perform cache lookup +* @dst_cache: the cache +* +* The caller should use dst_cache_get_ip4() if it need to retrieve the +* source address to be used when xmitting to the cached dst. +* local BH must be disabled. +*/ +struct dst_entry *dst_cache_get (struct dst_cache *dst_cache); + +/** +* dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address +* @dst_cache: the cache +* @saddr: return value for the retrieved source address +* +* local BH must be disabled. +*/ +struct rtable *dst_cache_get_ip4 (struct dst_cache *dst_cache,__be32 *saddr); + +/** +* dst_cache_set_ip4 - store the ipv4 dst into the cache +* @dst_cache: the cache +* @dst: the entry to be cached +* @saddr: the source address to be stored inside the cache +* +* local BH must be disabled. +*/ +void dst_cache_set_ip4 (struct dst_cache *dst_cache,struct dst_entry *dst, +__be32 saddr); + +#if IS_ENABLED (CONFIG_IPV6 ) + +/** +* dst_cache_set_ip6 - store the ipv6 dst into the cache +* @dst_cache: the cache +* @dst: the entry to be cached +* @saddr: the source address to be stored inside the cache +* +* local BH must be disabled. +*/ +void dst_cache_set_ip6 (struct dst_cache *dst_cache,struct dst_entry *dst, +const struct in6_addr *addr); + +/** +* dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address +* @dst_cache: the cache +* @saddr: return value for the retrieved source address +* +* local BH must be disabled. +*/ +struct dst_entry *dst_cache_get_ip6 (struct dst_cache *dst_cache, +struct in6_addr *saddr); +#endif + +/** +* dst_cache_reset - invalidate the cache contents +* @dst_cache: the cache +* +* This do not free the cached dst to avoid races and contentions. +* the dst will be freed on later cache lookup. +*/ +static inline void dst_cache_reset (struct dst_cache *dst_cache) +{ + dst_cache->reset_ts = jiffies; +} + +/** +* dst_cache_init - initialize the cache, allocating the required storage +* @dst_cache: the cache +* @gfp: allocation flags +*/ +int dst_cache_init (struct dst_cache *dst_cache,gfp_t gfp); + +/** +* dst_cache_destroy - empty the cache and free the allocated storage +* @dst_cache: the cache +* +* No synchronization is enforced: it must be called only when the cache +* is unsed. +*/ +void dst_cache_destroy (struct dst_cache *dst_cache); + +#endif
net/Kconfig +4 -0
@@ -392,6 +392,10 @@ config LWTUNNEL weight tunnel endpoint. Tunnel encapsulation parameters are stored with light weight tunnel state associated with fib routes. +config DST_CACHE + bool "dst cache" + default n + endif # if NET # Used by archs to tell that they support BPF_JIT
net/core/Makefile +1 -0
@@ -24,3 +24,4 @@ obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o obj-$(CONFIG_LWTUNNEL) += lwtunnel.o +obj-$(CONFIG_DST_CACHE) += dst_cache.o
net/core/dst_cache.c new file +168 -0
168 lines not on this page · raw message
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 2/7 net: replace dst_cache ip6_tunnel implementation with the generic one
In reply to Paolo AbeniThis also fix a potential race into the existing tunnel code, which could lead to the wrong dst to be permanenty cached:
CPU1: CPU2:
<xmit on ip6_tunnel>
<cache lookup fails>
dst = ip6_route_output(...)
<tunnel params are changed via nl> dst_cache_reset() // no effect,
// the cache is empty
dst_cache_set() // the wrong dst
// is permanenty stored // into the cache
With the new dst implementation the above race is not possible since the first cache lookup after dst_cache_reset will fail due to the timestamp check
--- include/net/ip6_tunnel.h | 14 +------ net/ipv6/Kconfig | 1 + net/ipv6/ip6_gre.c | 12 +++--- net/ipv6/ip6_tunnel.c | 103 +++-------------------------------------------- net/ipv6/ip6_vti.c | 2 +- 5 files changed, 16 insertions(+), 116 deletions(-)
include/net/ip6_tunnel.h +2 -12
@@ -6,6 +6,7 @@#include <linux/if_tunnel.h> #include <linux/ip6_tunnel.h> #include <net/ip_tunnels.h> +#include <net/dst_cache.h> #define IP6TUNNEL_ERR_TIMEO (30*HZ)
@@ -33,12 +34,6 @@ struct __ip6_tnl_parm {__be32 o_key; }; -struct ip6_tnl_dst { -seqlock_t lock; -struct dst_entry __rcu *dst; -u32 cookie; -}; -/* IPv6 tunnel */ struct ip6_tnl {struct ip6_tnl __rcu *next;/* next tunnel in list */
@@ -46,7 +41,7 @@ struct ip6_tnl {struct net *net;/* netns for packet i/o */ struct __ip6_tnl_parm parms;/* tunnel configuration parameters */ struct flowi fl;/* flowi template for xmit */ -struct ip6_tnl_dst __percpu *dst_cache;/* cached dst */ +struct dst_cache dst_cache;/* cached dst */ int err_count;unsigned long err_time;
@@ -66,11 +61,6 @@ struct ipv6_tlv_tnl_enc_lim {__u8 encap_limit;/* tunnel encapsulation limit */ } __packed; -struct dst_entry *ip6_tnl_dst_get (struct ip6_tnl *t); -int ip6_tnl_dst_init (struct ip6_tnl *t); -void ip6_tnl_dst_destroy (struct ip6_tnl *t); -void ip6_tnl_dst_reset (struct ip6_tnl *t); -void ip6_tnl_dst_set (struct ip6_tnl *t,struct dst_entry *dst);int ip6_tnl_rcv_ctl (struct ip6_tnl *t,const struct in6_addr *laddr,const struct in6_addr *raddr); int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
net/ipv6/Kconfig +1 -0
@@ -207,6 +207,7 @@ config IPV6_NDISC_NODETYPE config IPV6_TUNNEL tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)" select INET6_TUNNEL + select DST_CACHE ---help--- Support for IPv6-in-IPv6 and IPv4-in-IPv6 tunnels described in RFC 2473.
net/ipv6/ip6_gre.c +6 -6
@@ -360,7 +360,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)struct ip6gre_net *ign =net_generic (t->net, ip6gre_net_id);ip6gre_tunnel_unlink (ign, t); -ip6_tnl_dst_reset (t); +dst_cache_reset (&t->dst_cache);dev_put (dev); }
@@ -633,7 +633,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, }if (!fl6->flowi6_mark) - dst =ip6_tnl_dst_get (tunnel); + dst =dst_cache_get (&tunnel->dst_cache);if (!dst) { dst =ip6_route_output (net,NULL , fl6);
@@ -702,7 +702,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, }if (!fl6->flowi6_mark && ndst) -ip6_tnl_dst_set (tunnel, ndst); +dst_cache_set_ip6 (&tunnel->dst_cache, ndst, &fl6->saddr);skb_dst_set (skb, dst); proto =NEXTHDR_GRE ;
@@ -1009,7 +1009,7 @@ static int ip6gre_tnl_change(struct ip6_tnl *t, t->parms.o_key = p->o_key; t->parms.i_flags = p->i_flags; t->parms.o_flags = p->o_flags; -ip6_tnl_dst_reset (t); +dst_cache_reset (&t->dst_cache);ip6gre_tnl_link_config (t, set_mtu);return 0 ; }
@@ -1219,7 +1219,7 @@ static void ip6gre_dev_free(struct net_device *dev) {struct ip6_tnl *t =netdev_priv (dev); -ip6_tnl_dst_destroy (t); +dst_cache_destroy (&t->dst_cache);free_percpu (dev->tstats);free_netdev (dev); }
@@ -1257,7 +1257,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)if (!dev->tstats)return -ENOMEM ; - ret =ip6_tnl_dst_init (tunnel); + ret =dst_cache_init (&tunnel->dst_cache,GFP_KERNEL );if (ret) {free_percpu (dev->tstats); dev->tstats =NULL ;
net/ipv6/ip6_tunnel.c +6 -97
145 lines not on this page · raw message
net/ipv6/ip6_vti.c +1 -1
@@ -640,7 +640,7 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) t->parms.i_key = p->i_key; t->parms.o_key = p->o_key; t->parms.proto = p->proto; -ip6_tnl_dst_reset (t); +dst_cache_reset (&t->dst_cache);vti6_link_config (t);return 0 ; }
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 3/7 ip_tunnel: replace dst_cache with generic implementation
In reply to Paolo AbeniThe current ip_tunnel cache implementation is prone to a race that will cause the wrong dst to be cached on cuncurrent dst cache miss and ip tunnel update via netlink.
Replacing with the generic implementation fix the issue.
--- include/net/ip_tunnels.h | 9 ++---- net/ipv4/Kconfig | 1 + net/ipv4/ip_tunnel.c | 78 ++++++++---------------------------------------- net/ipv6/sit.c | 17 ++++++----- 4 files changed, 25 insertions(+), 80 deletions(-)
include/net/ip_tunnels.h +2 -7
@@ -13,6 +13,7 @@#include <net/netns/generic.h> #include <net/rtnetlink.h> #include <net/lwtunnel.h> +#include <net/dst_cache.h> #if IS_ENABLED (CONFIG_IPV6 )#include <net/ipv6.h>
@@ -85,11 +86,6 @@ struct ip_tunnel_prl_entry {struct rcu_head rcu_head; }; -struct ip_tunnel_dst { -struct dst_entry __rcu *dst; -__be32 saddr; -}; -struct metadata_dst ;struct ip_tunnel {
@@ -108,7 +104,7 @@ struct ip_tunnel {int tun_hlen;/* Precalculated header length */ int mlink; -struct ip_tunnel_dst __percpu *dst_cache; +struct dst_cache dst_cache;struct ip_tunnel_parm parms;
@@ -247,7 +243,6 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],int ip_tunnel_newlink (struct net_device *dev,struct nlattr *tb[],struct ip_tunnel_parm *p);void ip_tunnel_setup (struct net_device *dev,int net_id); -void ip_tunnel_dst_reset_all (struct ip_tunnel *t);int ip_tunnel_encap_setup (struct ip_tunnel *t,struct ip_tunnel_encap *ipencap);
net/ipv4/Kconfig +1 -0
@@ -186,6 +186,7 @@ config NET_IPGRE_DEMUX config NET_IP_TUNNEL tristate + select DST_CACHE default n config NET_IPGRE
net/ipv4/ip_tunnel.c +13 -65
131 lines not on this page · raw message
net/ipv6/sit.c +9 -8
@@ -475,7 +475,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)ipip6_tunnel_unlink (sitn, tunnel);ipip6_tunnel_del_prl (tunnel,NULL ); } -ip_tunnel_dst_reset_all (tunnel); +dst_cache_reset (&tunnel->dst_cache);dev_put (dev); }
@@ -1093,7 +1093,7 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) t->parms.link = p->link;ipip6_tunnel_bind_dev (t->dev); } -ip_tunnel_dst_reset_all (t); +dst_cache_reset (&t->dst_cache);netdev_state_change (t->dev); }
@@ -1124,7 +1124,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t, t->ip6rd.relay_prefix = relay_prefix; t->ip6rd.prefixlen = ip6rd->prefixlen; t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen; -ip_tunnel_dst_reset_all (t); +dst_cache_reset (&t->dst_cache);netdev_state_change (t->dev);return 0 ; }
@@ -1278,7 +1278,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) err =ipip6_tunnel_add_prl (t, &prl, cmd ==SIOCCHGPRL );break ; } -ip_tunnel_dst_reset_all (t); +dst_cache_reset (&t->dst_cache);netdev_state_change (dev);break ;
@@ -1339,7 +1339,7 @@ static void ipip6_dev_free(struct net_device *dev) {struct ip_tunnel *tunnel =netdev_priv (dev); -free_percpu (tunnel->dst_cache); +dst_cache_destroy (&tunnel->dst_cache);free_percpu (dev->tstats);free_netdev (dev); }
@@ -1372,6 +1372,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)static int ipip6_tunnel_init (struct net_device *dev) {struct ip_tunnel *tunnel =netdev_priv (dev); +int err; tunnel->dev = dev; tunnel->net =dev_net (dev);
@@ -1382,10 +1383,10 @@ static int ipip6_tunnel_init(struct net_device *dev)if (!dev->tstats)return -ENOMEM ; - tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst); -if (!tunnel->dst_cache) { + err =dst_cache_init (&tunnel->dst_cache,GFP_KERNEL ); +if (err) {free_percpu (dev->tstats); -return -ENOMEM ; +return err; }return 0 ;
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 4/7 net: use dst_cache for vxlan device
In reply to Paolo AbeniIn case of UDP traffic with datagram length below MTU this give about 3% performance increase when tunneling over ipv4 and about 70% when tunneling over ipv6.
---
v2: move the dst_cache usage into the vxlan lookup functions
--- drivers/net/vxlan.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-------- include/net/vxlan.h | 1 + 2 files changed, 48 insertions(+), 8 deletions(-)
drivers/net/vxlan.c +47 -8
@@ -480,6 +480,8 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f, rd = list_first_entry_or_null(&f->remotes, struct vxlan_rdst, list);if (!rd)return 0 ; + +dst_cache_reset (&rd->dst_cache); rd->remote_ip = *ip; rd->remote_port = port; rd->remote_vni = vni;
@@ -501,6 +503,12 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, rd =kmalloc (sizeof (*rd),GFP_ATOMIC );if (rd ==NULL )return -ENOBUFS ; + +if (dst_cache_init (&rd->dst_cache,GFP_ATOMIC )) { +kfree (rd); +return -ENOBUFS ; + } + rd->remote_ip = *ip; rd->remote_port = port; rd->remote_vni = vni;
@@ -749,8 +757,10 @@ static void vxlan_fdb_free(struct rcu_head *head) struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);struct vxlan_rdst *rd, *nd; -list_for_each_entry_safe (rd, nd, &f->remotes, list) +list_for_each_entry_safe (rd, nd, &f->remotes, list) { +dst_cache_destroy (&rd->dst_cache);kfree (rd); + }kfree (f); }
@@ -1756,11 +1766,24 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,static struct rtable *vxlan_get_route (struct vxlan_dev *vxlan,struct sk_buff *skb,int oif,u8 tos, -__be32 daddr,__be32 *saddr) +__be32 daddr,__be32 *saddr, +struct dst_cache *dst_cache, +struct ip_tunnel_info *info) {struct rtable *rt =NULL ; +bool use_cache = false;struct flowi4 fl4; +/* when the ip_tunnel_info is availble, the tos used for lookup is +* packet independent, so we can use the cache +*/ +if (dst_cache && !skb->mark && (!tos || info)) { + use_cache = true; + rt =dst_cache_get_ip4 (dst_cache, saddr); +if (rt) +return rt; + } +memset (&fl4,0 ,sizeof (fl4)); fl4.flowi4_oif = oif; fl4.flowi4_tos =RT_TOS (tos);
@@ -1770,8 +1793,11 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, fl4.saddr = vxlan->cfg.saddr.sin.sin_addr.s_addr; rt =ip_route_output_key (vxlan->net, &fl4); -if (!IS_ERR (rt)) +if (!IS_ERR (rt)) { *saddr = fl4.saddr; +if (use_cache) +dst_cache_set_ip4 (dst_cache, &rt->dst, fl4.saddr); + }return rt; }
@@ -1779,12 +1805,21 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,static struct dst_entry *vxlan6_get_route (struct vxlan_dev *vxlan,struct sk_buff *skb,int oif,const struct in6_addr *daddr, -struct in6_addr *saddr) +struct in6_addr *saddr, +struct dst_cache *dst_cache) { +bool use_cache = false;struct dst_entry *ndst;struct flowi6 fl6;int err; +if (dst_cache && !skb->mark) { + use_cache = true; + ndst =dst_cache_get_ip6 (dst_cache, saddr); +if (ndst) +return ndst; + } +memset (&fl6,0 ,sizeof (fl6)); fl6.flowi6_oif = oif; fl6.daddr = *daddr;
@@ -1799,6 +1834,8 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,return ERR_PTR (err); *saddr = fl6.saddr; +if (use_cache) +dst_cache_set_ip6 (dst_cache, ndst, saddr); return ndst; }#endif
@@ -1940,7 +1977,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, rt =vxlan_get_route (vxlan, skb, 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);if (IS_ERR (rt)) {netdev_dbg (dev,"no route to %pI4\n" , &dst->sin.sin_addr.s_addr);
@@ -1992,7 +2030,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ndst =vxlan6_get_route (vxlan, skb, rdst ? rdst->remote_ifindex :0 , - &dst->sin6.sin6_addr, &saddr); + &dst->sin6.sin6_addr, &saddr, + rdst ? &rdst->dst_cache :NULL );if (IS_ERR (ndst)) {netdev_dbg (dev,"no route to %pI6\n" , &dst->sin6.sin6_addr);
@@ -2333,7 +2372,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)return -EINVAL ; rt =vxlan_get_route (vxlan, skb,0 , info->key.tos, info->key.u.ipv4.dst, - &info->key.u.ipv4.src); + &info->key.u.ipv4.src,NULL , info);if (IS_ERR (rt))return PTR_ERR (rt);ip_rt_put (rt);
@@ -2345,7 +2384,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)return -EINVAL ; ndst =vxlan6_get_route (vxlan, skb,0 , &info->key.u.ipv6.dst, - &info->key.u.ipv6.src); + &info->key.u.ipv6.src,NULL );if (IS_ERR (ndst))return PTR_ERR (ndst);dst_release (ndst);
include/net/vxlan.h +1 -0
@@ -148,6 +148,7 @@ struct vxlan_rdst {u32 remote_ifindex;struct list_head list;struct rcu_head rcu; +struct dst_cache dst_cache; };struct vxlan_config {
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 5/7 net: add dst_cache to ovs vxlan lwtunnel
In reply to Paolo AbeniIn 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
---
v2: move the dst_cache inside the dst_metadata, so that it's properly refcounted upon usage; remove unneeded dst_cache check on lookup
--- drivers/net/vxlan.c | 15 ++++++++------- include/net/dst_metadata.h | 1 + include/net/ip_tunnels.h | 3 +++ net/core/dst.c | 10 +++++++++- net/openvswitch/Kconfig | 1 + net/openvswitch/flow_netlink.c | 6 ++++++ 6 files changed, 28 insertions(+), 8 deletions(-)
drivers/net/vxlan.c +8 -7
@@ -1777,7 +1777,7 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,/* when the ip_tunnel_info is availble, the tos used for lookup is * packet independent, so we can use the cache */ -if (dst_cache && !skb->mark && (!tos || info)) { +if (!skb->mark && (!tos || info)) { use_cache = true; rt =dst_cache_get_ip4 (dst_cache, saddr);if (rt)
@@ -1808,13 +1808,11 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,struct in6_addr *saddr, struct dst_cache *dst_cache) { - bool use_cache = false; struct dst_entry *ndst;struct flowi6 fl6;int err; -if (dst_cache && !skb->mark) { - use_cache = true; +if (!skb->mark) { ndst =dst_cache_get_ip6 (dst_cache, saddr);if (ndst)return ndst;
@@ -1834,7 +1832,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,return ERR_PTR (err); *saddr = fl6.saddr; -if (use_cache) +if (!skb->mark)dst_cache_set_ip6 (dst_cache, ndst, saddr);return ndst; }
@@ -1888,6 +1886,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,struct vxlan_rdst *rdst,bool did_rsc) { +struct dst_cache *dst_cache;struct ip_tunnel_info *info;struct vxlan_dev *vxlan =netdev_priv (dev);struct sock *sk;
@@ -1912,6 +1911,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; vni = rdst->remote_vni; dst = &rdst->remote_ip; + dst_cache = &rdst->dst_cache; }else {if (!info) { WARN_ONCE(1, "%s: Missing encapsulation instructions\n",
@@ -1926,6 +1926,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,else remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst; dst = &remote_ip; + dst_cache = &info->dst_cache; }if (vxlan_addr_any (dst)) {
@@ -1978,7 +1979,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, rt =vxlan_get_route (vxlan, skb, rdst ? rdst->remote_ifindex :0 , tos, dst->sin.sin_addr.s_addr, &saddr, - rdst ? &rdst->dst_cache :NULL , info); + dst_cache, info);if (IS_ERR (rt)) {netdev_dbg (dev,"no route to %pI4\n" , &dst->sin.sin_addr.s_addr);
@@ -2031,7 +2032,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ndst =vxlan6_get_route (vxlan, skb, rdst ? rdst->remote_ifindex :0 , &dst->sin6.sin6_addr, &saddr, - rdst ? &rdst->dst_cache :NULL ); + dst_cache);if (IS_ERR (ndst)) {netdev_dbg (dev,"no route to %pI6\n" , &dst->sin6.sin6_addr);
include/net/dst_metadata.h +1 -0
@@ -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); } +void metadata_dst_free (struct metadata_dst *);struct metadata_dst *metadata_dst_alloc (u8 optslen,gfp_t flags);struct metadata_dst __percpu *metadata_dst_alloc_percpu (u8 optslen,gfp_t flags);
include/net/ip_tunnels.h +3 -0
@@ -58,6 +58,9 @@ struct ip_tunnel_key {struct ip_tunnel_info {struct ip_tunnel_key key; +#ifdef CONFIG_DST_CACHE +struct dst_cache dst_cache; +#endif u8 options_len;u8 mode; };
net/core/dst.c +9 -1
@@ -265,7 +265,7 @@ again:lwtstate_put (dst->lwtstate);if (dst->flags &DST_METADATA ) -kfree (dst); +metadata_dst_free ((struct metadata_dst *)dst);else 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); +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) {int cpu;
net/openvswitch/Kconfig +1 -0
@@ -10,6 +10,7 @@ config OPENVSWITCH select LIBCRC32C select MPLS select NET_MPLS_GSO + select DST_CACHE ---help--- Open vSwitch is a multilayer Ethernet switch targeted at virtualized environments. In addition to supporting a variety of features
net/openvswitch/flow_netlink.c +6 -0
@@ -1959,6 +1959,12 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,if (!tun_dst)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 ,sizeof (*ovs_tun), log);if (IS_ERR (a)) {
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 6/7 geneve: add dst caching support
In reply to Paolo Abeniuse 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.
---
v2: remove unneeded check for null dst_cache and reorganize the
variables declaration to comply with the preferred style
--- drivers/net/geneve.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
drivers/net/geneve.c +39 -0
@@ -72,6 +72,7 @@ struct geneve_dev {bool collect_md;struct gro_cells gro_cells;u32 flags; +struct dst_cache dst_cache; };/* Geneve device flags */
@@ -297,6 +298,13 @@ static int geneve_init(struct net_device *dev)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 ; }
@@ -304,6 +312,7 @@ static void geneve_uninit(struct net_device *dev) {struct geneve_dev *geneve =netdev_priv (dev); +dst_cache_destroy (&geneve->dst_cache);gro_cells_destroy (&geneve->gro_cells);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 geneve_dev *geneve =netdev_priv (dev); +struct dst_cache *dst_cache;struct rtable *rt =NULL ; +bool use_cache = true;__u8 tos;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->saddr = info->key.u.ipv4.src; fl4->flowi4_tos =RT_TOS (info->key.tos); + dst_cache = &info->dst_cache; }else { tos = geneve->tos;if (tos ==1 ) {const struct iphdr *iip =ip_hdr (skb); tos =ip_tunnel_get_dsfield (iip, skb); + use_cache = false; } fl4->flowi4_tos =RT_TOS (tos); 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);
@@ -786,6 +807,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,ip_rt_put (rt);return ERR_PTR (-ELOOP ); } +if (use_cache) +dst_cache_set_ip4 (dst_cache, &rt->dst, fl4->saddr);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_sock *gs6 = geneve->sock6;struct dst_entry *dst =NULL ; +struct dst_cache *dst_cache; +bool use_cache = true;__u8 prio;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->saddr = info->key.u.ipv6.src; fl6->flowi6_tos =RT_TOS (info->key.tos); + dst_cache = &info->dst_cache; }else { prio = geneve->tos;if (prio ==1 ) {const struct iphdr *iip =ip_hdr (skb); prio =ip_tunnel_get_dsfield (iip, skb); + use_cache = false; } fl6->flowi6_tos =RT_TOS (prio); 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)) {
@@ -830,6 +865,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, return ERR_PTR(-ELOOP); } +if (use_cache) +dst_cache_set_ip6 (dst_cache, dst, &fl6->saddr);return dst; }#endif
@@ -1272,6 +1309,8 @@ static int geneve_configure(struct net *net, struct net_device *dev,return -EPERM ; } +dst_cache_reset (&geneve->dst_cache); + err =register_netdevice (dev);if (err)return err;
Signature · 1 line
1.8.3.1
Paolo Abeni
maintainerPATCH v2 7/7 net/ipv4: add dst cache support for gre lwtunnels
In reply to Paolo AbeniIn case of UDP traffic with datagram length below MTU this gives about 4% performance increase
---
v2: codying style cleanup
--- net/ipv4/ip_gre.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
net/ipv4/ip_gre.c +10 -3
@@ -531,9 +531,16 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) goto err_free_skb; key = &tun_info->key; - rt =gre_get_rt (skb, dev, &fl, key); -if (IS_ERR (rt)) - goto err_free_skb; + rt = !skb->mark ?dst_cache_get_ip4 (&tun_info->dst_cache, &fl.saddr) : +NULL ; +if (!rt) { + rt =gre_get_rt (skb, dev, &fl, key); +if (IS_ERR (rt)) + goto err_free_skb; +if (!skb->mark) +dst_cache_set_ip4 (&tun_info->dst_cache, &rt->dst, + fl.saddr); + } tunnel_hlen =ip_gre_calc_hlen (key->tun_flags);
Signature · 1 line
1.8.3.1
David Miller
maintainerFrom: Paolo Abeni <[email protected]>
Date: Fri, 12 Feb 2016 15:43:52 +0100
Quoted 14 lines
This patch series try to unify the dst cache implementations currently present in the kernel, namely in
ip_tunnel.candip6_tunnel.c, introducing a new generic implementation, replacing the existing ones, and then using the new implementation in other tunnel devices which currently lack it.The new dst implementation is compiled, as built-in, only if any device using it is enabled.
Caching the dst for the tunnel remote address gives small, but measurable, performance improvement when tunneling over ipv4 (in the 2%-4% range) and significant ones when tunneling over ipv6 (roughly 60% when no fragmentation/segmentation take place and the tunnel local address is not specified).
Quoted 5 lines
v2:
- move the vxlandst_cacheusage inside the device lookup functions
- fix usage after free for lwt tunnel moving the dst cache storage inside thedst_metadata,
- sparse codying style cleanup
Series applied, thanks for doing this work as it is a major improvement.
Quoted 17 lines · David Miller
From: Paolo Abeni <[email protected]>
Date: Fri, 12 Feb 2016 15:43:52 +0100Quoted 14 lines
This patch series try to unify the dst cache implementations currently present in the kernel, namely in
ip_tunnel.candip6_tunnel.c, introducing a new generic implementation, replacing the existing ones, and then using the new implementation in other tunnel devices which currently lack it.The new dst implementation is compiled, as built-in, only if any device using it is enabled.
Caching the dst for the tunnel remote address gives small, but measurable, performance improvement when tunneling over ipv4 (in the 2%-4% range) and significant ones when tunneling over ipv6 (roughly 60% when no fragmentation/segmentation take place and the tunnel local address is not specified).
Quoted 7 lines
Quoted 5 lines
v2:
- move the vxlandst_cacheusage inside the device lookup functions
- fix usage after free for lwt tunnel moving the dst cache storage inside thedst_metadata,
- sparse codying style cleanupSeries applied, thanks for doing this work as it is a major improvement.
Paolo, please check following warning :
This might be caused by e09acddf873bf775b208b452a4c3a3fd26fa9427 ("ip_tunnel: replace dst_cache with generic implementation")
[ 73.982267] BUG: using smp_processor_id() in preemptible [00000000] code: ip/10604 [ 73.990978] caller is debug_smp_processor_id+0x17/0x20 [ 73.990981] CPU: 26 PID: 10604 Comm: ip Not tainted 4.6.0-dbx-DEV #1075 [ 73.990982] Hardware name: ... [ 73.990983] 0000000000000000 ffff881fc11d3b98 ffffffff8140a51f 000000000000001a [ 73.990987] ffffffff81a585c5 ffff881fc11d3bc8 ffffffff8142700f 000060bfa000e0c0 [ 73.990989] ffff881fcb6b0f00 000000009807f60a ffff881fcb6b0f00 ffff881fc11d3bd8 [ 73.990992] Call Trace: [ 73.990996] [<ffffffff8140a51f>] dump_stack+0x67/0x98 [ 73.990998] [<ffffffff8142700f>] check_preemption_disabled+0xef/0x100 [ 73.991000] [<ffffffff81427057>] debug_smp_processor_id+0x17/0x20 [ 73.991003] [<ffffffff816bc2cc>] dst_cache_set_ip4+0x2c/0x70 [ 73.991006] [<ffffffff8174fed1>] ip_tunnel_bind_dev+0x101/0x170 [ 73.991008] [<ffffffff81750750>] ip_tunnel_ioctl+0x330/0x430 [ 73.991010] [<ffffffff81750425>] ? ip_tunnel_ioctl+0x5/0x430 [ 73.991012] [<ffffffff81754b2b>] ipgre_tunnel_ioctl+0xdb/0x160 [ 73.991015] [<ffffffff816a66f7>] ? rtnl_lock+0x17/0x20 [ 73.991017] [<ffffffff816b03e5>] dev_ifsioc+0x325/0x370 [ 73.991018] [<ffffffff816b0662>] dev_ioctl+0xd2/0x630 [ 73.991022] [<ffffffff8166fc23>] sock_ioctl+0xd3/0x270 [ 73.991025] [<ffffffff81283643>] do_vfs_ioctl+0x93/0x6f0 [ 73.991026] [<ffffffff8166ff01>] ? sock_alloc_file+0x91/0x120 [ 73.991029] [<ffffffff8128fa3c>] ? __fget_light+0x6c/0x90 [ 73.991031] [<ffffffff81283d2b>] SyS_ioctl+0x8b/0xa0 [ 73.991042] [<ffffffff817ef2a5>] entry_SYSCALL_64_fastpath+0x18/0xa8
Thanks
Paolo Abeni
maintainerQuoted 49 lines · Eric Dumazet
Quoted 17 lines · David Miller
From: Paolo Abeni <[email protected]>
Date: Fri, 12 Feb 2016 15:43:52 +0100Quoted 14 lines
This patch series try to unify the dst cache implementations currently present in the kernel, namely in
ip_tunnel.candip6_tunnel.c, introducing a new generic implementation, replacing the existing ones, and then using the new implementation in other tunnel devices which currently lack it.The new dst implementation is compiled, as built-in, only if any device using it is enabled.
Caching the dst for the tunnel remote address gives small, but measurable, performance improvement when tunneling over ipv4 (in the 2%-4% range) and significant ones when tunneling over ipv6 (roughly 60% when no fragmentation/segmentation take place and the tunnel local address is not specified).
Quoted 7 lines
Quoted 5 lines
v2:
- move the vxlandst_cacheusage inside the device lookup functions
- fix usage after free for lwt tunnel moving the dst cache storage inside thedst_metadata,
- sparse codying style cleanupSeries applied, thanks for doing this work as it is a major improvement.
Paolo, please check following warning :
This might be caused by
e09acddf873bf775b208b452a4c3a3fd26fa9427("ip_tunnel: replacedst_cachewith generic implementation")[ 73.982267] BUG: using smp_processor_id() in preemptible [00000000] code: ip/10604 [ 73.990978] caller is debug_smp_processor_id+0x17/0x20 [ 73.990981] CPU: 26 PID: 10604 Comm: ip Not tainted 4.6.0-dbx-DEV #1075 [ 73.990982] Hardware name: ... [ 73.990983] 0000000000000000 ffff881fc11d3b98 ffffffff8140a51f 000000000000001a [ 73.990987] ffffffff81a585c5 ffff881fc11d3bc8 ffffffff8142700f 000060bfa000e0c0 [ 73.990989] ffff881fcb6b0f00 000000009807f60a ffff881fcb6b0f00 ffff881fc11d3bd8 [ 73.990992] Call Trace: [ 73.990996] [<ffffffff8140a51f>] dump_stack+0x67/0x98 [ 73.990998] [<ffffffff8142700f>] check_preemption_disabled+0xef/0x100 [ 73.991000] [<ffffffff81427057>] debug_smp_processor_id+0x17/0x20 [ 73.991003] [<ffffffff816bc2cc>] dst_cache_set_ip4+0x2c/0x70 [ 73.991006] [<ffffffff8174fed1>] ip_tunnel_bind_dev+0x101/0x170 [ 73.991008] [<ffffffff81750750>] ip_tunnel_ioctl+0x330/0x430 [ 73.991010] [<ffffffff81750425>] ? ip_tunnel_ioctl+0x5/0x430 [ 73.991012] [<ffffffff81754b2b>] ipgre_tunnel_ioctl+0xdb/0x160 [ 73.991015] [<ffffffff816a66f7>] ? rtnl_lock+0x17/0x20
Quoted 8 lines
[ 73.991017] [<ffffffff816b03e5>] dev_ifsioc+0x325/0x370 [ 73.991018] [<ffffffff816b0662>] dev_ioctl+0xd2/0x630 [ 73.991022] [<ffffffff8166fc23>] sock_ioctl+0xd3/0x270 [ 73.991025] [<ffffffff81283643>] do_vfs_ioctl+0x93/0x6f0 [ 73.991026] [<ffffffff8166ff01>] ? sock_alloc_file+0x91/0x120 [ 73.991029] [<ffffffff8128fa3c>] ? __fget_light+0x6c/0x90 [ 73.991031] [<ffffffff81283d2b>] SyS_ioctl+0x8b/0xa0 [ 73.991042] [<ffffffff817ef2a5>] entry_SYSCALL_64_fastpath+0x18/0xa8
I'm on it right now.
Thank you for the head up.
Paolo