@@ -119,6 +119,44 @@ static int get_nth_socket(int *fds, int fds_len, struct bpf_link *link, int n)
119119 return nth_sock_idx ;
120120}
121121
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+
122160static int get_seen_count (int fd , struct sock_count counts [], int n )
123161{
124162 __u64 cookie = socket_cookie (fd );
@@ -241,6 +279,43 @@ static void remove_seen(int family, int sock_type, const char *addr, __u16 port,
241279 counts_len );
242280}
243281
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+
244319static void remove_unseen (int family , int sock_type , const char * addr ,
245320 __u16 port , int * socks , int socks_len ,
246321 int * established_socks , int established_socks_len ,
@@ -274,6 +349,51 @@ static void remove_unseen(int family, int sock_type, const char *addr,
274349 counts_len );
275350}
276351
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+
277397static void remove_all (int family , int sock_type , const char * addr ,
278398 __u16 port , int * socks , int socks_len ,
279399 int * established_socks , int established_socks_len ,
@@ -303,6 +423,54 @@ static void remove_all(int family, int sock_type, const char *addr,
303423 ASSERT_EQ (read_n (iter_fd , -1 , counts , counts_len ), 0 , "read_n" );
304424}
305425
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+
306474static void add_some (int family , int sock_type , const char * addr , __u16 port ,
307475 int * socks , int socks_len , int * established_socks ,
308476 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,
333501 free_fds (new_socks , socks_len );
334502}
335503
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+
336547static void force_realloc (int family , int sock_type , const char * addr ,
337548 __u16 port , int * socks , int socks_len ,
338549 int * established_socks , int established_socks_len ,
@@ -362,6 +573,24 @@ static void force_realloc(int family, int sock_type, const char *addr,
362573 free_fds (new_socks , socks_len );
363574}
364575
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+
365594struct test_case {
366595 void (* test )(int family , int sock_type , const char * addr , __u16 port ,
367596 int * socks , int socks_len , int * established_socks ,
@@ -471,6 +700,69 @@ static struct test_case resume_tests[] = {
471700 .family = AF_INET6 ,
472701 .test = force_realloc ,
473702 },
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+ },
474766};
475767
476768static void do_resume_test (struct test_case * tc )
0 commit comments