History

bpf, vxlan, geneve, gre: fix usage of dst_cache on xmit

The assumptions from commit 0c1d70af924b ("net: use dst_cache for vxlan device"), 468dfffcd762 ("geneve: add dst caching support") and 3c1cb4d2604c ("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.

Daniel Borkmann committed 10 years ago

Commit db3c6131 parent 14ca0755 files · +36 −21Browse files

Unified · Split

5 files
  1. drivers/net/geneve.c +2 −4
  2. drivers/net/vxlan.c +12 −12
  3. include/net/ip_tunnels.h +15 −0
  4. net/core/filter.c +1 −1
  5. net/ipv4/ip_gre.c +6 −4
drivers/net/geneve.c+2−4
@@ -775,10 +775,10 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb, · 774 unmodified lines
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, · 19 unmodified lines
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, · 21 unmodified lines
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, · 19 unmodified lines
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+12−12
@@ -1756,17 +1756,15 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, · 1755 unmodified lines
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, · 21 unmodified lines
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, · 13 unmodified lines
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, · 191 unmodified lines
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) · 362 unmodified lines
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+15−0
@@ -140,6 +140,7 @@ struct ip_tunnel { · 139 unmodified lines
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, · 60 unmodified lines
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+1−1
@@ -1870,7 +1870,7 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5) · 1869 unmodified lines
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+6−4
@@ -527,11 +527,12 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) · 526 unmodified lines
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) · 2 unmodified lines
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 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t