Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / net / ipv6 / ip6_output.c
index 635b8d3..6001e78 100644 (file)
@@ -56,6 +56,7 @@
 #include <net/checksum.h>
 #include <linux/mroute6.h>
 #include <net/l3mdev.h>
+#include <net/lwtunnel.h>
 
 static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
@@ -104,6 +105,13 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
                }
        }
 
+       if (lwtunnel_xmit_redirect(dst->lwtstate)) {
+               int res = lwtunnel_xmit(skb);
+
+               if (res < 0 || res == LWTUNNEL_XMIT_DONE)
+                       return res;
+       }
+
        rcu_read_lock_bh();
        nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
        neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
@@ -228,6 +236,14 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
                IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
                              IPSTATS_MIB_OUT, skb->len);
+
+               /* if egress device is enslaved to an L3 master device pass the
+                * skb to its handler for processing
+                */
+               skb = l3mdev_ip6_out((struct sock *)sk, skb);
+               if (unlikely(!skb))
+                       return 0;
+
                /* hooks should never assume socket lock is held.
                 * we promote our socket to non const
                 */
@@ -368,7 +384,7 @@ static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
        if (skb->ignore_df)
                return false;
 
-       if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
+       if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
                return false;
 
        return true;
@@ -999,10 +1015,11 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
        return 0;
 
 out_err_release:
-       if (err == -ENETUNREACH)
-               IP6_INC_STATS(net, NULL, IPSTATS_MIB_OUTNOROUTES);
        dst_release(*dst);
        *dst = NULL;
+
+       if (err == -ENETUNREACH)
+               IP6_INC_STATS(net, NULL, IPSTATS_MIB_OUTNOROUTES);
        return err;
 }
 
@@ -1046,8 +1063,6 @@ struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
                return ERR_PTR(err);
        if (final_dst)
                fl6->daddr = *final_dst;
-       if (!fl6->flowi6_oif)
-               fl6->flowi6_oif = l3mdev_fib_oif(dst->dev);
 
        return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
 }