@@ -119,6 +119,46 @@ static int get_nth_socket(int *fds, int fds_len, struct bpf_link *link, int n)
119
119
return nth_sock_idx ;
120
120
}
121
121
122
+ static bool close_and_wait (int fd , struct bpf_link * link )
123
+ {
124
+ static const int us_per_ms = 1000 ;
125
+ __u64 cookie = socket_cookie (fd );
126
+ struct iter_out out ;
127
+ bool exists = true;
128
+ int iter_fd , nread ;
129
+ int waits = 20 ; /* 2 seconds */
130
+
131
+ close (fd );
132
+
133
+ /* Wait for socket to disappear from the ehash table. */
134
+ while (waits -- ) {
135
+ exists = false;
136
+
137
+ iter_fd = bpf_iter_create (bpf_link__fd (link ));
138
+ if (!ASSERT_OK_FD (iter_fd , "bpf_iter_create" ))
139
+ break ;
140
+
141
+ /* Is it still there? */
142
+ do {
143
+ nread = read (iter_fd , & out , sizeof (out ));
144
+ if (!ASSERT_GE (nread , 0 , "nread" )) {
145
+ close (iter_fd );
146
+ return false;
147
+ }
148
+ exists = nread && cookie == out .cookie ;
149
+ } while (!exists && nread );
150
+
151
+ close (iter_fd );
152
+
153
+ if (!exists )
154
+ break ;
155
+
156
+ usleep (100 * us_per_ms );
157
+ }
158
+
159
+ return !exists ;
160
+ }
161
+
122
162
static int get_seen_count (int fd , struct sock_count counts [], int n )
123
163
{
124
164
__u64 cookie = socket_cookie (fd );
@@ -241,6 +281,42 @@ static void remove_seen(int family, int sock_type, const char *addr, __u16 port,
241
281
counts_len );
242
282
}
243
283
284
+ static void remove_seen_established (int family , int sock_type , const char * addr ,
285
+ __u16 port , int * listen_socks ,
286
+ int listen_socks_len , int * established_socks ,
287
+ int established_socks_len ,
288
+ struct sock_count * counts , int counts_len ,
289
+ struct bpf_link * link , int iter_fd )
290
+ {
291
+ int close_idx ;
292
+
293
+ /* Iterate through all listening sockets. */
294
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
295
+
296
+ /* Make sure we saw all listening sockets exactly once. */
297
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
298
+ counts , counts_len );
299
+
300
+ /* Leave one established socket. */
301
+ read_n (iter_fd , established_socks_len - 1 , counts , counts_len );
302
+
303
+ /* Close a socket we've already seen to remove it from the bucket. */
304
+ close_idx = get_seen_socket (established_socks , counts , counts_len );
305
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
306
+ return ;
307
+ close (established_socks [close_idx ]);
308
+ established_socks [close_idx ] = -1 ;
309
+
310
+ /* Iterate through the rest of the sockets. */
311
+ read_n (iter_fd , -1 , counts , counts_len );
312
+
313
+ /* Make sure the last socket wasn't skipped and that there were no
314
+ * repeats.
315
+ */
316
+ check_n_were_seen_once (established_socks , established_socks_len ,
317
+ established_socks_len - 1 , counts , counts_len );
318
+ }
319
+
244
320
static void remove_unseen (int family , int sock_type , const char * addr ,
245
321
__u16 port , int * socks , int socks_len ,
246
322
int * established_socks , int established_socks_len ,
@@ -274,6 +350,50 @@ static void remove_unseen(int family, int sock_type, const char *addr,
274
350
counts_len );
275
351
}
276
352
353
+ static void remove_unseen_established (int family , int sock_type ,
354
+ const char * addr , __u16 port ,
355
+ int * listen_socks , int listen_socks_len ,
356
+ int * established_socks ,
357
+ int established_socks_len ,
358
+ struct sock_count * counts , int counts_len ,
359
+ struct bpf_link * link , int iter_fd )
360
+ {
361
+ int close_idx ;
362
+
363
+ /* Iterate through all listening sockets. */
364
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
365
+
366
+ /* Make sure we saw all listening sockets exactly once. */
367
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
368
+ counts , counts_len );
369
+
370
+ /* Iterate through the first established socket. */
371
+ read_n (iter_fd , 1 , counts , counts_len );
372
+
373
+ /* Make sure we saw one established socks. */
374
+ check_n_were_seen_once (established_socks , established_socks_len , 1 ,
375
+ counts , counts_len );
376
+
377
+ /* Close what would be the next socket in the bucket to exercise the
378
+ * condition where we need to skip past the first cookie we remembered.
379
+ */
380
+ close_idx = get_nth_socket (established_socks , established_socks_len ,
381
+ link , listen_socks_len + 1 );
382
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
383
+ return ;
384
+ close (established_socks [close_idx ]);
385
+ established_socks [close_idx ] = -1 ;
386
+
387
+ /* Iterate through the rest of the sockets. */
388
+ read_n (iter_fd , -1 , counts , counts_len );
389
+
390
+ /* Make sure the remaining sockets were seen exactly once and that we
391
+ * didn't repeat the socket that was already seen.
392
+ */
393
+ check_n_were_seen_once (established_socks , established_socks_len ,
394
+ established_socks_len - 1 , counts , counts_len );
395
+ }
396
+
277
397
static void remove_all (int family , int sock_type , const char * addr ,
278
398
__u16 port , int * socks , int socks_len ,
279
399
int * established_socks , int established_socks_len ,
@@ -303,6 +423,48 @@ static void remove_all(int family, int sock_type, const char *addr,
303
423
ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
304
424
}
305
425
426
+ static void remove_all_established (int family , int sock_type , const char * addr ,
427
+ __u16 port , int * listen_socks ,
428
+ int listen_socks_len , int * established_socks ,
429
+ int established_socks_len ,
430
+ struct sock_count * counts , int counts_len ,
431
+ struct bpf_link * link , int iter_fd )
432
+ {
433
+ int close_idx , i ;
434
+
435
+ /* Iterate through all listening sockets. */
436
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
437
+
438
+ /* Make sure we saw all listening sockets exactly once. */
439
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
440
+ counts , counts_len );
441
+
442
+ /* Iterate through the first established socket. */
443
+ read_n (iter_fd , 1 , counts , counts_len );
444
+
445
+ /* Make sure we saw one established socks. */
446
+ check_n_were_seen_once (established_socks , established_socks_len , 1 ,
447
+ counts , counts_len );
448
+
449
+ /* Close all remaining sockets to exhaust the list of saved cookies and
450
+ * exit without putting any sockets into the batch on the next read.
451
+ */
452
+ for (i = 0 ; i < established_socks_len - 1 ; i ++ ) {
453
+ close_idx = get_nth_socket (established_socks ,
454
+ established_socks_len , link ,
455
+ listen_socks_len + 1 );
456
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
457
+ return ;
458
+ if (!ASSERT_TRUE (close_and_wait (established_socks [close_idx ],
459
+ link ), "close_and_wait" ))
460
+ return ;
461
+ established_socks [close_idx ] = -1 ;
462
+ }
463
+
464
+ /* Make sure there are no more sockets returned */
465
+ ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
466
+ }
467
+
306
468
static void add_some (int family , int sock_type , const char * addr , __u16 port ,
307
469
int * socks , int socks_len , int * established_socks ,
308
470
int established_socks_len , struct sock_count * counts ,
@@ -333,6 +495,49 @@ static void add_some(int family, int sock_type, const char *addr, __u16 port,
333
495
free_fds (new_socks , socks_len );
334
496
}
335
497
498
+ static void add_some_established (int family , int sock_type , const char * addr ,
499
+ __u16 port , int * listen_socks ,
500
+ int listen_socks_len , int * established_socks ,
501
+ int established_socks_len ,
502
+ struct sock_count * counts ,
503
+ int counts_len , struct bpf_link * link ,
504
+ int iter_fd )
505
+ {
506
+ int * new_socks = NULL ;
507
+
508
+ /* Iterate through all listening sockets. */
509
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
510
+
511
+ /* Make sure we saw all listening sockets exactly once. */
512
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
513
+ counts , counts_len );
514
+
515
+ /* Iterate through the first established_socks_len - 1 sockets. */
516
+ read_n (iter_fd , established_socks_len - 1 , counts , counts_len );
517
+
518
+ /* Make sure we saw established_socks_len - 1 sockets exactly once. */
519
+ check_n_were_seen_once (established_socks , established_socks_len ,
520
+ established_socks_len - 1 , counts , counts_len );
521
+
522
+ /* Double the number of established sockets in the bucket. */
523
+ new_socks = connect_to_server (family , sock_type , addr , port ,
524
+ established_socks_len / 2 , listen_socks ,
525
+ listen_socks_len );
526
+ if (!ASSERT_OK_PTR (new_socks , "connect_to_server" ))
527
+ goto done ;
528
+
529
+ /* Iterate through the rest of the sockets. */
530
+ read_n (iter_fd , -1 , counts , counts_len );
531
+
532
+ /* Make sure each of the original sockets was seen exactly once. */
533
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
534
+ counts , counts_len );
535
+ check_n_were_seen_once (established_socks , established_socks_len ,
536
+ established_socks_len , counts , counts_len );
537
+ done :
538
+ free_fds (new_socks , established_socks_len );
539
+ }
540
+
336
541
static void force_realloc (int family , int sock_type , const char * addr ,
337
542
__u16 port , int * socks , int socks_len ,
338
543
int * established_socks , int established_socks_len ,
@@ -362,6 +567,24 @@ static void force_realloc(int family, int sock_type, const char *addr,
362
567
free_fds (new_socks , socks_len );
363
568
}
364
569
570
+ static void force_realloc_established (int family , int sock_type ,
571
+ const char * addr , __u16 port ,
572
+ int * listen_socks , int listen_socks_len ,
573
+ int * established_socks ,
574
+ int established_socks_len ,
575
+ struct sock_count * counts , int counts_len ,
576
+ struct bpf_link * link , int iter_fd )
577
+ {
578
+ /* Iterate through all sockets to trigger a realloc. */
579
+ read_n (iter_fd , -1 , counts , counts_len );
580
+
581
+ /* Make sure each socket was seen exactly once. */
582
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
583
+ counts , counts_len );
584
+ check_n_were_seen_once (established_socks , established_socks_len ,
585
+ established_socks_len , counts , counts_len );
586
+ }
587
+
365
588
struct test_case {
366
589
void (* test )(int family , int sock_type , const char * addr , __u16 port ,
367
590
int * socks , int socks_len , int * established_socks ,
@@ -471,6 +694,69 @@ static struct test_case resume_tests[] = {
471
694
.family = AF_INET6 ,
472
695
.test = force_realloc ,
473
696
},
697
+ {
698
+ .description = "tcp: resume after removing a seen socket (established)" ,
699
+ /* Force all established sockets into one bucket */
700
+ .ehash_buckets = 1 ,
701
+ .connections = nr_soreuse ,
702
+ .init_socks = nr_soreuse ,
703
+ /* Room for connect()ed and accept()ed sockets */
704
+ .max_socks = nr_soreuse * 3 ,
705
+ .sock_type = SOCK_STREAM ,
706
+ .family = AF_INET6 ,
707
+ .test = remove_seen_established ,
708
+ },
709
+ {
710
+ .description = "tcp: resume after removing one unseen socket (established)" ,
711
+ /* Force all established sockets into one bucket */
712
+ .ehash_buckets = 1 ,
713
+ .connections = nr_soreuse ,
714
+ .init_socks = nr_soreuse ,
715
+ /* Room for connect()ed and accept()ed sockets */
716
+ .max_socks = nr_soreuse * 3 ,
717
+ .sock_type = SOCK_STREAM ,
718
+ .family = AF_INET6 ,
719
+ .test = remove_unseen_established ,
720
+ },
721
+ {
722
+ .description = "tcp: resume after removing all unseen sockets (established)" ,
723
+ /* Force all established sockets into one bucket */
724
+ .ehash_buckets = 1 ,
725
+ .connections = nr_soreuse ,
726
+ .init_socks = nr_soreuse ,
727
+ /* Room for connect()ed and accept()ed sockets */
728
+ .max_socks = nr_soreuse * 3 ,
729
+ .sock_type = SOCK_STREAM ,
730
+ .family = AF_INET6 ,
731
+ .test = remove_all_established ,
732
+ },
733
+ {
734
+ .description = "tcp: resume after adding a few sockets (established)" ,
735
+ /* Force all established sockets into one bucket */
736
+ .ehash_buckets = 1 ,
737
+ .connections = nr_soreuse ,
738
+ .init_socks = nr_soreuse ,
739
+ /* Room for connect()ed and accept()ed sockets */
740
+ .max_socks = nr_soreuse * 3 ,
741
+ .sock_type = SOCK_STREAM ,
742
+ .family = AF_INET6 ,
743
+ .test = add_some_established ,
744
+ },
745
+ {
746
+ .description = "tcp: force a realloc to occur (established)" ,
747
+ /* Force all established sockets into one bucket */
748
+ .ehash_buckets = 1 ,
749
+ /* Bucket size will need to double when going from listening to
750
+ * established sockets.
751
+ */
752
+ .connections = init_batch_size ,
753
+ .init_socks = nr_soreuse ,
754
+ /* Room for connect()ed and accept()ed sockets */
755
+ .max_socks = nr_soreuse + (init_batch_size * 2 ),
756
+ .sock_type = SOCK_STREAM ,
757
+ .family = AF_INET6 ,
758
+ .test = force_realloc_established ,
759
+ },
474
760
};
475
761
476
762
static void do_resume_test (struct test_case * tc )
0 commit comments