Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / udp.c
index dfaa29b8b2939c03fef13fa416f6fdaef031bf5d..599e1ba6d1ceaa6766d53eda020a69a0aa234e5b 100644 (file)
@@ -45,6 +45,7 @@
 #include <net/tcp_states.h>
 #include <net/ip6_checksum.h>
 #include <net/xfrm.h>
+#include <net/inet6_hashtables.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net,
 {
        struct sock *sk, *result;
        struct hlist_nulls_node *node;
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
 begin:
        result = NULL;
@@ -214,8 +216,18 @@ begin:
                if (score > badness) {
                        result = sk;
                        badness = score;
-                       if (score == SCORE2_MAX)
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet6_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       } else if (score == SCORE2_MAX)
                                goto exact_match;
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
        unsigned short hnum = ntohs(dport);
        unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
        struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
        rcu_read_lock();
        if (hslot->count > 10) {
@@ -284,6 +297,17 @@ begin:
                if (score > badness) {
                        result = sk;
                        badness = score;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet6_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       }
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -443,7 +467,7 @@ try_again:
                        ip_cmsg_recv(msg, skb);
        } else {
                if (np->rxopt.all)
-                       datagram_recv_ctl(sk, msg, skb);
+                       ip6_datagram_recv_ctl(sk, msg, skb);
        }
 
        err = copied;
@@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
        return 0;
 }
 
-static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
-                                int proto)
-{
-       int err;
-
-       UDP_SKB_CB(skb)->partial_cov = 0;
-       UDP_SKB_CB(skb)->cscov = skb->len;
-
-       if (proto == IPPROTO_UDPLITE) {
-               err = udplite_checksum_init(skb, uh);
-               if (err)
-                       return err;
-       }
-
-       if (uh->check == 0) {
-               /* RFC 2460 section 8.1 says that we SHOULD log
-                  this error. Well, it is reasonable.
-                */
-               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
-               return 1;
-       }
-       if (skb->ip_summed == CHECKSUM_COMPLETE &&
-           !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
-                            skb->len, proto, skb->csum))
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       if (!skb_csum_unnecessary(skb))
-               skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                        &ipv6_hdr(skb)->daddr,
-                                                        skb->len, proto, 0));
-
-       return 0;
-}
-
 int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                   int proto)
 {
@@ -1153,8 +1143,8 @@ do_udp_sendmsg:
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(*opt);
 
-               err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                       &hlimit, &tclass, &dontfrag);
+               err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+                                           &hlimit, &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;