14
14
#include <errno.h>
15
15
#include <inttypes.h>
16
16
#include <linux/bpf.h>
17
+ #include <pthread.h>
17
18
#include <stdio.h>
18
19
#include <stdlib.h>
19
20
#include <string.h>
@@ -641,6 +642,98 @@ static void test_lpm_get_next_key(void)
641
642
close (map_fd );
642
643
}
643
644
645
+ #define MAX_TEST_KEYS 4
646
+ struct lpm_mt_test_info {
647
+ int cmd ; /* 0: update, 1: delete, 2: lookup, 3: get_next_key */
648
+ int iter ;
649
+ int map_fd ;
650
+ struct {
651
+ __u32 prefixlen ;
652
+ __u32 data ;
653
+ } key [MAX_TEST_KEYS ];
654
+ };
655
+
656
+ static void * lpm_test_command (void * arg )
657
+ {
658
+ int i , j , ret , iter , key_size ;
659
+ struct lpm_mt_test_info * info = arg ;
660
+ struct bpf_lpm_trie_key * key_p ;
661
+
662
+ key_size = sizeof (struct bpf_lpm_trie_key ) + sizeof (__u32 );
663
+ key_p = alloca (key_size );
664
+ for (iter = 0 ; iter < info -> iter ; iter ++ )
665
+ for (i = 0 ; i < MAX_TEST_KEYS ; i ++ ) {
666
+ /* first half of iterations in forward order,
667
+ * and second half in backward order.
668
+ */
669
+ j = (iter < (info -> iter / 2 )) ? i : MAX_TEST_KEYS - i - 1 ;
670
+ key_p -> prefixlen = info -> key [j ].prefixlen ;
671
+ memcpy (key_p -> data , & info -> key [j ].data , sizeof (__u32 ));
672
+ if (info -> cmd == 0 ) {
673
+ __u32 value = j ;
674
+ /* update must succeed */
675
+ assert (bpf_map_update_elem (info -> map_fd , key_p , & value , 0 ) == 0 );
676
+ } else if (info -> cmd == 1 ) {
677
+ ret = bpf_map_delete_elem (info -> map_fd , key_p );
678
+ assert (ret == 0 || errno == ENOENT );
679
+ } else if (info -> cmd == 2 ) {
680
+ __u32 value ;
681
+ ret = bpf_map_lookup_elem (info -> map_fd , key_p , & value );
682
+ assert (ret == 0 || errno == ENOENT );
683
+ } else {
684
+ struct bpf_lpm_trie_key * next_key_p = alloca (key_size );
685
+ ret = bpf_map_get_next_key (info -> map_fd , key_p , next_key_p );
686
+ assert (ret == 0 || errno == ENOENT || errno == ENOMEM );
687
+ }
688
+ }
689
+
690
+ // Pass successful exit info back to the main thread
691
+ pthread_exit ((void * )info );
692
+ }
693
+
694
+ static void setup_lpm_mt_test_info (struct lpm_mt_test_info * info , int map_fd )
695
+ {
696
+ info -> iter = 2000 ;
697
+ info -> map_fd = map_fd ;
698
+ info -> key [0 ].prefixlen = 16 ;
699
+ inet_pton (AF_INET , "192.168.0.0" , & info -> key [0 ].data );
700
+ info -> key [1 ].prefixlen = 24 ;
701
+ inet_pton (AF_INET , "192.168.0.0" , & info -> key [1 ].data );
702
+ info -> key [2 ].prefixlen = 24 ;
703
+ inet_pton (AF_INET , "192.168.128.0" , & info -> key [2 ].data );
704
+ info -> key [3 ].prefixlen = 24 ;
705
+ inet_pton (AF_INET , "192.168.1.0" , & info -> key [3 ].data );
706
+ }
707
+
708
+ static void test_lpm_multi_thread (void )
709
+ {
710
+ struct lpm_mt_test_info info [4 ];
711
+ size_t key_size , value_size ;
712
+ pthread_t thread_id [4 ];
713
+ int i , map_fd ;
714
+ void * ret ;
715
+
716
+ /* create a trie */
717
+ value_size = sizeof (__u32 );
718
+ key_size = sizeof (struct bpf_lpm_trie_key ) + value_size ;
719
+ map_fd = bpf_create_map (BPF_MAP_TYPE_LPM_TRIE , key_size , value_size ,
720
+ 100 , BPF_F_NO_PREALLOC );
721
+
722
+ /* create 4 threads to test update, delete, lookup and get_next_key */
723
+ setup_lpm_mt_test_info (& info [0 ], map_fd );
724
+ for (i = 0 ; i < 4 ; i ++ ) {
725
+ if (i != 0 )
726
+ memcpy (& info [i ], & info [0 ], sizeof (info [i ]));
727
+ info [i ].cmd = i ;
728
+ assert (pthread_create (& thread_id [i ], NULL , & lpm_test_command , & info [i ]) == 0 );
729
+ }
730
+
731
+ for (i = 0 ; i < 4 ; i ++ )
732
+ assert (pthread_join (thread_id [i ], & ret ) == 0 && ret == (void * )& info [i ]);
733
+
734
+ close (map_fd );
735
+ }
736
+
644
737
int main (void )
645
738
{
646
739
struct rlimit limit = { RLIM_INFINITY , RLIM_INFINITY };
@@ -667,6 +760,8 @@ int main(void)
667
760
668
761
test_lpm_get_next_key ();
669
762
763
+ test_lpm_multi_thread ();
764
+
670
765
printf ("test_lpm: OK\n" );
671
766
return 0 ;
672
767
}
0 commit comments