@@ -120,6 +120,45 @@ static int get_nth_socket(int *fds, int fds_len, struct bpf_link *link, int n)
120120 return nth_sock_idx ;
121121}
122122
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+
123162static int get_seen_count (int fd , struct sock_count counts [], int n )
124163{
125164 __u64 cookie = socket_cookie (fd );
@@ -247,6 +286,43 @@ static void remove_seen(int family, int sock_type, const char *addr, __u16 port,
247286 counts_len );
248287}
249288
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+
250326static void remove_unseen (int family , int sock_type , const char * addr ,
251327 __u16 port , int * socks , int socks_len ,
252328 int * established_socks , int established_socks_len ,
@@ -280,6 +356,51 @@ static void remove_unseen(int family, int sock_type, const char *addr,
280356 counts_len );
281357}
282358
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+
283404static void remove_all (int family , int sock_type , const char * addr ,
284405 __u16 port , int * socks , int socks_len ,
285406 int * established_socks , int established_socks_len ,
@@ -309,6 +430,54 @@ static void remove_all(int family, int sock_type, const char *addr,
309430 ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
310431}
311432
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+
312481static void add_some (int family , int sock_type , const char * addr , __u16 port ,
313482 int * socks , int socks_len , int * established_socks ,
314483 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,
339508 free_fds (new_socks , socks_len );
340509}
341510
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+
342554static void force_realloc (int family , int sock_type , const char * addr ,
343555 __u16 port , int * socks , int socks_len ,
344556 int * established_socks , int established_socks_len ,
@@ -368,6 +580,24 @@ static void force_realloc(int family, int sock_type, const char *addr,
368580 free_fds (new_socks , socks_len );
369581}
370582
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+
371601struct test_case {
372602 void (* test )(int family , int sock_type , const char * addr , __u16 port ,
373603 int * socks , int socks_len , int * established_socks ,
@@ -477,6 +707,69 @@ static struct test_case resume_tests[] = {
477707 .family = AF_INET6 ,
478708 .test = force_realloc ,
479709 },
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+ },
480773};
481774
482775static void do_resume_test (struct test_case * tc )
0 commit comments