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:
Paolo Abeni 2016-02-12 15:43:57 +01:00 коммит произвёл David S. Miller
Родитель 0c1d70af92
Коммит d71785ffc7
6 изменённых файлов: 28 добавлений и 8 удалений

Просмотреть файл

@ -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 @@ again:
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)) {