Skip to content

Commit b9b0c99

Browse files
lxingregkh
authored andcommitted
ipip: only increase err_count for some certain type icmp in ipip_err
[ Upstream commit f3594f0a7ea36661d7fd942facd7f31a64245f1a ] 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 fd58156 ("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: fd58156 ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 9bae2ff commit b9b0c99

1 file changed

Lines changed: 42 additions & 16 deletions

File tree

net/ipv4/ipip.c

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,42 +129,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly;
129129
static int ipip_err(struct sk_buff *skb, u32 info)
130130
{
131131

132-
/* All the routers (except for Linux) return only
133-
8 bytes of packet payload. It means, that precise relaying of
134-
ICMP in the real Internet is absolutely infeasible.
135-
*/
132+
/* All the routers (except for Linux) return only
133+
8 bytes of packet payload. It means, that precise relaying of
134+
ICMP in the real Internet is absolutely infeasible.
135+
*/
136136
struct net *net = dev_net(skb->dev);
137137
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
138138
const struct iphdr *iph = (const struct iphdr *)skb->data;
139-
struct ip_tunnel *t;
140-
int err;
141139
const int type = icmp_hdr(skb)->type;
142140
const int code = icmp_hdr(skb)->code;
141+
struct ip_tunnel *t;
142+
int err = 0;
143+
144+
switch (type) {
145+
case ICMP_DEST_UNREACH:
146+
switch (code) {
147+
case ICMP_SR_FAILED:
148+
/* Impossible event. */
149+
goto out;
150+
default:
151+
/* All others are translated to HOST_UNREACH.
152+
* rfc2003 contains "deep thoughts" about NET_UNREACH,
153+
* I believe they are just ether pollution. --ANK
154+
*/
155+
break;
156+
}
157+
break;
158+
159+
case ICMP_TIME_EXCEEDED:
160+
if (code != ICMP_EXC_TTL)
161+
goto out;
162+
break;
163+
164+
case ICMP_REDIRECT:
165+
break;
166+
167+
default:
168+
goto out;
169+
}
143170

144-
err = -ENOENT;
145171
t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
146172
iph->daddr, iph->saddr, 0);
147-
if (!t)
173+
if (!t) {
174+
err = -ENOENT;
148175
goto out;
176+
}
149177

150178
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
151-
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
152-
t->parms.link, 0, IPPROTO_IPIP, 0);
153-
err = 0;
179+
ipv4_update_pmtu(skb, net, info, t->parms.link, 0,
180+
iph->protocol, 0);
154181
goto out;
155182
}
156183

157184
if (type == ICMP_REDIRECT) {
158-
ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
159-
IPPROTO_IPIP, 0);
160-
err = 0;
185+
ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0);
161186
goto out;
162187
}
163188

164-
if (t->parms.iph.daddr == 0)
189+
if (t->parms.iph.daddr == 0) {
190+
err = -ENOENT;
165191
goto out;
192+
}
166193

167-
err = 0;
168194
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
169195
goto out;
170196

0 commit comments

Comments
 (0)