@@ -119,6 +119,44 @@ 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
+ iter_fd = bpf_iter_create (bpf_link__fd (link ));
136
+ if (!ASSERT_OK_FD (iter_fd , "bpf_iter_create" ))
137
+ return false;
138
+
139
+ /* Is it still there? */
140
+ do {
141
+ nread = read (iter_fd , & out , sizeof (out ));
142
+ if (!ASSERT_GE (nread , 0 , "nread" )) {
143
+ close (iter_fd );
144
+ return false;
145
+ }
146
+ exists = nread && cookie == out .cookie ;
147
+ } while (!exists && nread );
148
+
149
+ close (iter_fd );
150
+
151
+ if (!exists )
152
+ break ;
153
+
154
+ usleep (100 * us_per_ms );
155
+ }
156
+
157
+ return !exists ;
158
+ }
159
+
122
160
static int get_seen_count (int fd , struct sock_count counts [], int n )
123
161
{
124
162
__u64 cookie = socket_cookie (fd );
@@ -241,6 +279,43 @@ static void remove_seen(int family, int sock_type, const char *addr, __u16 port,
241
279
counts_len );
242
280
}
243
281
282
+ static void remove_seen_established (int family , int sock_type , const char * addr ,
283
+ __u16 port , int * listen_socks ,
284
+ int listen_socks_len , int * established_socks ,
285
+ int established_socks_len ,
286
+ struct sock_count * counts , int counts_len ,
287
+ struct bpf_link * link , int iter_fd )
288
+ {
289
+ int close_idx ;
290
+
291
+ /* Iterate through all listening sockets. */
292
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
293
+
294
+ /* Make sure we saw all listening sockets exactly once. */
295
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
296
+ counts , counts_len );
297
+
298
+ /* Leave one established socket. */
299
+ read_n (iter_fd , established_socks_len - 1 , counts , counts_len );
300
+
301
+ /* Close a socket we've already seen to remove it from the bucket. */
302
+ close_idx = get_seen_socket (established_socks , counts , counts_len );
303
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
304
+ return ;
305
+ ASSERT_TRUE (close_and_wait (established_socks [close_idx ], link ),
306
+ "close_and_wait" );
307
+ established_socks [close_idx ] = -1 ;
308
+
309
+ /* Iterate through the rest of the sockets. */
310
+ read_n (iter_fd , -1 , counts , counts_len );
311
+
312
+ /* Make sure the last socket wasn't skipped and that there were no
313
+ * repeats.
314
+ */
315
+ check_n_were_seen_once (established_socks , established_socks_len ,
316
+ established_socks_len - 1 , counts , counts_len );
317
+ }
318
+
244
319
static void remove_unseen (int family , int sock_type , const char * addr ,
245
320
__u16 port , int * socks , int socks_len ,
246
321
int * established_socks , int established_socks_len ,
@@ -274,6 +349,52 @@ static void remove_unseen(int family, int sock_type, const char *addr,
274
349
counts_len );
275
350
}
276
351
352
+ static void remove_unseen_established (int family , int sock_type ,
353
+ const char * addr , __u16 port ,
354
+ int * listen_socks , int listen_socks_len ,
355
+ int * established_socks ,
356
+ int established_socks_len ,
357
+ struct sock_count * counts , int counts_len ,
358
+ struct bpf_link * link , int iter_fd )
359
+ {
360
+ int close_idx ;
361
+
362
+ /* Iterate through all listening sockets. */
363
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
364
+
365
+ /* Make sure we saw all listening sockets exactly once. */
366
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
367
+ counts , counts_len );
368
+
369
+ /* Iterate through the first established socket. */
370
+ read_n (iter_fd , 1 , counts , counts_len );
371
+
372
+ /* Make sure we saw one established socks. */
373
+ check_n_were_seen_once (established_socks , established_socks_len , 1 ,
374
+ counts , counts_len );
375
+
376
+ /* Close what would be the next socket in the bucket to exercise the
377
+ * condition where we need to skip past the first cookie we remembered.
378
+ */
379
+ close_idx = get_nth_socket (established_socks , established_socks_len ,
380
+ link , listen_socks_len + 1 );
381
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
382
+ return ;
383
+
384
+ ASSERT_TRUE (close_and_wait (established_socks [close_idx ], link ),
385
+ "close_and_wait" );
386
+ established_socks [close_idx ] = -1 ;
387
+
388
+ /* Iterate through the rest of the sockets. */
389
+ read_n (iter_fd , -1 , counts , counts_len );
390
+
391
+ /* Make sure the remaining sockets were seen exactly once and that we
392
+ * didn't repeat the socket that was already seen.
393
+ */
394
+ check_n_were_seen_once (established_socks , established_socks_len ,
395
+ established_socks_len - 1 , counts , counts_len );
396
+ }
397
+
277
398
static void remove_all (int family , int sock_type , const char * addr ,
278
399
__u16 port , int * socks , int socks_len ,
279
400
int * established_socks , int established_socks_len ,
@@ -303,6 +424,47 @@ static void remove_all(int family, int sock_type, const char *addr,
303
424
ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
304
425
}
305
426
427
+ static void remove_all_established (int family , int sock_type , const char * addr ,
428
+ __u16 port , int * listen_socks ,
429
+ int listen_socks_len , int * established_socks ,
430
+ int established_socks_len ,
431
+ struct sock_count * counts , int counts_len ,
432
+ struct bpf_link * link , int iter_fd )
433
+ {
434
+ int close_idx , i ;
435
+
436
+ /* Iterate through all listening sockets. */
437
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
438
+
439
+ /* Make sure we saw all listening sockets exactly once. */
440
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
441
+ counts , counts_len );
442
+
443
+ /* Iterate through the first established socket. */
444
+ read_n (iter_fd , 1 , counts , counts_len );
445
+
446
+ /* Make sure we saw one established socks. */
447
+ check_n_were_seen_once (established_socks , established_socks_len , 1 ,
448
+ counts , counts_len );
449
+
450
+ /* Close all remaining sockets to exhaust the list of saved cookies and
451
+ * exit without putting any sockets into the batch on the next read.
452
+ */
453
+ for (i = 0 ; i < established_socks_len - 1 ; i ++ ) {
454
+ close_idx = get_nth_socket (established_socks ,
455
+ established_socks_len , link ,
456
+ listen_socks_len + 1 );
457
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
458
+ return ;
459
+ ASSERT_TRUE (close_and_wait (established_socks [close_idx ], link ),
460
+ "close_and_wait" );
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