diff options
| author | Xin Long <lucien.xin@gmail.com> | 2017-10-26 07:19:56 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-10-27 10:43:31 -0400 |
| commit | f3594f0a7ea36661d7fd942facd7f31a64245f1a (patch) | |
| tree | 4c6d3e49ce6b519ec208d1ec5cec569181552a08 | |
| parent | 6d9f0790af8d33476f936ac84a07cac42f808f6c (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.c | 59 |
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 | ||
| 129 | static int ipip_err(struct sk_buff *skb, u32 info) | 129 | static 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 | ||
