Skip to content

Commit db3c613

Browse files
borkmanndavem330
authored andcommitted
bpf, vxlan, geneve, gre: fix usage of dst_cache on xmit
The assumptions from commit 0c1d70a ("net: use dst_cache for vxlan device"), 468dfff ("geneve: add dst caching support") and 3c1cb4d ("net/ipv4: add dst cache support for gre lwtunnels") on dst_cache usage when ip_tunnel_info is used is unfortunately not always valid as assumed. While it seems correct for ip_tunnel_info front-ends such as OVS, eBPF however can fill in ip_tunnel_info for consumers like vxlan, geneve or gre with different remote dsts, tos, etc, therefore they cannot be assumed as packet independent. Right now vxlan, geneve, gre would cache the dst for eBPF and every packet would reuse the same entry that was first created on the initial route lookup. eBPF doesn't store/cache the ip_tunnel_info, so each skb may have a different one. Fix it by adding a flag that checks the ip_tunnel_info. Also the !tos test in vxlan needs to be handeled differently in this context as it is currently inferred from ip_tunnel_info as well if present. ip_tunnel_dst_cache_usable() helper is added for the three tunnel cases, which checks if we can use dst cache. Fixes: 0c1d70a ("net: use dst_cache for vxlan device") Fixes: 468dfff ("geneve: add dst caching support") Fixes: 3c1cb4d ("net/ipv4: add dst cache support for gre lwtunnels") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Paolo Abeni <pabeni@redhat.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 14ca075 commit db3c613

File tree

5 files changed

+36
-21
lines changed

5 files changed

+36
-21
lines changed

drivers/net/geneve.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -775,10 +775,10 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
775775
struct flowi4 *fl4,
776776
struct ip_tunnel_info *info)
777777
{
778+
bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
778779
struct geneve_dev *geneve = netdev_priv(dev);
779780
struct dst_cache *dst_cache;
780781
struct rtable *rt = NULL;
781-
bool use_cache = true;
782782
__u8 tos;
783783

784784
memset(fl4, 0, sizeof(*fl4));
@@ -804,7 +804,6 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
804804
dst_cache = &geneve->dst_cache;
805805
}
806806

807-
use_cache = use_cache && !skb->mark;
808807
if (use_cache) {
809808
rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
810809
if (rt)
@@ -832,11 +831,11 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
832831
struct flowi6 *fl6,
833832
struct ip_tunnel_info *info)
834833
{
834+
bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
835835
struct geneve_dev *geneve = netdev_priv(dev);
836836
struct geneve_sock *gs6 = geneve->sock6;
837837
struct dst_entry *dst = NULL;
838838
struct dst_cache *dst_cache;
839-
bool use_cache = true;
840839
__u8 prio;
841840

842841
memset(fl6, 0, sizeof(*fl6));
@@ -862,7 +861,6 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
862861
dst_cache = &geneve->dst_cache;
863862
}
864863

865-
use_cache = use_cache && !skb->mark;
866864
if (use_cache) {
867865
dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
868866
if (dst)

drivers/net/vxlan.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,17 +1756,15 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
17561756
struct sk_buff *skb, int oif, u8 tos,
17571757
__be32 daddr, __be32 *saddr,
17581758
struct dst_cache *dst_cache,
1759-
struct ip_tunnel_info *info)
1759+
const struct ip_tunnel_info *info)
17601760
{
1761+
bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
17611762
struct rtable *rt = NULL;
1762-
bool use_cache = false;
17631763
struct flowi4 fl4;
17641764

1765-
/* when the ip_tunnel_info is availble, the tos used for lookup is
1766-
* packet independent, so we can use the cache
1767-
*/
1768-
if (!skb->mark && (!tos || info)) {
1769-
use_cache = true;
1765+
if (tos && !info)
1766+
use_cache = false;
1767+
if (use_cache) {
17701768
rt = dst_cache_get_ip4(dst_cache, saddr);
17711769
if (rt)
17721770
return rt;
@@ -1794,13 +1792,15 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
17941792
struct sk_buff *skb, int oif,
17951793
const struct in6_addr *daddr,
17961794
struct in6_addr *saddr,
1797-
struct dst_cache *dst_cache)
1795+
struct dst_cache *dst_cache,
1796+
const struct ip_tunnel_info *info)
17981797
{
1798+
bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
17991799
struct dst_entry *ndst;
18001800
struct flowi6 fl6;
18011801
int err;
18021802

1803-
if (!skb->mark) {
1803+
if (use_cache) {
18041804
ndst = dst_cache_get_ip6(dst_cache, saddr);
18051805
if (ndst)
18061806
return ndst;
@@ -1820,7 +1820,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
18201820
return ERR_PTR(err);
18211821

18221822
*saddr = fl6.saddr;
1823-
if (!skb->mark)
1823+
if (use_cache)
18241824
dst_cache_set_ip6(dst_cache, ndst, saddr);
18251825
return ndst;
18261826
}
@@ -2018,7 +2018,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
20182018
ndst = vxlan6_get_route(vxlan, skb,
20192019
rdst ? rdst->remote_ifindex : 0,
20202020
&dst->sin6.sin6_addr, &saddr,
2021-
dst_cache);
2021+
dst_cache, info);
20222022
if (IS_ERR(ndst)) {
20232023
netdev_dbg(dev, "no route to %pI6\n",
20242024
&dst->sin6.sin6_addr);
@@ -2387,7 +2387,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
23872387
return -EINVAL;
23882388
ndst = vxlan6_get_route(vxlan, skb, 0,
23892389
&info->key.u.ipv6.dst,
2390-
&info->key.u.ipv6.src, NULL);
2390+
&info->key.u.ipv6.src, NULL, info);
23912391
if (IS_ERR(ndst))
23922392
return PTR_ERR(ndst);
23932393
dst_release(ndst);

include/net/ip_tunnels.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ struct ip_tunnel {
140140
#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400)
141141
#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800)
142142
#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000)
143+
#define TUNNEL_NOCACHE __cpu_to_be16(0x2000)
143144

144145
#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)
145146

@@ -206,6 +207,20 @@ static inline void ip_tunnel_key_init(struct ip_tunnel_key *key,
206207
0, sizeof(*key) - IP_TUNNEL_KEY_SIZE);
207208
}
208209

210+
static inline bool
211+
ip_tunnel_dst_cache_usable(const struct sk_buff *skb,
212+
const struct ip_tunnel_info *info)
213+
{
214+
if (skb->mark)
215+
return false;
216+
if (!info)
217+
return true;
218+
if (info->key.tun_flags & TUNNEL_NOCACHE)
219+
return false;
220+
221+
return true;
222+
}
223+
209224
static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info
210225
*tun_info)
211226
{

net/core/filter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
18701870
info = &md->u.tun_info;
18711871
info->mode = IP_TUNNEL_INFO_TX;
18721872

1873-
info->key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM;
1873+
info->key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_NOCACHE;
18741874
if (flags & BPF_F_DONT_FRAGMENT)
18751875
info->key.tun_flags |= TUNNEL_DONT_FRAGMENT;
18761876

net/ipv4/ip_gre.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,11 +527,12 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
527527
{
528528
struct ip_tunnel_info *tun_info;
529529
const struct ip_tunnel_key *key;
530+
struct rtable *rt = NULL;
530531
struct flowi4 fl;
531-
struct rtable *rt;
532532
int min_headroom;
533533
int tunnel_hlen;
534534
__be16 df, flags;
535+
bool use_cache;
535536
int err;
536537

537538
tun_info = skb_tunnel_info(skb);
@@ -540,13 +541,14 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
540541
goto err_free_skb;
541542

542543
key = &tun_info->key;
543-
rt = !skb->mark ? dst_cache_get_ip4(&tun_info->dst_cache, &fl.saddr) :
544-
NULL;
544+
use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
545+
if (use_cache)
546+
rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl.saddr);
545547
if (!rt) {
546548
rt = gre_get_rt(skb, dev, &fl, key);
547549
if (IS_ERR(rt))
548550
goto err_free_skb;
549-
if (!skb->mark)
551+
if (use_cache)
550552
dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
551553
fl.saddr);
552554
}

0 commit comments

Comments
 (0)