diff options
Diffstat (limited to 'net/ipv4/udp.c')
| -rw-r--r-- | net/ipv4/udp.c | 25 |
1 files changed, 19 insertions, 6 deletions
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 | } |
| 216 | found: | 217 | found: |
| 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 | ||
| 243 | static 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 | |||
| 241 | int udp_v4_get_port(struct sock *sk, unsigned short snum) | 249 | int 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)) { |
