]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/ipv6/ip6_output.c
net: hns3: fix for rss result nonuniform
[linux.git] / net / ipv6 / ip6_output.c
index 89e0d5118afe69a94c93e1f584047240fc0d1a51..5f9fa0302b5a97af835b6f9ff10f53f1b6e1c9be 100644 (file)
@@ -195,37 +195,37 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        const struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_addr *first_hop = &fl6->daddr;
        struct dst_entry *dst = skb_dst(skb);
+       unsigned int head_room;
        struct ipv6hdr *hdr;
        u8  proto = fl6->flowi6_proto;
        int seg_len = skb->len;
        int hlimit = -1;
        u32 mtu;
 
-       if (opt) {
-               unsigned int head_room;
+       head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
+       if (opt)
+               head_room += opt->opt_nflen + opt->opt_flen;
 
-               /* First: exthdrs may take lots of space (~8K for now)
-                  MAX_HEADER is not enough.
-                */
-               head_room = opt->opt_nflen + opt->opt_flen;
-               seg_len += head_room;
-               head_room += sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
-
-               if (skb_headroom(skb) < head_room) {
-                       struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
-                       if (!skb2) {
-                               IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                                             IPSTATS_MIB_OUTDISCARDS);
-                               kfree_skb(skb);
-                               return -ENOBUFS;
-                       }
-                       if (skb->sk)
-                               skb_set_owner_w(skb2, skb->sk);
-                       consume_skb(skb);
-                       skb = skb2;
+       if (unlikely(skb_headroom(skb) < head_room)) {
+               struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
+               if (!skb2) {
+                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
+                                     IPSTATS_MIB_OUTDISCARDS);
+                       kfree_skb(skb);
+                       return -ENOBUFS;
                }
+               if (skb->sk)
+                       skb_set_owner_w(skb2, skb->sk);
+               consume_skb(skb);
+               skb = skb2;
+       }
+
+       if (opt) {
+               seg_len += opt->opt_nflen + opt->opt_flen;
+
                if (opt->opt_flen)
                        ipv6_push_frag_opts(skb, opt, &proto);
+
                if (opt->opt_nflen)
                        ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
                                             &fl6->saddr);
@@ -378,6 +378,14 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,
        __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
        __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
 
+#ifdef CONFIG_NET_SWITCHDEV
+       if (skb->offload_l3_fwd_mark) {
+               consume_skb(skb);
+               return 0;
+       }
+#endif
+
+       skb->tstamp = 0;
        return dst_output(net, sk, skb);
 }
 
@@ -574,6 +582,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
+       skb_ext_copy(to, from);
        skb_copy_secmark(to, from);
 }
 
@@ -1245,6 +1254,7 @@ static int __ip6_append_data(struct sock *sk,
 {
        struct sk_buff *skb, *skb_prev = NULL;
        unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
+       struct ubuf_info *uarg = NULL;
        int exthdrlen = 0;
        int dst_exthdrlen = 0;
        int hh_len;
@@ -1257,7 +1267,7 @@ static int __ip6_append_data(struct sock *sk,
        int csummode = CHECKSUM_NONE;
        unsigned int maxnonfragsize, headersize;
        unsigned int wmem_alloc_delta = 0;
-       bool paged;
+       bool paged, extra_uref;
 
        skb = skb_peek_tail(queue);
        if (!skb) {
@@ -1322,6 +1332,20 @@ static int __ip6_append_data(struct sock *sk,
            rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
                csummode = CHECKSUM_PARTIAL;
 
+       if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) {
+               uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
+               if (!uarg)
+                       return -ENOBUFS;
+               extra_uref = true;
+               if (rt->dst.dev->features & NETIF_F_SG &&
+                   csummode == CHECKSUM_PARTIAL) {
+                       paged = true;
+               } else {
+                       uarg->zerocopy = 0;
+                       skb_zcopy_set(skb, uarg, &extra_uref);
+               }
+       }
+
        /*
         * Let's try using as much space as possible.
         * Use MTU if total length of the message fits into the MTU.
@@ -1354,7 +1378,7 @@ static int __ip6_append_data(struct sock *sk,
                        unsigned int fraglen;
                        unsigned int fraggap;
                        unsigned int alloclen;
-                       unsigned int pagedlen = 0;
+                       unsigned int pagedlen;
 alloc_new_skb:
                        /* There's no room in the current skb */
                        if (skb)
@@ -1378,6 +1402,7 @@ static int __ip6_append_data(struct sock *sk,
                        if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
                                datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
                        fraglen = datalen + fragheaderlen;
+                       pagedlen = 0;
 
                        if ((flags & MSG_MORE) &&
                            !(rt->dst.dev->features&NETIF_F_SG))
@@ -1439,12 +1464,6 @@ static int __ip6_append_data(struct sock *sk,
                        skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +
                                    dst_exthdrlen);
 
-                       /* Only the initial fragment is time stamped */
-                       skb_shinfo(skb)->tx_flags = cork->tx_flags;
-                       cork->tx_flags = 0;
-                       skb_shinfo(skb)->tskey = tskey;
-                       tskey = 0;
-
                        /*
                         *      Find where to start putting bytes
                         */
@@ -1476,6 +1495,13 @@ static int __ip6_append_data(struct sock *sk,
                        exthdrlen = 0;
                        dst_exthdrlen = 0;
 
+                       /* Only the initial fragment is time stamped */
+                       skb_shinfo(skb)->tx_flags = cork->tx_flags;
+                       cork->tx_flags = 0;
+                       skb_shinfo(skb)->tskey = tskey;
+                       tskey = 0;
+                       skb_zcopy_set(skb, uarg, &extra_uref);
+
                        if ((flags & MSG_CONFIRM) && !skb_prev)
                                skb_set_dst_pending_confirm(skb, 1);
 
@@ -1505,7 +1531,7 @@ static int __ip6_append_data(struct sock *sk,
                                err = -EFAULT;
                                goto error;
                        }
-               } else {
+               } else if (!uarg || !uarg->zerocopy) {
                        int i = skb_shinfo(skb)->nr_frags;
 
                        err = -ENOMEM;
@@ -1535,6 +1561,10 @@ static int __ip6_append_data(struct sock *sk,
                        skb->data_len += copy;
                        skb->truesize += copy;
                        wmem_alloc_delta += copy;
+               } else {
+                       err = skb_zerocopy_iter_dgram(skb, from, copy);
+                       if (err < 0)
+                               goto error;
                }
                offset += copy;
                length -= copy;
@@ -1547,6 +1577,8 @@ static int __ip6_append_data(struct sock *sk,
 error_efault:
        err = -EFAULT;
 error:
+       if (uarg)
+               sock_zerocopy_put_abort(uarg, extra_uref);
        cork->length -= length;
        IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
        refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);