@@ -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 void destroy (int fd )
123
+ {
124
+ struct sock_iter_batch * skel = NULL ;
125
+ __u64 cookie = socket_cookie (fd );
126
+ struct bpf_link * link = NULL ;
127
+ int iter_fd = -1 ;
128
+ int nread ;
129
+ __u64 out ;
130
+
131
+ skel = sock_iter_batch__open ();
132
+ if (!ASSERT_OK_PTR (skel , "sock_iter_batch__open" ))
133
+ goto done ;
134
+
135
+ skel -> rodata -> destroy_cookie = cookie ;
136
+
137
+ if (!ASSERT_OK (sock_iter_batch__load (skel ), "sock_iter_batch__load" ))
138
+ goto done ;
139
+
140
+ link = bpf_program__attach_iter (skel -> progs .iter_tcp_destroy , NULL );
141
+ if (!ASSERT_OK_PTR (link , "bpf_program__attach_iter" ))
142
+ goto done ;
143
+
144
+ iter_fd = bpf_iter_create (bpf_link__fd (link ));
145
+ if (!ASSERT_OK_FD (iter_fd , "bpf_iter_create" ))
146
+ goto done ;
147
+
148
+ /* Delete matching socket. */
149
+ nread = read (iter_fd , & out , sizeof (out ));
150
+ ASSERT_GE (nread , 0 , "nread" );
151
+ if (nread )
152
+ ASSERT_EQ (out , cookie , "cookie matches" );
153
+ done :
154
+ if (iter_fd >= 0 )
155
+ close (iter_fd );
156
+ bpf_link__destroy (link );
157
+ sock_iter_batch__destroy (skel );
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_nth_socket (established_socks , established_socks_len ,
303
+ link , listen_socks_len + 1 );
304
+ if (!ASSERT_GE (close_idx , 0 , "close_idx" ))
305
+ return ;
306
+ destroy (established_socks [close_idx ]);
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,51 @@ 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
+ destroy (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,54 @@ 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 = NULL ;
434
+ int 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
+ close_idx = malloc (sizeof (int ) * (established_socks_len - 1 ));
454
+ if (!ASSERT_OK_PTR (close_idx , "close_idx malloc" ))
455
+ return ;
456
+ for (i = 0 ; i < established_socks_len - 1 ; i ++ ) {
457
+ close_idx [i ] = get_nth_socket (established_socks ,
458
+ established_socks_len , link ,
459
+ listen_socks_len + i );
460
+ if (!ASSERT_GE (close_idx [i ], 0 , "close_idx" ))
461
+ return ;
462
+ }
463
+
464
+ for (i = 0 ; i < established_socks_len - 1 ; i ++ ) {
465
+ destroy (established_socks [close_idx [i ]]);
466
+ established_socks [close_idx [i ]] = -1 ;
467
+ }
468
+
469
+ /* Make sure there are no more sockets returned */
470
+ ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
471
+ free (close_idx );
472
+ }
473
+
306
474
static void add_some (int family , int sock_type , const char * addr , __u16 port ,
307
475
int * socks , int socks_len , int * established_socks ,
308
476
int established_socks_len , struct sock_count * counts ,
@@ -333,6 +501,49 @@ static void add_some(int family, int sock_type, const char *addr, __u16 port,
333
501
free_fds (new_socks , socks_len );
334
502
}
335
503
504
+ static void add_some_established (int family , int sock_type , const char * addr ,
505
+ __u16 port , int * listen_socks ,
506
+ int listen_socks_len , int * established_socks ,
507
+ int established_socks_len ,
508
+ struct sock_count * counts ,
509
+ int counts_len , struct bpf_link * link ,
510
+ int iter_fd )
511
+ {
512
+ int * new_socks = NULL ;
513
+
514
+ /* Iterate through all listening sockets. */
515
+ read_n (iter_fd , listen_socks_len , counts , counts_len );
516
+
517
+ /* Make sure we saw all listening sockets exactly once. */
518
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
519
+ counts , counts_len );
520
+
521
+ /* Iterate through the first established_socks_len - 1 sockets. */
522
+ read_n (iter_fd , established_socks_len - 1 , counts , counts_len );
523
+
524
+ /* Make sure we saw established_socks_len - 1 sockets exactly once. */
525
+ check_n_were_seen_once (established_socks , established_socks_len ,
526
+ established_socks_len - 1 , counts , counts_len );
527
+
528
+ /* Double the number of established sockets in the bucket. */
529
+ new_socks = connect_to_server (family , sock_type , addr , port ,
530
+ established_socks_len / 2 , listen_socks ,
531
+ listen_socks_len );
532
+ if (!ASSERT_OK_PTR (new_socks , "connect_to_server" ))
533
+ goto done ;
534
+
535
+ /* Iterate through the rest of the sockets. */
536
+ read_n (iter_fd , -1 , counts , counts_len );
537
+
538
+ /* Make sure each of the original sockets was seen exactly once. */
539
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
540
+ counts , counts_len );
541
+ check_n_were_seen_once (established_socks , established_socks_len ,
542
+ established_socks_len , counts , counts_len );
543
+ done :
544
+ free_fds (new_socks , established_socks_len );
545
+ }
546
+
336
547
static void force_realloc (int family , int sock_type , const char * addr ,
337
548
__u16 port , int * socks , int socks_len ,
338
549
int * established_socks , int established_socks_len ,
@@ -362,6 +573,24 @@ static void force_realloc(int family, int sock_type, const char *addr,
362
573
free_fds (new_socks , socks_len );
363
574
}
364
575
576
+ static void force_realloc_established (int family , int sock_type ,
577
+ const char * addr , __u16 port ,
578
+ int * listen_socks , int listen_socks_len ,
579
+ int * established_socks ,
580
+ int established_socks_len ,
581
+ struct sock_count * counts , int counts_len ,
582
+ struct bpf_link * link , int iter_fd )
583
+ {
584
+ /* Iterate through all sockets to trigger a realloc. */
585
+ read_n (iter_fd , -1 , counts , counts_len );
586
+
587
+ /* Make sure each socket was seen exactly once. */
588
+ check_n_were_seen_once (listen_socks , listen_socks_len , listen_socks_len ,
589
+ counts , counts_len );
590
+ check_n_were_seen_once (established_socks , established_socks_len ,
591
+ established_socks_len , counts , counts_len );
592
+ }
593
+
365
594
struct test_case {
366
595
void (* test )(int family , int sock_type , const char * addr , __u16 port ,
367
596
int * socks , int socks_len , int * established_socks ,
@@ -471,6 +700,69 @@ static struct test_case resume_tests[] = {
471
700
.family = AF_INET6 ,
472
701
.test = force_realloc ,
473
702
},
703
+ {
704
+ .description = "tcp: resume after removing a seen socket (established)" ,
705
+ /* Force all established sockets into one bucket */
706
+ .ehash_buckets = 1 ,
707
+ .connections = nr_soreuse ,
708
+ .init_socks = nr_soreuse ,
709
+ /* Room for connect()ed and accept()ed sockets */
710
+ .max_socks = nr_soreuse * 3 ,
711
+ .sock_type = SOCK_STREAM ,
712
+ .family = AF_INET6 ,
713
+ .test = remove_seen_established ,
714
+ },
715
+ {
716
+ .description = "tcp: resume after removing one unseen socket (established)" ,
717
+ /* Force all established sockets into one bucket */
718
+ .ehash_buckets = 1 ,
719
+ .connections = nr_soreuse ,
720
+ .init_socks = nr_soreuse ,
721
+ /* Room for connect()ed and accept()ed sockets */
722
+ .max_socks = nr_soreuse * 3 ,
723
+ .sock_type = SOCK_STREAM ,
724
+ .family = AF_INET6 ,
725
+ .test = remove_unseen_established ,
726
+ },
727
+ {
728
+ .description = "tcp: resume after removing all unseen sockets (established)" ,
729
+ /* Force all established sockets into one bucket */
730
+ .ehash_buckets = 1 ,
731
+ .connections = nr_soreuse ,
732
+ .init_socks = nr_soreuse ,
733
+ /* Room for connect()ed and accept()ed sockets */
734
+ .max_socks = nr_soreuse * 3 ,
735
+ .sock_type = SOCK_STREAM ,
736
+ .family = AF_INET6 ,
737
+ .test = remove_all_established ,
738
+ },
739
+ {
740
+ .description = "tcp: resume after adding a few sockets (established)" ,
741
+ /* Force all established sockets into one bucket */
742
+ .ehash_buckets = 1 ,
743
+ .connections = nr_soreuse ,
744
+ .init_socks = nr_soreuse ,
745
+ /* Room for connect()ed and accept()ed sockets */
746
+ .max_socks = nr_soreuse * 3 ,
747
+ .sock_type = SOCK_STREAM ,
748
+ .family = AF_INET6 ,
749
+ .test = add_some_established ,
750
+ },
751
+ {
752
+ .description = "tcp: force a realloc to occur (established)" ,
753
+ /* Force all established sockets into one bucket */
754
+ .ehash_buckets = 1 ,
755
+ /* Bucket size will need to double when going from listening to
756
+ * established sockets.
757
+ */
758
+ .connections = init_batch_size ,
759
+ .init_socks = nr_soreuse ,
760
+ /* Room for connect()ed and accept()ed sockets */
761
+ .max_socks = nr_soreuse + (init_batch_size * 2 ),
762
+ .sock_type = SOCK_STREAM ,
763
+ .family = AF_INET6 ,
764
+ .test = force_realloc_established ,
765
+ },
474
766
};
475
767
476
768
static void do_resume_test (struct test_case * tc )
0 commit comments