aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorDmitry Popov <ixaphire@qrator.net>2014-07-28 19:07:52 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-30 18:18:58 -0400
commit95cb5745983c222867cc9ac593aebb2ad67d72c0 (patch)
treeaea09d3b5173d5365eb42cdb2dd11eee831062c6 /net/ipv4
parentdabf24d168ae7da5c3dc8c383db64b200e9ab483 (diff)
ip_tunnel(ipv4): fix tunnels with "local any remote $remote_ip"
Ipv4 tunnels created with "local any remote $ip" didn't work properly since 7d442fab0 (ipv4: Cache dst in tunnels). 99% of packets sent via those tunnels had src addr = 0.0.0.0. That was because only dst_entry was cached, although fl4.saddr has to be cached too. Every time ip_tunnel_xmit used cached dst_entry (tunnel_rtable_get returned non-NULL), fl4.saddr was initialized with tnl_params->saddr (= 0 in our case), and wasn't changed until iptunnel_xmit(). This patch adds saddr to ip_tunnel->dst_cache, fixing this issue. Reported-by: Sergey Popov <pinkbyte@gentoo.org> Signed-off-by: Dmitry Popov <ixaphire@qrator.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/ip_tunnel.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 6f9de61dce5f..45920d928341 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -69,23 +69,25 @@ static unsigned int ip_tunnel_hash(__be32 key, __be32 remote)
69} 69}
70 70
71static void __tunnel_dst_set(struct ip_tunnel_dst *idst, 71static void __tunnel_dst_set(struct ip_tunnel_dst *idst,
72 struct dst_entry *dst) 72 struct dst_entry *dst, __be32 saddr)
73{ 73{
74 struct dst_entry *old_dst; 74 struct dst_entry *old_dst;
75 75
76 dst_clone(dst); 76 dst_clone(dst);
77 old_dst = xchg((__force struct dst_entry **)&idst->dst, dst); 77 old_dst = xchg((__force struct dst_entry **)&idst->dst, dst);
78 dst_release(old_dst); 78 dst_release(old_dst);
79 idst->saddr = saddr;
79} 80}
80 81
81static void tunnel_dst_set(struct ip_tunnel *t, struct dst_entry *dst) 82static void tunnel_dst_set(struct ip_tunnel *t,
83 struct dst_entry *dst, __be32 saddr)
82{ 84{
83 __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst); 85 __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst, saddr);
84} 86}
85 87
86static void tunnel_dst_reset(struct ip_tunnel *t) 88static void tunnel_dst_reset(struct ip_tunnel *t)
87{ 89{
88 tunnel_dst_set(t, NULL); 90 tunnel_dst_set(t, NULL, 0);
89} 91}
90 92
91void ip_tunnel_dst_reset_all(struct ip_tunnel *t) 93void ip_tunnel_dst_reset_all(struct ip_tunnel *t)
@@ -93,20 +95,25 @@ void ip_tunnel_dst_reset_all(struct ip_tunnel *t)
93 int i; 95 int i;
94 96
95 for_each_possible_cpu(i) 97 for_each_possible_cpu(i)
96 __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL); 98 __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL, 0);
97} 99}
98EXPORT_SYMBOL(ip_tunnel_dst_reset_all); 100EXPORT_SYMBOL(ip_tunnel_dst_reset_all);
99 101
100static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie) 102static struct rtable *tunnel_rtable_get(struct ip_tunnel *t,
103 u32 cookie, __be32 *saddr)
101{ 104{
105 struct ip_tunnel_dst *idst;
102 struct dst_entry *dst; 106 struct dst_entry *dst;
103 107
104 rcu_read_lock(); 108 rcu_read_lock();
105 dst = rcu_dereference(this_cpu_ptr(t->dst_cache)->dst); 109 idst = this_cpu_ptr(t->dst_cache);
110 dst = rcu_dereference(idst->dst);
106 if (dst && !atomic_inc_not_zero(&dst->__refcnt)) 111 if (dst && !atomic_inc_not_zero(&dst->__refcnt))
107 dst = NULL; 112 dst = NULL;
108 if (dst) { 113 if (dst) {
109 if (dst->obsolete && dst->ops->check(dst, cookie) == NULL) { 114 if (!dst->obsolete || dst->ops->check(dst, cookie)) {
115 *saddr = idst->saddr;
116 } else {
110 tunnel_dst_reset(t); 117 tunnel_dst_reset(t);
111 dst_release(dst); 118 dst_release(dst);
112 dst = NULL; 119 dst = NULL;
@@ -367,7 +374,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
367 374
368 if (!IS_ERR(rt)) { 375 if (!IS_ERR(rt)) {
369 tdev = rt->dst.dev; 376 tdev = rt->dst.dev;
370 tunnel_dst_set(tunnel, &rt->dst); 377 tunnel_dst_set(tunnel, &rt->dst, fl4.saddr);
371 ip_rt_put(rt); 378 ip_rt_put(rt);
372 } 379 }
373 if (dev->type != ARPHRD_ETHER) 380 if (dev->type != ARPHRD_ETHER)
@@ -610,7 +617,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
610 init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, 617 init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
611 tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); 618 tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link);
612 619
613 rt = connected ? tunnel_rtable_get(tunnel, 0) : NULL; 620 rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL;
614 621
615 if (!rt) { 622 if (!rt) {
616 rt = ip_route_output_key(tunnel->net, &fl4); 623 rt = ip_route_output_key(tunnel->net, &fl4);
@@ -620,7 +627,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
620 goto tx_error; 627 goto tx_error;
621 } 628 }
622 if (connected) 629 if (connected)
623 tunnel_dst_set(tunnel, &rt->dst); 630 tunnel_dst_set(tunnel, &rt->dst, fl4.saddr);
624 } 631 }
625 632
626 if (rt->dst.dev == dev) { 633 if (rt->dst.dev == dev) {