|
@@ -491,19 +491,17 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
|
{
|
|
|
struct ip_tunnel *tunnel = netdev_priv(dev);
|
|
|
const struct iphdr *inner_iph;
|
|
|
- struct iphdr *iph;
|
|
|
struct flowi4 fl4;
|
|
|
u8 tos, ttl;
|
|
|
__be16 df;
|
|
|
struct rtable *rt; /* Route to the other host */
|
|
|
- struct net_device *tdev; /* Device to other host */
|
|
|
unsigned int max_headroom; /* The extra header space needed */
|
|
|
__be32 dst;
|
|
|
int mtu;
|
|
|
+ int err;
|
|
|
|
|
|
inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
|
|
|
|
|
|
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
|
|
|
dst = tnl_params->daddr;
|
|
|
if (dst == 0) {
|
|
|
/* NBMA tunnel */
|
|
@@ -571,14 +569,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
|
dev->stats.tx_carrier_errors++;
|
|
|
goto tx_error;
|
|
|
}
|
|
|
- tdev = rt->dst.dev;
|
|
|
-
|
|
|
- if (tdev == dev) {
|
|
|
+ if (rt->dst.dev == dev) {
|
|
|
ip_rt_put(rt);
|
|
|
dev->stats.collisions++;
|
|
|
goto tx_error;
|
|
|
}
|
|
|
-
|
|
|
df = tnl_params->frag_off;
|
|
|
|
|
|
if (df)
|
|
@@ -596,6 +591,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
|
if (!skb_is_gso(skb) &&
|
|
|
(inner_iph->frag_off&htons(IP_DF)) &&
|
|
|
mtu < ntohs(inner_iph->tot_len)) {
|
|
|
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
|
|
|
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
|
|
|
ip_rt_put(rt);
|
|
|
goto tx_error;
|
|
@@ -646,8 +642,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
|
ttl = ip4_dst_hoplimit(&rt->dst);
|
|
|
}
|
|
|
|
|
|
- max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr)
|
|
|
- + rt->dst.header_len;
|
|
|
+ max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
|
|
|
+ + rt->dst.header_len;
|
|
|
if (max_headroom > dev->needed_headroom) {
|
|
|
dev->needed_headroom = max_headroom;
|
|
|
if (skb_cow_head(skb, dev->needed_headroom)) {
|
|
@@ -657,27 +653,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- skb_dst_drop(skb);
|
|
|
- skb_dst_set(skb, &rt->dst);
|
|
|
-
|
|
|
- /* Push down and install the IP header. */
|
|
|
- skb_push(skb, sizeof(struct iphdr));
|
|
|
- skb_reset_network_header(skb);
|
|
|
-
|
|
|
- iph = ip_hdr(skb);
|
|
|
- inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
|
|
|
+ err = iptunnel_xmit(dev_net(dev), rt, skb,
|
|
|
+ fl4.saddr, fl4.daddr, protocol,
|
|
|
+ ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df);
|
|
|
+ iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
|
|
|
|
|
|
- iph->version = 4;
|
|
|
- iph->ihl = sizeof(struct iphdr) >> 2;
|
|
|
- iph->frag_off = df;
|
|
|
- iph->protocol = protocol;
|
|
|
- iph->tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
|
|
|
- iph->daddr = fl4.daddr;
|
|
|
- iph->saddr = fl4.saddr;
|
|
|
- iph->ttl = ttl;
|
|
|
- tunnel_ip_select_ident(skb, inner_iph, &rt->dst);
|
|
|
-
|
|
|
- iptunnel_xmit(skb, dev);
|
|
|
return;
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|