@@ -120,6 +120,45 @@ static int get_nth_socket(int *fds, int fds_len, struct bpf_link *link, int n)
120
120
return nth_sock_idx ;
121
121
}
122
122
123
+ static void destroy (int fd )
124
+ {
125
+ struct sock_iter_batch * skel = NULL ;
126
+ __u64 cookie = socket_cookie (fd );
127
+ struct bpf_link * link = NULL ;
128
+ int iter_fd = -1 ;
129
+ int nread ;
130
+ __u64 out ;
131
+
132
+ skel = sock_iter_batch__open ();
133
+ if (!ASSERT_OK_PTR (skel , "sock_iter_batch__open" ))
134
+ goto done ;
135
+
136
+ skel -> rodata -> destroy_cookie = cookie ;
137
+
138
+ if (!ASSERT_OK (sock_iter_batch__load (skel ), "sock_iter_batch__load" ))
139
+ goto done ;
140
+
141
+ link = bpf_program__attach_iter (skel -> progs .iter_tcp_destroy , NULL );
142
+ if (!ASSERT_OK_PTR (link , "bpf_program__attach_iter" ))
143
+ goto done ;
144
+
145
+ iter_fd = bpf_iter_create (bpf_link__fd (link ));
146
+ if (!ASSERT_OK_FD (iter_fd , "bpf_iter_create" ))
147
+ goto done ;
148
+
149
+ /* Delete matching socket. */
150
+ nread = read (iter_fd , & out , sizeof (out ));
151
+ ASSERT_GE (nread , 0 , "nread" );
152
+ if (nread )
153
+ ASSERT_EQ (out , cookie , "cookie matches" );
154
+ done :
155
+ if (iter_fd >= 0 )
156
+ close (iter_fd );
157
+ bpf_link__destroy (link );
158
+ sock_iter_batch__destroy (skel );
159
+ close (fd );
160
+ }
161
+
123
162
static int get_seen_count (int fd , struct sock_count counts [], int n )
124
163
{
125
164
__u64 cookie = socket_cookie (fd );
@@ -247,6 +286,43 @@ static void remove_seen(int family, int sock_type, const char *addr, __u16 port,
247
286
counts_len );
248
287
}
249
288
289
+ static void remove_seen_established (int family , int sock_type , const char * addr ,
290
+ __u16 port , int * listen_socks ,
291
+ int listen_socks_len , int * established_socks ,
292
+ int established_socks_len ,
293
+ struct sock_count * counts , int counts_len ,
294
+ struct bpf_link * link , int iter_fd )
295
+ {
296
+ int close_idx ;
297
+
298
+ /* Iterate through all listening sockets. */
299
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
300
+
301
+ /* Make sure we saw all listening sockets exactly once. */
302
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
303
+ counts , counts_len );
304
+
305
+ /* Leave one established socket. */
306
+ read_n (iter_fd , established_socks_len - 1 , counts , counts_len );
307
+
308
+ /* Close a socket we've already seen to remove it from the bucket. */
309
+ close_idx = get_nth_socket (established_socks , established_socks_len ,
310
+ link , listen_socks_len + 1 );
311
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
312
+ return ;
313
+ destroy (established_socks [close_idx ]);
314
+ established_socks [close_idx ] = -1 ;
315
+
316
+ /* Iterate through the rest of the sockets. */
317
+ read_n (iter_fd , -1 , counts , counts_len );
318
+
319
+ /* Make sure the last socket wasn't skipped and that there were no
320
+ * repeats.
321
+ */
322
+ check_n_were_seen_once (established_socks , established_socks_len ,
323
+ established_socks_len - 1 , counts , counts_len );
324
+ }
325
+
250
326
static void remove_unseen (int family , int sock_type , const char * addr ,
251
327
__u16 port , int * socks , int socks_len ,
252
328
int * established_socks , int established_socks_len ,
@@ -280,6 +356,51 @@ static void remove_unseen(int family, int sock_type, const char *addr,
280
356
counts_len );
281
357
}
282
358
359
+ static void remove_unseen_established (int family , int sock_type ,
360
+ const char * addr , __u16 port ,
361
+ int * listen_socks , int listen_socks_len ,
362
+ int * established_socks ,
363
+ int established_socks_len ,
364
+ struct sock_count * counts , int counts_len ,
365
+ struct bpf_link * link , int iter_fd )
366
+ {
367
+ int close_idx ;
368
+
369
+ /* Iterate through all listening sockets. */
370
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
371
+
372
+ /* Make sure we saw all listening sockets exactly once. */
373
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
374
+ counts , counts_len );
375
+
376
+ /* Iterate through the first established socket. */
377
+ read_n (iter_fd , 1 , counts , counts_len );
378
+
379
+ /* Make sure we saw one established socks. */
380
+ check_n_were_seen_once (established_socks , established_socks_len , 1 ,
381
+ counts , counts_len );
382
+
383
+ /* Close what would be the next socket in the bucket to exercise the
384
+ * condition where we need to skip past the first cookie we remembered.
385
+ */
386
+ close_idx = get_nth_socket (established_socks , established_socks_len ,
387
+ link , listen_socks_len + 1 );
388
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
389
+ return ;
390
+
391
+ destroy (established_socks [close_idx ]);
392
+ established_socks [close_idx ] = -1 ;
393
+
394
+ /* Iterate through the rest of the sockets. */
395
+ read_n (iter_fd , -1 , counts , counts_len );
396
+
397
+ /* Make sure the remaining sockets were seen exactly once and that we
398
+ * didn't repeat the socket that was already seen.
399
+ */
400
+ check_n_were_seen_once (established_socks , established_socks_len ,
401
+ established_socks_len - 1 , counts , counts_len );
402
+ }
403
+
283
404
static void remove_all (int family , int sock_type , const char * addr ,
284
405
__u16 port , int * socks , int socks_len ,
285
406
int * established_socks , int established_socks_len ,
@@ -309,6 +430,54 @@ static void remove_all(int family, int sock_type, const char *addr,
309
430
ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
310
431
}
311
432
433
+ static void remove_all_established (int family , int sock_type , const char * addr ,
434
+ __u16 port , int * listen_socks ,
435
+ int listen_socks_len , int * established_socks ,
436
+ int established_socks_len ,
437
+ struct sock_count * counts , int counts_len ,
438
+ struct bpf_link * link , int iter_fd )
439
+ {
440
+ int * close_idx = NULL ;
441
+ int i ;
442
+
443
+ /* Iterate through all listening sockets. */
444
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
445
+
446
+ /* Make sure we saw all listening sockets exactly once. */
447
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
448
+ counts , counts_len );
449
+
450
+ /* Iterate through the first established socket. */
451
+ read_n (iter_fd , 1 , counts , counts_len );
452
+
453
+ /* Make sure we saw one established socks. */
454
+ check_n_were_seen_once (established_socks , established_socks_len , 1 ,
455
+ counts , counts_len );
456
+
457
+ /* Close all remaining sockets to exhaust the list of saved cookies and
458
+ * exit without putting any sockets into the batch on the next read.
459
+ */
460
+ close_idx = malloc (sizeof (int ) * (established_socks_len - 1 ));
461
+ if (!ASSERT_OK_PTR (close_idx , "close_idx malloc" ))
462
+ return ;
463
+ for (i = 0 ; i < established_socks_len - 1 ; i ++ ) {
464
+ close_idx [i ] = get_nth_socket (established_socks ,
465
+ established_socks_len , link ,
466
+ listen_socks_len + i );
467
+ if (!ASSERT_GE (close_idx [i ], 0 , "close_idx" ))
468
+ return ;
469
+ }
470
+
471
+ for (i = 0 ; i < established_socks_len - 1 ; i ++ ) {
472
+ destroy (established_socks [close_idx [i ]]);
473
+ established_socks [close_idx [i ]] = -1 ;
474
+ }
475
+
476
+ /* Make sure there are no more sockets returned */
477
+ ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
478
+ free (close_idx );
479
+ }
480
+
312
481
static void add_some (int family , int sock_type , const char * addr , __u16 port ,
313
482
int * socks , int socks_len , int * established_socks ,
314
483
int established_socks_len , struct sock_count * counts ,
@@ -339,6 +508,49 @@ static void add_some(int family, int sock_type, const char *addr, __u16 port,
339
508
free_fds (new_socks , socks_len );
340
509
}
341
510
511
+ static void add_some_established (int family , int sock_type , const char * addr ,
512
+ __u16 port , int * listen_socks ,
513
+ int listen_socks_len , int * established_socks ,
514
+ int established_socks_len ,
515
+ struct sock_count * counts ,
516
+ int counts_len , struct bpf_link * link ,
517
+ int iter_fd )
518
+ {
519
+ int * new_socks = NULL ;
520
+
521
+ /* Iterate through all listening sockets. */
522
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
523
+
524
+ /* Make sure we saw all listening sockets exactly once. */
525
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
526
+ counts , counts_len );
527
+
528
+ /* Iterate through the first established_socks_len - 1 sockets. */
529
+ read_n (iter_fd , established_socks_len - 1 , counts , counts_len );
530
+
531
+ /* Make sure we saw established_socks_len - 1 sockets exactly once. */
532
+ check_n_were_seen_once (established_socks , established_socks_len ,
533
+ established_socks_len - 1 , counts , counts_len );
534
+
535
+ /* Double the number of established sockets in the bucket. */
536
+ new_socks = connect_to_server (family , sock_type , addr , port ,
537
+ established_socks_len / 2 , listen_socks ,
538
+ listen_socks_len );
539
+ if (!ASSERT_OK_PTR (new_socks , "connect_to_server" ))
540
+ goto done ;
541
+
542
+ /* Iterate through the rest of the sockets. */
543
+ read_n (iter_fd , -1 , counts , counts_len );
544
+
545
+ /* Make sure each of the original sockets was seen exactly once. */
546
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
547
+ counts , counts_len );
548
+ check_n_were_seen_once (established_socks , established_socks_len ,
549
+ established_socks_len , counts , counts_len );
550
+ done :
551
+ free_fds (new_socks , established_socks_len );
552
+ }
553
+
342
554
static void force_realloc (int family , int sock_type , const char * addr ,
343
555
__u16 port , int * socks , int socks_len ,
344
556
int * established_socks , int established_socks_len ,
@@ -368,6 +580,24 @@ static void force_realloc(int family, int sock_type, const char *addr,
368
580
free_fds (new_socks , socks_len );
369
581
}
370
582
583
+ static void force_realloc_established (int family , int sock_type ,
584
+ const char * addr , __u16 port ,
585
+ int * listen_socks , int listen_socks_len ,
586
+ int * established_socks ,
587
+ int established_socks_len ,
588
+ struct sock_count * counts , int counts_len ,
589
+ struct bpf_link * link , int iter_fd )
590
+ {
591
+ /* Iterate through all sockets to trigger a realloc. */
592
+ read_n (iter_fd , -1 , counts , counts_len );
593
+
594
+ /* Make sure each socket was seen exactly once. */
595
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
596
+ counts , counts_len );
597
+ check_n_were_seen_once (established_socks , established_socks_len ,
598
+ established_socks_len , counts , counts_len );
599
+ }
600
+
371
601
struct test_case {
372
602
void (* test )(int family , int sock_type , const char * addr , __u16 port ,
373
603
int * socks , int socks_len , int * established_socks ,
@@ -477,6 +707,69 @@ static struct test_case resume_tests[] = {
477
707
.family = AF_INET6 ,
478
708
.test = force_realloc ,
479
709
},
710
+ {
711
+ .description = "tcp: resume after removing a seen socket (established)" ,
712
+ /* Force all established sockets into one bucket */
713
+ .ehash_buckets = 1 ,
714
+ .connections = nr_soreuse ,
715
+ .init_socks = nr_soreuse ,
716
+ /* Room for connect()ed and accept()ed sockets */
717
+ .max_socks = nr_soreuse * 3 ,
718
+ .sock_type = SOCK_STREAM ,
719
+ .family = AF_INET6 ,
720
+ .test = remove_seen_established ,
721
+ },
722
+ {
723
+ .description = "tcp: resume after removing one unseen socket (established)" ,
724
+ /* Force all established sockets into one bucket */
725
+ .ehash_buckets = 1 ,
726
+ .connections = nr_soreuse ,
727
+ .init_socks = nr_soreuse ,
728
+ /* Room for connect()ed and accept()ed sockets */
729
+ .max_socks = nr_soreuse * 3 ,
730
+ .sock_type = SOCK_STREAM ,
731
+ .family = AF_INET6 ,
732
+ .test = remove_unseen_established ,
733
+ },
734
+ {
735
+ .description = "tcp: resume after removing all unseen sockets (established)" ,
736
+ /* Force all established sockets into one bucket */
737
+ .ehash_buckets = 1 ,
738
+ .connections = nr_soreuse ,
739
+ .init_socks = nr_soreuse ,
740
+ /* Room for connect()ed and accept()ed sockets */
741
+ .max_socks = nr_soreuse * 3 ,
742
+ .sock_type = SOCK_STREAM ,
743
+ .family = AF_INET6 ,
744
+ .test = remove_all_established ,
745
+ },
746
+ {
747
+ .description = "tcp: resume after adding a few sockets (established)" ,
748
+ /* Force all established sockets into one bucket */
749
+ .ehash_buckets = 1 ,
750
+ .connections = nr_soreuse ,
751
+ .init_socks = nr_soreuse ,
752
+ /* Room for connect()ed and accept()ed sockets */
753
+ .max_socks = nr_soreuse * 3 ,
754
+ .sock_type = SOCK_STREAM ,
755
+ .family = AF_INET6 ,
756
+ .test = add_some_established ,
757
+ },
758
+ {
759
+ .description = "tcp: force a realloc to occur (established)" ,
760
+ /* Force all established sockets into one bucket */
761
+ .ehash_buckets = 1 ,
762
+ /* Bucket size will need to double when going from listening to
763
+ * established sockets.
764
+ */
765
+ .connections = init_batch_size ,
766
+ .init_socks = nr_soreuse ,
767
+ /* Room for connect()ed and accept()ed sockets */
768
+ .max_socks = nr_soreuse + (init_batch_size * 2 ),
769
+ .sock_type = SOCK_STREAM ,
770
+ .family = AF_INET6 ,
771
+ .test = force_realloc_established ,
772
+ },
480
773
};
481
774
482
775
static void do_resume_test (struct test_case * tc )
0 commit comments