|
@@ -14,6 +14,7 @@
|
|
#include <errno.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <inttypes.h>
|
|
#include <linux/bpf.h>
|
|
#include <linux/bpf.h>
|
|
|
|
+#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <string.h>
|
|
@@ -641,6 +642,98 @@ static void test_lpm_get_next_key(void)
|
|
close(map_fd);
|
|
close(map_fd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define MAX_TEST_KEYS 4
|
|
|
|
+struct lpm_mt_test_info {
|
|
|
|
+ int cmd; /* 0: update, 1: delete, 2: lookup, 3: get_next_key */
|
|
|
|
+ int iter;
|
|
|
|
+ int map_fd;
|
|
|
|
+ struct {
|
|
|
|
+ __u32 prefixlen;
|
|
|
|
+ __u32 data;
|
|
|
|
+ } key[MAX_TEST_KEYS];
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void *lpm_test_command(void *arg)
|
|
|
|
+{
|
|
|
|
+ int i, j, ret, iter, key_size;
|
|
|
|
+ struct lpm_mt_test_info *info = arg;
|
|
|
|
+ struct bpf_lpm_trie_key *key_p;
|
|
|
|
+
|
|
|
|
+ key_size = sizeof(struct bpf_lpm_trie_key) + sizeof(__u32);
|
|
|
|
+ key_p = alloca(key_size);
|
|
|
|
+ for (iter = 0; iter < info->iter; iter++)
|
|
|
|
+ for (i = 0; i < MAX_TEST_KEYS; i++) {
|
|
|
|
+ /* first half of iterations in forward order,
|
|
|
|
+ * and second half in backward order.
|
|
|
|
+ */
|
|
|
|
+ j = (iter < (info->iter / 2)) ? i : MAX_TEST_KEYS - i - 1;
|
|
|
|
+ key_p->prefixlen = info->key[j].prefixlen;
|
|
|
|
+ memcpy(key_p->data, &info->key[j].data, sizeof(__u32));
|
|
|
|
+ if (info->cmd == 0) {
|
|
|
|
+ __u32 value = j;
|
|
|
|
+ /* update must succeed */
|
|
|
|
+ assert(bpf_map_update_elem(info->map_fd, key_p, &value, 0) == 0);
|
|
|
|
+ } else if (info->cmd == 1) {
|
|
|
|
+ ret = bpf_map_delete_elem(info->map_fd, key_p);
|
|
|
|
+ assert(ret == 0 || errno == ENOENT);
|
|
|
|
+ } else if (info->cmd == 2) {
|
|
|
|
+ __u32 value;
|
|
|
|
+ ret = bpf_map_lookup_elem(info->map_fd, key_p, &value);
|
|
|
|
+ assert(ret == 0 || errno == ENOENT);
|
|
|
|
+ } else {
|
|
|
|
+ struct bpf_lpm_trie_key *next_key_p = alloca(key_size);
|
|
|
|
+ ret = bpf_map_get_next_key(info->map_fd, key_p, next_key_p);
|
|
|
|
+ assert(ret == 0 || errno == ENOENT || errno == ENOMEM);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Pass successful exit info back to the main thread
|
|
|
|
+ pthread_exit((void *)info);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void setup_lpm_mt_test_info(struct lpm_mt_test_info *info, int map_fd)
|
|
|
|
+{
|
|
|
|
+ info->iter = 2000;
|
|
|
|
+ info->map_fd = map_fd;
|
|
|
|
+ info->key[0].prefixlen = 16;
|
|
|
|
+ inet_pton(AF_INET, "192.168.0.0", &info->key[0].data);
|
|
|
|
+ info->key[1].prefixlen = 24;
|
|
|
|
+ inet_pton(AF_INET, "192.168.0.0", &info->key[1].data);
|
|
|
|
+ info->key[2].prefixlen = 24;
|
|
|
|
+ inet_pton(AF_INET, "192.168.128.0", &info->key[2].data);
|
|
|
|
+ info->key[3].prefixlen = 24;
|
|
|
|
+ inet_pton(AF_INET, "192.168.1.0", &info->key[3].data);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void test_lpm_multi_thread(void)
|
|
|
|
+{
|
|
|
|
+ struct lpm_mt_test_info info[4];
|
|
|
|
+ size_t key_size, value_size;
|
|
|
|
+ pthread_t thread_id[4];
|
|
|
|
+ int i, map_fd;
|
|
|
|
+ void *ret;
|
|
|
|
+
|
|
|
|
+ /* create a trie */
|
|
|
|
+ value_size = sizeof(__u32);
|
|
|
|
+ key_size = sizeof(struct bpf_lpm_trie_key) + value_size;
|
|
|
|
+ map_fd = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE, key_size, value_size,
|
|
|
|
+ 100, BPF_F_NO_PREALLOC);
|
|
|
|
+
|
|
|
|
+ /* create 4 threads to test update, delete, lookup and get_next_key */
|
|
|
|
+ setup_lpm_mt_test_info(&info[0], map_fd);
|
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
|
+ if (i != 0)
|
|
|
|
+ memcpy(&info[i], &info[0], sizeof(info[i]));
|
|
|
|
+ info[i].cmd = i;
|
|
|
|
+ assert(pthread_create(&thread_id[i], NULL, &lpm_test_command, &info[i]) == 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < 4; i++)
|
|
|
|
+ assert(pthread_join(thread_id[i], &ret) == 0 && ret == (void *)&info[i]);
|
|
|
|
+
|
|
|
|
+ close(map_fd);
|
|
|
|
+}
|
|
|
|
+
|
|
int main(void)
|
|
int main(void)
|
|
{
|
|
{
|
|
struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY };
|
|
struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY };
|
|
@@ -667,6 +760,8 @@ int main(void)
|
|
|
|
|
|
test_lpm_get_next_key();
|
|
test_lpm_get_next_key();
|
|
|
|
|
|
|
|
+ test_lpm_multi_thread();
|
|
|
|
+
|
|
printf("test_lpm: OK\n");
|
|
printf("test_lpm: OK\n");
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|