aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2017-10-26 07:19:56 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-27 10:43:31 -0400
commitf3594f0a7ea36661d7fd942facd7f31a64245f1a (patch)
tree4c6d3e49ce6b519ec208d1ec5cec569181552a08
parent6d9f0790af8d33476f936ac84a07cac42f808f6c (diff)
ipip: only increase err_count for some certain type icmp in ipip_err
t->err_count is used to count the link failure on tunnel and an err will be reported to user socket in tx path if t->err_count is not 0. udp socket could even return EHOSTUNREACH to users. Since commit fd58156e456d ("IPIP: Use ip-tunneling code.") removed the 'switch check' for icmp type in ipip_err(), err_count would be increased by the icmp packet with ICMP_EXC_FRAGTIME code. an link failure would be reported out due to this. In Jianlin's case, when receiving ICMP_EXC_FRAGTIME a icmp packet, udp netperf failed with the err: send_data: data send error: No route to host (errno 113) We expect this error reported from tunnel to socket when receiving some certain type icmp, but not ICMP_EXC_FRAGTIME, ICMP_SR_FAILED or ICMP_PARAMETERPROB ones. This patch is to bring 'switch check' for icmp type back to ipip_err so that it only reports link failure for the right type icmp, just as in ipgre_err() and ipip6_err(). Fixes: fd58156e456d ("IPIP: Use ip-tunneling code.") Reported-by: Jianlin Shi <jishi@redhat.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/ipip.c59
1 files changed, 42 insertions, 17 deletions
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index fb1ad22b5e29..cdd627355ed1 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -128,43 +128,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly;
128 128
129static int ipip_err(struct sk_buff *skb, u32 info) 129static int ipip_err(struct sk_buff *skb, u32 info)
130{ 130{
131 131 /* All the routers (except for Linux) return only
132/* All the routers (except for Linux) return only 132 * 8 bytes of packet payload. It means, that precise relaying of
133 8 bytes of packet payload. It means, that precise relaying of 133 * ICMP in the real Internet is absolutely infeasible.
134 ICMP in the real Internet is absolutely infeasible. 134 */
135 */
136 struct net *net = dev_net(skb->dev); 135 struct net *net = dev_net(skb->dev);
137 struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 136 struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
138 const struct iphdr *iph = (const struct iphdr *)skb->data; 137 const struct iphdr *iph = (const struct iphdr *)skb->data;
139 struct ip_tunnel *t;
140 int err;
141 const int type = icmp_hdr(skb)->type; 138 const int type = icmp_hdr(skb)->type;
142 const int code = icmp_hdr(skb)->code; 139 const int code = icmp_hdr(skb)->code;
140 struct ip_tunnel *t;
141 int err = 0;
142
143 switch (type) {
144 case ICMP_DEST_UNREACH:
145 switch (code) {
146 case ICMP_SR_FAILED:
147 /* Impossible event. */
148 goto out;
149 default:
150 /* All others are translated to HOST_UNREACH.
151 * rfc2003 contains "deep thoughts" about NET_UNREACH,
152 * I believe they are just ether pollution. --ANK
153 */
154 break;
155 }
156 break;
157
158 case ICMP_TIME_EXCEEDED:
159 if (code != ICMP_EXC_TTL)
160 goto out;
161 break;
162
163 case ICMP_REDIRECT:
164 break;
165
166 default:
167 goto out;
168 }
143 169
144 err = -ENOENT;
145 t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 170 t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
146 iph->daddr, iph->saddr, 0); 171 iph->daddr, iph->saddr, 0);
147 if (!t) 172 if (!t) {
173 err = -ENOENT;
148 goto out; 174 goto out;
175 }
149 176
150 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 177 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
151 ipv4_update_pmtu(skb, dev_net(skb->dev), info, 178 ipv4_update_pmtu(skb, net, info, t->parms.link, 0,
152 t->parms.link, 0, iph->protocol, 0); 179 iph->protocol, 0);
153 err = 0;
154 goto out; 180 goto out;
155 } 181 }
156 182
157 if (type == ICMP_REDIRECT) { 183 if (type == ICMP_REDIRECT) {
158 ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, 184 ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0);
159 iph->protocol, 0);
160 err = 0;
161 goto out; 185 goto out;
162 } 186 }
163 187
164 if (t->parms.iph.daddr == 0) 188 if (t->parms.iph.daddr == 0) {
189 err = -ENOENT;
165 goto out; 190 goto out;
191 }
166 192
167 err = 0;
168 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 193 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
169 goto out; 194 goto out;
170 195