aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/udp.h2
-rw-r--r--include/net/sock.h6
-rw-r--r--net/ipv4/udp.c25
-rw-r--r--net/ipv6/udp.c27
4 files changed, 51 insertions, 9 deletions
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 832361e3e596..5b4b5274e683 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -55,6 +55,8 @@ static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask)
55struct udp_sock { 55struct udp_sock {
56 /* inet_sock has to be the first member */ 56 /* inet_sock has to be the first member */
57 struct inet_sock inet; 57 struct inet_sock inet;
58#define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0]
59#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1]
58 int pending; /* Any pending frames ? */ 60 int pending; /* Any pending frames ? */
59 unsigned int corkflag; /* Cork is required */ 61 unsigned int corkflag; /* Cork is required */
60 __u16 encap_type; /* Is this an Encapsulation socket? */ 62 __u16 encap_type; /* Is this an Encapsulation socket? */
diff --git a/include/net/sock.h b/include/net/sock.h
index 55de3bd719a5..827366b62680 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -109,6 +109,7 @@ struct net;
109 * @skc_refcnt: reference count 109 * @skc_refcnt: reference count
110 * @skc_tx_queue_mapping: tx queue number for this connection 110 * @skc_tx_queue_mapping: tx queue number for this connection
111 * @skc_hash: hash value used with various protocol lookup tables 111 * @skc_hash: hash value used with various protocol lookup tables
112 * @skc_u16hashes: two u16 hash values used by UDP lookup tables
112 * @skc_family: network address family 113 * @skc_family: network address family
113 * @skc_state: Connection state 114 * @skc_state: Connection state
114 * @skc_reuse: %SO_REUSEADDR setting 115 * @skc_reuse: %SO_REUSEADDR setting
@@ -131,7 +132,10 @@ struct sock_common {
131 atomic_t skc_refcnt; 132 atomic_t skc_refcnt;
132 int skc_tx_queue_mapping; 133 int skc_tx_queue_mapping;
133 134
134 unsigned int skc_hash; 135 union {
136 unsigned int skc_hash;
137 __u16 skc_u16hashes[2];
138 };
135 unsigned short skc_family; 139 unsigned short skc_family;
136 volatile unsigned char skc_state; 140 volatile unsigned char skc_state;
137 unsigned char skc_reuse; 141 unsigned char skc_reuse;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ffc837643a04..af72de1c8690 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -138,13 +138,14 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
138 sk_nulls_for_each(sk2, node, &hslot->head) 138 sk_nulls_for_each(sk2, node, &hslot->head)
139 if (net_eq(sock_net(sk2), net) && 139 if (net_eq(sock_net(sk2), net) &&
140 sk2 != sk && 140 sk2 != sk &&
141 (bitmap || sk2->sk_hash == num) && 141 (bitmap || udp_sk(sk2)->udp_port_hash == num) &&
142 (!sk2->sk_reuse || !sk->sk_reuse) && 142 (!sk2->sk_reuse || !sk->sk_reuse) &&
143 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if 143 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
144 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && 144 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
145 (*saddr_comp)(sk, sk2)) { 145 (*saddr_comp)(sk, sk2)) {
146 if (bitmap) 146 if (bitmap)
147 __set_bit(sk2->sk_hash >> log, bitmap); 147 __set_bit(udp_sk(sk2)->udp_port_hash >> log,
148 bitmap);
148 else 149 else
149 return 1; 150 return 1;
150 } 151 }
@@ -215,7 +216,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
215 } 216 }
216found: 217found:
217 inet_sk(sk)->inet_num = snum; 218 inet_sk(sk)->inet_num = snum;
218 sk->sk_hash = snum; 219 udp_sk(sk)->udp_port_hash = snum;
220 udp_sk(sk)->udp_portaddr_hash ^= snum;
219 if (sk_unhashed(sk)) { 221 if (sk_unhashed(sk)) {
220 sk_nulls_add_node_rcu(sk, &hslot->head); 222 sk_nulls_add_node_rcu(sk, &hslot->head);
221 hslot->count++; 223 hslot->count++;
@@ -238,8 +240,19 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
238 inet1->inet_rcv_saddr == inet2->inet_rcv_saddr)); 240 inet1->inet_rcv_saddr == inet2->inet_rcv_saddr));
239} 241}
240 242
243static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr,
244 unsigned int port)
245{
246 return jhash_1word(saddr, net_hash_mix(net)) ^ port;
247}
248
241int udp_v4_get_port(struct sock *sk, unsigned short snum) 249int udp_v4_get_port(struct sock *sk, unsigned short snum)
242{ 250{
251 /* precompute partial secondary hash */
252 udp_sk(sk)->udp_portaddr_hash =
253 udp4_portaddr_hash(sock_net(sk),
254 inet_sk(sk)->inet_rcv_saddr,
255 0);
243 return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); 256 return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal);
244} 257}
245 258
@@ -249,7 +262,7 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
249{ 262{
250 int score = -1; 263 int score = -1;
251 264
252 if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && 265 if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
253 !ipv6_only_sock(sk)) { 266 !ipv6_only_sock(sk)) {
254 struct inet_sock *inet = inet_sk(sk); 267 struct inet_sock *inet = inet_sk(sk);
255 268
@@ -360,7 +373,7 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk,
360 struct inet_sock *inet = inet_sk(s); 373 struct inet_sock *inet = inet_sk(s);
361 374
362 if (!net_eq(sock_net(s), net) || 375 if (!net_eq(sock_net(s), net) ||
363 s->sk_hash != hnum || 376 udp_sk(s)->udp_port_hash != hnum ||
364 (inet->inet_daddr && inet->inet_daddr != rmt_addr) || 377 (inet->inet_daddr && inet->inet_daddr != rmt_addr) ||
365 (inet->inet_dport != rmt_port && inet->inet_dport) || 378 (inet->inet_dport != rmt_port && inet->inet_dport) ||
366 (inet->inet_rcv_saddr && 379 (inet->inet_rcv_saddr &&
@@ -1050,7 +1063,7 @@ void udp_lib_unhash(struct sock *sk)
1050 if (sk_hashed(sk)) { 1063 if (sk_hashed(sk)) {
1051 struct udp_table *udptable = sk->sk_prot->h.udp_table; 1064 struct udp_table *udptable = sk->sk_prot->h.udp_table;
1052 struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk), 1065 struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk),
1053 sk->sk_hash); 1066 udp_sk(sk)->udp_port_hash);
1054 1067
1055 spin_lock_bh(&hslot->lock); 1068 spin_lock_bh(&hslot->lock);
1056 if (sk_nulls_del_node_init_rcu(sk)) { 1069 if (sk_nulls_del_node_init_rcu(sk)) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 5bc7cdbf030a..1e5fadd997b7 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -81,8 +81,30 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
81 return 0; 81 return 0;
82} 82}
83 83
84static unsigned int udp6_portaddr_hash(struct net *net,
85 const struct in6_addr *addr6,
86 unsigned int port)
87{
88 unsigned int hash, mix = net_hash_mix(net);
89
90 if (ipv6_addr_any(addr6))
91 hash = jhash_1word(0, mix);
92 else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED)
93 hash = jhash_1word(addr6->s6_addr32[3], mix);
94 else
95 hash = jhash2(addr6->s6_addr32, 4, mix);
96
97 return hash ^ port;
98}
99
100
84int udp_v6_get_port(struct sock *sk, unsigned short snum) 101int udp_v6_get_port(struct sock *sk, unsigned short snum)
85{ 102{
103 /* precompute partial secondary hash */
104 udp_sk(sk)->udp_portaddr_hash =
105 udp6_portaddr_hash(sock_net(sk),
106 &inet6_sk(sk)->rcv_saddr,
107 0);
86 return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); 108 return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal);
87} 109}
88 110
@@ -94,7 +116,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
94{ 116{
95 int score = -1; 117 int score = -1;
96 118
97 if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && 119 if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
98 sk->sk_family == PF_INET6) { 120 sk->sk_family == PF_INET6) {
99 struct ipv6_pinfo *np = inet6_sk(sk); 121 struct ipv6_pinfo *np = inet6_sk(sk);
100 struct inet_sock *inet = inet_sk(sk); 122 struct inet_sock *inet = inet_sk(sk);
@@ -415,7 +437,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
415 if (!net_eq(sock_net(s), net)) 437 if (!net_eq(sock_net(s), net))
416 continue; 438 continue;
417 439
418 if (s->sk_hash == num && s->sk_family == PF_INET6) { 440 if (udp_sk(s)->udp_port_hash == num &&
441 s->sk_family == PF_INET6) {
419 struct ipv6_pinfo *np = inet6_sk(s); 442 struct ipv6_pinfo *np = inet6_sk(s);
420 if (inet->inet_dport) { 443 if (inet->inet_dport) {
421 if (inet->inet_dport != rmt_port) 444 if (inet->inet_dport != rmt_port)