@@ -38,20 +38,21 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
38
38
* IPV6_ADDR_ANY only equals to IPV6_ADDR_ANY,
39
39
* and 0.0.0.0 equals to 0.0.0.0 only
40
40
*/
41
- static int ipv6_rcv_saddr_equal (const struct sock * sk , const struct sock * sk2 ,
41
+ static int ipv6_rcv_saddr_equal (const struct in6_addr * sk1_rcv_saddr6 ,
42
+ const struct in6_addr * sk2_rcv_saddr6 ,
43
+ __be32 sk1_rcv_saddr , __be32 sk2_rcv_saddr ,
44
+ bool sk1_ipv6only , bool sk2_ipv6only ,
42
45
bool match_wildcard )
43
46
{
44
- const struct in6_addr * sk2_rcv_saddr6 = inet6_rcv_saddr (sk2 );
45
- int sk2_ipv6only = inet_v6_ipv6only (sk2 );
46
- int addr_type = ipv6_addr_type (& sk -> sk_v6_rcv_saddr );
47
+ int addr_type = ipv6_addr_type (sk1_rcv_saddr6 );
47
48
int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type (sk2_rcv_saddr6 ) : IPV6_ADDR_MAPPED ;
48
49
49
50
/* if both are mapped, treat as IPv4 */
50
51
if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED ) {
51
52
if (!sk2_ipv6only ) {
52
- if (sk -> sk_rcv_saddr == sk2 -> sk_rcv_saddr )
53
+ if (sk1_rcv_saddr == sk2_rcv_saddr )
53
54
return 1 ;
54
- if (!sk -> sk_rcv_saddr || !sk2 -> sk_rcv_saddr )
55
+ if (!sk1_rcv_saddr || !sk2_rcv_saddr )
55
56
return match_wildcard ;
56
57
}
57
58
return 0 ;
@@ -65,11 +66,11 @@ static int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
65
66
return 1 ;
66
67
67
68
if (addr_type == IPV6_ADDR_ANY && match_wildcard &&
68
- !(ipv6_only_sock ( sk ) && addr_type2 == IPV6_ADDR_MAPPED ))
69
+ !(sk1_ipv6only && addr_type2 == IPV6_ADDR_MAPPED ))
69
70
return 1 ;
70
71
71
72
if (sk2_rcv_saddr6 &&
72
- ipv6_addr_equal (& sk -> sk_v6_rcv_saddr , sk2_rcv_saddr6 ))
73
+ ipv6_addr_equal (sk1_rcv_saddr6 , sk2_rcv_saddr6 ))
73
74
return 1 ;
74
75
75
76
return 0 ;
@@ -80,13 +81,13 @@ static int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
80
81
* match_wildcard == false: addresses must be exactly the same, i.e.
81
82
* 0.0.0.0 only equals to 0.0.0.0
82
83
*/
83
- static int ipv4_rcv_saddr_equal (const struct sock * sk , const struct sock * sk2 ,
84
- bool match_wildcard )
84
+ static int ipv4_rcv_saddr_equal (__be32 sk1_rcv_saddr , __be32 sk2_rcv_saddr ,
85
+ bool sk2_ipv6only , bool match_wildcard )
85
86
{
86
- if (!ipv6_only_sock ( sk2 ) ) {
87
- if (sk -> sk_rcv_saddr == sk2 -> sk_rcv_saddr )
87
+ if (!sk2_ipv6only ) {
88
+ if (sk1_rcv_saddr == sk2_rcv_saddr )
88
89
return 1 ;
89
- if (!sk -> sk_rcv_saddr || !sk2 -> sk_rcv_saddr )
90
+ if (!sk1_rcv_saddr || !sk2_rcv_saddr )
90
91
return match_wildcard ;
91
92
}
92
93
return 0 ;
@@ -97,9 +98,16 @@ int inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
97
98
{
98
99
#if IS_ENABLED (CONFIG_IPV6 )
99
100
if (sk -> sk_family == AF_INET6 )
100
- return ipv6_rcv_saddr_equal (sk , sk2 , match_wildcard );
101
+ return ipv6_rcv_saddr_equal (& sk -> sk_v6_rcv_saddr ,
102
+ & sk2 -> sk_v6_rcv_saddr ,
103
+ sk -> sk_rcv_saddr ,
104
+ sk2 -> sk_rcv_saddr ,
105
+ ipv6_only_sock (sk ),
106
+ ipv6_only_sock (sk2 ),
107
+ match_wildcard );
101
108
#endif
102
- return ipv4_rcv_saddr_equal (sk , sk2 , match_wildcard );
109
+ return ipv4_rcv_saddr_equal (sk -> sk_rcv_saddr , sk2 -> sk_rcv_saddr ,
110
+ ipv6_only_sock (sk2 ), match_wildcard );
103
111
}
104
112
EXPORT_SYMBOL (inet_rcv_saddr_equal );
105
113
@@ -234,6 +242,39 @@ inet_csk_find_open_port(struct sock *sk, struct inet_bind_bucket **tb_ret, int *
234
242
return head ;
235
243
}
236
244
245
+ static inline int sk_reuseport_match (struct inet_bind_bucket * tb ,
246
+ struct sock * sk )
247
+ {
248
+ kuid_t uid = sock_i_uid (sk );
249
+
250
+ if (tb -> fastreuseport <= 0 )
251
+ return 0 ;
252
+ if (!sk -> sk_reuseport )
253
+ return 0 ;
254
+ if (rcu_access_pointer (sk -> sk_reuseport_cb ))
255
+ return 0 ;
256
+ if (!uid_eq (tb -> fastuid , uid ))
257
+ return 0 ;
258
+ /* We only need to check the rcv_saddr if this tb was once marked
259
+ * without fastreuseport and then was reset, as we can only know that
260
+ * the fast_*rcv_saddr doesn't have any conflicts with the socks on the
261
+ * owners list.
262
+ */
263
+ if (tb -> fastreuseport == FASTREUSEPORT_ANY )
264
+ return 1 ;
265
+ #if IS_ENABLED (CONFIG_IPV6 )
266
+ if (tb -> fast_sk_family == AF_INET6 )
267
+ return ipv6_rcv_saddr_equal (& tb -> fast_v6_rcv_saddr ,
268
+ & sk -> sk_v6_rcv_saddr ,
269
+ tb -> fast_rcv_saddr ,
270
+ sk -> sk_rcv_saddr ,
271
+ tb -> fast_ipv6_only ,
272
+ ipv6_only_sock (sk ), true);
273
+ #endif
274
+ return ipv4_rcv_saddr_equal (tb -> fast_rcv_saddr , sk -> sk_rcv_saddr ,
275
+ ipv6_only_sock (sk ), true);
276
+ }
277
+
237
278
/* Obtain a reference to a local port for the given sock,
238
279
* if snum is zero it means select any available local port.
239
280
* We try to allocate an odd port (and leave even ports for connect())
@@ -273,9 +314,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
273
314
goto success ;
274
315
275
316
if ((tb -> fastreuse > 0 && reuse ) ||
276
- (tb -> fastreuseport > 0 &&
277
- !rcu_access_pointer (sk -> sk_reuseport_cb ) &&
278
- sk -> sk_reuseport && uid_eq (tb -> fastuid , uid )))
317
+ sk_reuseport_match (tb , sk ))
279
318
goto success ;
280
319
if (inet_csk_bind_conflict (sk , tb , true, true))
281
320
goto fail_unlock ;
@@ -284,16 +323,43 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
284
323
if (!hlist_empty (& tb -> owners )) {
285
324
tb -> fastreuse = reuse ;
286
325
if (sk -> sk_reuseport ) {
287
- tb -> fastreuseport = 1 ;
326
+ tb -> fastreuseport = FASTREUSEPORT_ANY ;
288
327
tb -> fastuid = uid ;
328
+ tb -> fast_rcv_saddr = sk -> sk_rcv_saddr ;
329
+ tb -> fast_ipv6_only = ipv6_only_sock (sk );
330
+ #if IS_ENABLED (CONFIG_IPV6 )
331
+ tb -> fast_v6_rcv_saddr = sk -> sk_v6_rcv_saddr ;
332
+ #endif
289
333
} else {
290
334
tb -> fastreuseport = 0 ;
291
335
}
292
336
} else {
293
337
if (!reuse )
294
338
tb -> fastreuse = 0 ;
295
- if (!sk -> sk_reuseport || !uid_eq (tb -> fastuid , uid ))
339
+ if (sk -> sk_reuseport ) {
340
+ /* We didn't match or we don't have fastreuseport set on
341
+ * the tb, but we have sk_reuseport set on this socket
342
+ * and we know that there are no bind conflicts with
343
+ * this socket in this tb, so reset our tb's reuseport
344
+ * settings so that any subsequent sockets that match
345
+ * our current socket will be put on the fast path.
346
+ *
347
+ * If we reset we need to set FASTREUSEPORT_STRICT so we
348
+ * do extra checking for all subsequent sk_reuseport
349
+ * socks.
350
+ */
351
+ if (!sk_reuseport_match (tb , sk )) {
352
+ tb -> fastreuseport = FASTREUSEPORT_STRICT ;
353
+ tb -> fastuid = uid ;
354
+ tb -> fast_rcv_saddr = sk -> sk_rcv_saddr ;
355
+ tb -> fast_ipv6_only = ipv6_only_sock (sk );
356
+ #if IS_ENABLED (CONFIG_IPV6 )
357
+ tb -> fast_v6_rcv_saddr = sk -> sk_v6_rcv_saddr ;
358
+ #endif
359
+ }
360
+ } else {
296
361
tb -> fastreuseport = 0 ;
362
+ }
297
363
}
298
364
if (!inet_csk (sk )-> icsk_bind_hash )
299
365
inet_bind_hash (sk , tb , port );
0 commit comments