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 commitfd58156e45
("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:fd58156e45
("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>
This commit is contained in:
parent
6d9f0790af
commit
f3594f0a7e
|
@ -128,43 +128,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly;
|
||||||
|
|
||||||
static int ipip_err(struct sk_buff *skb, u32 info)
|
static int ipip_err(struct sk_buff *skb, u32 info)
|
||||||
{
|
{
|
||||||
|
/* All the routers (except for Linux) return only
|
||||||
/* All the routers (except for Linux) return only
|
* 8 bytes of packet payload. It means, that precise relaying of
|
||||||
8 bytes of packet payload. It means, that precise relaying of
|
* ICMP in the real Internet is absolutely infeasible.
|
||||||
ICMP in the real Internet is absolutely infeasible.
|
*/
|
||||||
*/
|
|
||||||
struct net *net = dev_net(skb->dev);
|
struct net *net = dev_net(skb->dev);
|
||||||
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
|
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
|
||||||
const struct iphdr *iph = (const struct iphdr *)skb->data;
|
const struct iphdr *iph = (const struct iphdr *)skb->data;
|
||||||
struct ip_tunnel *t;
|
|
||||||
int err;
|
|
||||||
const int type = icmp_hdr(skb)->type;
|
const int type = icmp_hdr(skb)->type;
|
||||||
const int code = icmp_hdr(skb)->code;
|
const int code = icmp_hdr(skb)->code;
|
||||||
|
struct ip_tunnel *t;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ICMP_DEST_UNREACH:
|
||||||
|
switch (code) {
|
||||||
|
case ICMP_SR_FAILED:
|
||||||
|
/* Impossible event. */
|
||||||
|
goto out;
|
||||||
|
default:
|
||||||
|
/* All others are translated to HOST_UNREACH.
|
||||||
|
* rfc2003 contains "deep thoughts" about NET_UNREACH,
|
||||||
|
* I believe they are just ether pollution. --ANK
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ICMP_TIME_EXCEEDED:
|
||||||
|
if (code != ICMP_EXC_TTL)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ICMP_REDIRECT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
err = -ENOENT;
|
|
||||||
t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
|
t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
|
||||||
iph->daddr, iph->saddr, 0);
|
iph->daddr, iph->saddr, 0);
|
||||||
if (!t)
|
if (!t) {
|
||||||
|
err = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
||||||
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
|
ipv4_update_pmtu(skb, net, info, t->parms.link, 0,
|
||||||
t->parms.link, 0, iph->protocol, 0);
|
iph->protocol, 0);
|
||||||
err = 0;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ICMP_REDIRECT) {
|
if (type == ICMP_REDIRECT) {
|
||||||
ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
|
ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0);
|
||||||
iph->protocol, 0);
|
|
||||||
err = 0;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->parms.iph.daddr == 0)
|
if (t->parms.iph.daddr == 0) {
|
||||||
|
err = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
err = 0;
|
|
||||||
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue