diff options
author | Alexander Duyck <aduyck@mirantis.com> | 2016-04-14 15:33:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-16 19:09:13 -0400 |
commit | aed069df099cd1a27900acb56bb892ec24c66ac4 (patch) | |
tree | 8d25251d281421e71d2a30b9c72716885217c5e3 /drivers/net/geneve.c | |
parent | ec9dcd3507f055f025a7692a1ff90ce105f84c1b (diff) | |
download | linux-aed069df099cd1a27900acb56bb892ec24c66ac4.tar.bz2 |
ip_tunnel_core: iptunnel_handle_offloads returns int and doesn't free skb
This patch updates the IP tunnel core function iptunnel_handle_offloads so
that we return an int and do not free the skb inside the function. This
actually allows us to clean up several paths in several tunnels so that we
can free the skb at one point in the path without having to have a
secondary path if we are supporting tunnel offloads.
In addition it should resolve some double-free issues I have found in the
tunnels paths as I believe it is possible for us to end up triggering such
an event in the case of fou or gue.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/geneve.c')
-rw-r--r-- | drivers/net/geneve.c | 32 |
1 files changed, 12 insertions, 20 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index a9fbf17eb256..efbc7ceedc3a 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -696,16 +696,12 @@ static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb, min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr); err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) { - kfree_skb(skb); + if (unlikely(err)) goto free_rt; - } - skb = udp_tunnel_handle_offloads(skb, udp_sum); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); + err = udp_tunnel_handle_offloads(skb, udp_sum); + if (err) goto free_rt; - } gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); geneve_build_header(gnvh, tun_flags, vni, opt_len, opt); @@ -733,16 +729,12 @@ static int geneve6_build_skb(struct dst_entry *dst, struct sk_buff *skb, min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len + GENEVE_BASE_HLEN + opt_len + sizeof(struct ipv6hdr); err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) { - kfree_skb(skb); + if (unlikely(err)) goto free_dst; - } - skb = udp_tunnel_handle_offloads(skb, udp_sum); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); + err = udp_tunnel_handle_offloads(skb, udp_sum); + if (IS_ERR(skb)) goto free_dst; - } gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); geneve_build_header(gnvh, tun_flags, vni, opt_len, opt); @@ -937,7 +929,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, err = geneve_build_skb(rt, skb, key->tun_flags, vni, info->options_len, opts, flags, xnet); if (unlikely(err)) - goto err; + goto tx_error; tos = ip_tunnel_ecn_encap(key->tos, iip, skb); ttl = key->ttl; @@ -946,7 +938,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, err = geneve_build_skb(rt, skb, 0, geneve->vni, 0, NULL, flags, xnet); if (unlikely(err)) - goto err; + goto tx_error; tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb); ttl = geneve->ttl; @@ -964,7 +956,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, tx_error: dev_kfree_skb(skb); -err: + if (err == -ELOOP) dev->stats.collisions++; else if (err == -ENETUNREACH) @@ -1026,7 +1018,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, info->options_len, opts, flags, xnet); if (unlikely(err)) - goto err; + goto tx_error; prio = ip_tunnel_ecn_encap(key->tos, iip, skb); ttl = key->ttl; @@ -1035,7 +1027,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, err = geneve6_build_skb(dst, skb, 0, geneve->vni, 0, NULL, flags, xnet); if (unlikely(err)) - goto err; + goto tx_error; prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel), iip, skb); @@ -1054,7 +1046,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, tx_error: dev_kfree_skb(skb); -err: + if (err == -ELOOP) dev->stats.collisions++; else if (err == -ENETUNREACH) |