162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Randomized tests for eBPF longest-prefix-match maps 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This program runs randomized tests against the lpm-bpf-map. It implements a 662306a36Sopenharmony_ci * "Trivial Longest Prefix Match" (tlpm) based on simple, linear, singly linked 762306a36Sopenharmony_ci * lists. The implementation should be pretty straightforward. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on tlpm, this inserts randomized data into bpf-lpm-maps and verifies 1062306a36Sopenharmony_ci * the trie-based bpf-map implementation behaves the same way as tlpm. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <assert.h> 1462306a36Sopenharmony_ci#include <errno.h> 1562306a36Sopenharmony_ci#include <inttypes.h> 1662306a36Sopenharmony_ci#include <linux/bpf.h> 1762306a36Sopenharmony_ci#include <pthread.h> 1862306a36Sopenharmony_ci#include <stdio.h> 1962306a36Sopenharmony_ci#include <stdlib.h> 2062306a36Sopenharmony_ci#include <string.h> 2162306a36Sopenharmony_ci#include <time.h> 2262306a36Sopenharmony_ci#include <unistd.h> 2362306a36Sopenharmony_ci#include <arpa/inet.h> 2462306a36Sopenharmony_ci#include <sys/time.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <bpf/bpf.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "bpf_util.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct tlpm_node { 3162306a36Sopenharmony_ci struct tlpm_node *next; 3262306a36Sopenharmony_ci size_t n_bits; 3362306a36Sopenharmony_ci uint8_t key[]; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct tlpm_node *tlpm_match(struct tlpm_node *list, 3762306a36Sopenharmony_ci const uint8_t *key, 3862306a36Sopenharmony_ci size_t n_bits); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct tlpm_node *tlpm_add(struct tlpm_node *list, 4162306a36Sopenharmony_ci const uint8_t *key, 4262306a36Sopenharmony_ci size_t n_bits) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct tlpm_node *node; 4562306a36Sopenharmony_ci size_t n; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci n = (n_bits + 7) / 8; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* 'overwrite' an equivalent entry if one already exists */ 5062306a36Sopenharmony_ci node = tlpm_match(list, key, n_bits); 5162306a36Sopenharmony_ci if (node && node->n_bits == n_bits) { 5262306a36Sopenharmony_ci memcpy(node->key, key, n); 5362306a36Sopenharmony_ci return list; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* add new entry with @key/@n_bits to @list and return new head */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci node = malloc(sizeof(*node) + n); 5962306a36Sopenharmony_ci assert(node); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci node->next = list; 6262306a36Sopenharmony_ci node->n_bits = n_bits; 6362306a36Sopenharmony_ci memcpy(node->key, key, n); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return node; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void tlpm_clear(struct tlpm_node *list) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct tlpm_node *node; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* free all entries in @list */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci while ((node = list)) { 7562306a36Sopenharmony_ci list = list->next; 7662306a36Sopenharmony_ci free(node); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic struct tlpm_node *tlpm_match(struct tlpm_node *list, 8162306a36Sopenharmony_ci const uint8_t *key, 8262306a36Sopenharmony_ci size_t n_bits) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct tlpm_node *best = NULL; 8562306a36Sopenharmony_ci size_t i; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Perform longest prefix-match on @key/@n_bits. That is, iterate all 8862306a36Sopenharmony_ci * entries and match each prefix against @key. Remember the "best" 8962306a36Sopenharmony_ci * entry we find (i.e., the longest prefix that matches) and return it 9062306a36Sopenharmony_ci * to the caller when done. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci for ( ; list; list = list->next) { 9462306a36Sopenharmony_ci for (i = 0; i < n_bits && i < list->n_bits; ++i) { 9562306a36Sopenharmony_ci if ((key[i / 8] & (1 << (7 - i % 8))) != 9662306a36Sopenharmony_ci (list->key[i / 8] & (1 << (7 - i % 8)))) 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (i >= list->n_bits) { 10162306a36Sopenharmony_ci if (!best || i > best->n_bits) 10262306a36Sopenharmony_ci best = list; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return best; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct tlpm_node *tlpm_delete(struct tlpm_node *list, 11062306a36Sopenharmony_ci const uint8_t *key, 11162306a36Sopenharmony_ci size_t n_bits) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct tlpm_node *best = tlpm_match(list, key, n_bits); 11462306a36Sopenharmony_ci struct tlpm_node *node; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!best || best->n_bits != n_bits) 11762306a36Sopenharmony_ci return list; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (best == list) { 12062306a36Sopenharmony_ci node = best->next; 12162306a36Sopenharmony_ci free(best); 12262306a36Sopenharmony_ci return node; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci for (node = list; node; node = node->next) { 12662306a36Sopenharmony_ci if (node->next == best) { 12762306a36Sopenharmony_ci node->next = best->next; 12862306a36Sopenharmony_ci free(best); 12962306a36Sopenharmony_ci return list; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci /* should never get here */ 13362306a36Sopenharmony_ci assert(0); 13462306a36Sopenharmony_ci return list; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void test_lpm_basic(void) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct tlpm_node *list = NULL, *t1, *t2; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* very basic, static tests to verify tlpm works as expected */ 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci assert(!tlpm_match(list, (uint8_t[]){ 0xff }, 8)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci t1 = list = tlpm_add(list, (uint8_t[]){ 0xff }, 8); 14662306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff }, 8)); 14762306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 16)); 14862306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0x00 }, 16)); 14962306a36Sopenharmony_ci assert(!tlpm_match(list, (uint8_t[]){ 0x7f }, 8)); 15062306a36Sopenharmony_ci assert(!tlpm_match(list, (uint8_t[]){ 0xfe }, 8)); 15162306a36Sopenharmony_ci assert(!tlpm_match(list, (uint8_t[]){ 0xff }, 7)); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci t2 = list = tlpm_add(list, (uint8_t[]){ 0xff, 0xff }, 16); 15462306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff }, 8)); 15562306a36Sopenharmony_ci assert(t2 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 16)); 15662306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 15)); 15762306a36Sopenharmony_ci assert(!tlpm_match(list, (uint8_t[]){ 0x7f, 0xff }, 16)); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci list = tlpm_delete(list, (uint8_t[]){ 0xff, 0xff }, 16); 16062306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff }, 8)); 16162306a36Sopenharmony_ci assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 16)); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci list = tlpm_delete(list, (uint8_t[]){ 0xff }, 8); 16462306a36Sopenharmony_ci assert(!tlpm_match(list, (uint8_t[]){ 0xff }, 8)); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci tlpm_clear(list); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void test_lpm_order(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct tlpm_node *t1, *t2, *l1 = NULL, *l2 = NULL; 17262306a36Sopenharmony_ci size_t i, j; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Verify the tlpm implementation works correctly regardless of the 17562306a36Sopenharmony_ci * order of entries. Insert a random set of entries into @l1, and copy 17662306a36Sopenharmony_ci * the same data in reverse order into @l2. Then verify a lookup of 17762306a36Sopenharmony_ci * random keys will yield the same result in both sets. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci for (i = 0; i < (1 << 12); ++i) 18162306a36Sopenharmony_ci l1 = tlpm_add(l1, (uint8_t[]){ 18262306a36Sopenharmony_ci rand() % 0xff, 18362306a36Sopenharmony_ci rand() % 0xff, 18462306a36Sopenharmony_ci }, rand() % 16 + 1); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci for (t1 = l1; t1; t1 = t1->next) 18762306a36Sopenharmony_ci l2 = tlpm_add(l2, t1->key, t1->n_bits); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < (1 << 8); ++i) { 19062306a36Sopenharmony_ci uint8_t key[] = { rand() % 0xff, rand() % 0xff }; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci t1 = tlpm_match(l1, key, 16); 19362306a36Sopenharmony_ci t2 = tlpm_match(l2, key, 16); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci assert(!t1 == !t2); 19662306a36Sopenharmony_ci if (t1) { 19762306a36Sopenharmony_ci assert(t1->n_bits == t2->n_bits); 19862306a36Sopenharmony_ci for (j = 0; j < t1->n_bits; ++j) 19962306a36Sopenharmony_ci assert((t1->key[j / 8] & (1 << (7 - j % 8))) == 20062306a36Sopenharmony_ci (t2->key[j / 8] & (1 << (7 - j % 8)))); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci tlpm_clear(l1); 20562306a36Sopenharmony_ci tlpm_clear(l2); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void test_lpm_map(int keysize) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); 21162306a36Sopenharmony_ci volatile size_t n_matches, n_matches_after_delete; 21262306a36Sopenharmony_ci size_t i, j, n_nodes, n_lookups; 21362306a36Sopenharmony_ci struct tlpm_node *t, *list = NULL; 21462306a36Sopenharmony_ci struct bpf_lpm_trie_key *key; 21562306a36Sopenharmony_ci uint8_t *data, *value; 21662306a36Sopenharmony_ci int r, map; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* Compare behavior of tlpm vs. bpf-lpm. Create a randomized set of 21962306a36Sopenharmony_ci * prefixes and insert it into both tlpm and bpf-lpm. Then run some 22062306a36Sopenharmony_ci * randomized lookups and verify both maps return the same result. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci n_matches = 0; 22462306a36Sopenharmony_ci n_matches_after_delete = 0; 22562306a36Sopenharmony_ci n_nodes = 1 << 8; 22662306a36Sopenharmony_ci n_lookups = 1 << 16; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci data = alloca(keysize); 22962306a36Sopenharmony_ci memset(data, 0, keysize); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci value = alloca(keysize + 1); 23262306a36Sopenharmony_ci memset(value, 0, keysize + 1); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci key = alloca(sizeof(*key) + keysize); 23562306a36Sopenharmony_ci memset(key, 0, sizeof(*key) + keysize); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci map = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, 23862306a36Sopenharmony_ci sizeof(*key) + keysize, 23962306a36Sopenharmony_ci keysize + 1, 24062306a36Sopenharmony_ci 4096, 24162306a36Sopenharmony_ci &opts); 24262306a36Sopenharmony_ci assert(map >= 0); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0; i < n_nodes; ++i) { 24562306a36Sopenharmony_ci for (j = 0; j < keysize; ++j) 24662306a36Sopenharmony_ci value[j] = rand() & 0xff; 24762306a36Sopenharmony_ci value[keysize] = rand() % (8 * keysize + 1); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci list = tlpm_add(list, value, value[keysize]); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci key->prefixlen = value[keysize]; 25262306a36Sopenharmony_ci memcpy(key->data, value, keysize); 25362306a36Sopenharmony_ci r = bpf_map_update_elem(map, key, value, 0); 25462306a36Sopenharmony_ci assert(!r); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < n_lookups; ++i) { 25862306a36Sopenharmony_ci for (j = 0; j < keysize; ++j) 25962306a36Sopenharmony_ci data[j] = rand() & 0xff; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci t = tlpm_match(list, data, 8 * keysize); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci key->prefixlen = 8 * keysize; 26462306a36Sopenharmony_ci memcpy(key->data, data, keysize); 26562306a36Sopenharmony_ci r = bpf_map_lookup_elem(map, key, value); 26662306a36Sopenharmony_ci assert(!r || errno == ENOENT); 26762306a36Sopenharmony_ci assert(!t == !!r); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (t) { 27062306a36Sopenharmony_ci ++n_matches; 27162306a36Sopenharmony_ci assert(t->n_bits == value[keysize]); 27262306a36Sopenharmony_ci for (j = 0; j < t->n_bits; ++j) 27362306a36Sopenharmony_ci assert((t->key[j / 8] & (1 << (7 - j % 8))) == 27462306a36Sopenharmony_ci (value[j / 8] & (1 << (7 - j % 8)))); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Remove the first half of the elements in the tlpm and the 27962306a36Sopenharmony_ci * corresponding nodes from the bpf-lpm. Then run the same 28062306a36Sopenharmony_ci * large number of random lookups in both and make sure they match. 28162306a36Sopenharmony_ci * Note: we need to count the number of nodes actually inserted 28262306a36Sopenharmony_ci * since there may have been duplicates. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci for (i = 0, t = list; t; i++, t = t->next) 28562306a36Sopenharmony_ci ; 28662306a36Sopenharmony_ci for (j = 0; j < i / 2; ++j) { 28762306a36Sopenharmony_ci key->prefixlen = list->n_bits; 28862306a36Sopenharmony_ci memcpy(key->data, list->key, keysize); 28962306a36Sopenharmony_ci r = bpf_map_delete_elem(map, key); 29062306a36Sopenharmony_ci assert(!r); 29162306a36Sopenharmony_ci list = tlpm_delete(list, list->key, list->n_bits); 29262306a36Sopenharmony_ci assert(list); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci for (i = 0; i < n_lookups; ++i) { 29562306a36Sopenharmony_ci for (j = 0; j < keysize; ++j) 29662306a36Sopenharmony_ci data[j] = rand() & 0xff; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci t = tlpm_match(list, data, 8 * keysize); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci key->prefixlen = 8 * keysize; 30162306a36Sopenharmony_ci memcpy(key->data, data, keysize); 30262306a36Sopenharmony_ci r = bpf_map_lookup_elem(map, key, value); 30362306a36Sopenharmony_ci assert(!r || errno == ENOENT); 30462306a36Sopenharmony_ci assert(!t == !!r); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (t) { 30762306a36Sopenharmony_ci ++n_matches_after_delete; 30862306a36Sopenharmony_ci assert(t->n_bits == value[keysize]); 30962306a36Sopenharmony_ci for (j = 0; j < t->n_bits; ++j) 31062306a36Sopenharmony_ci assert((t->key[j / 8] & (1 << (7 - j % 8))) == 31162306a36Sopenharmony_ci (value[j / 8] & (1 << (7 - j % 8)))); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci close(map); 31662306a36Sopenharmony_ci tlpm_clear(list); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* With 255 random nodes in the map, we are pretty likely to match 31962306a36Sopenharmony_ci * something on every lookup. For statistics, use this: 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * printf(" nodes: %zu\n" 32262306a36Sopenharmony_ci * " lookups: %zu\n" 32362306a36Sopenharmony_ci * " matches: %zu\n" 32462306a36Sopenharmony_ci * "matches(delete): %zu\n", 32562306a36Sopenharmony_ci * n_nodes, n_lookups, n_matches, n_matches_after_delete); 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* Test the implementation with some 'real world' examples */ 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void test_lpm_ipaddr(void) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); 33462306a36Sopenharmony_ci struct bpf_lpm_trie_key *key_ipv4; 33562306a36Sopenharmony_ci struct bpf_lpm_trie_key *key_ipv6; 33662306a36Sopenharmony_ci size_t key_size_ipv4; 33762306a36Sopenharmony_ci size_t key_size_ipv6; 33862306a36Sopenharmony_ci int map_fd_ipv4; 33962306a36Sopenharmony_ci int map_fd_ipv6; 34062306a36Sopenharmony_ci __u64 value; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci key_size_ipv4 = sizeof(*key_ipv4) + sizeof(__u32); 34362306a36Sopenharmony_ci key_size_ipv6 = sizeof(*key_ipv6) + sizeof(__u32) * 4; 34462306a36Sopenharmony_ci key_ipv4 = alloca(key_size_ipv4); 34562306a36Sopenharmony_ci key_ipv6 = alloca(key_size_ipv6); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci map_fd_ipv4 = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, 34862306a36Sopenharmony_ci key_size_ipv4, sizeof(value), 34962306a36Sopenharmony_ci 100, &opts); 35062306a36Sopenharmony_ci assert(map_fd_ipv4 >= 0); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci map_fd_ipv6 = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, 35362306a36Sopenharmony_ci key_size_ipv6, sizeof(value), 35462306a36Sopenharmony_ci 100, &opts); 35562306a36Sopenharmony_ci assert(map_fd_ipv6 >= 0); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Fill data some IPv4 and IPv6 address ranges */ 35862306a36Sopenharmony_ci value = 1; 35962306a36Sopenharmony_ci key_ipv4->prefixlen = 16; 36062306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key_ipv4->data); 36162306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, &value, 0) == 0); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci value = 2; 36462306a36Sopenharmony_ci key_ipv4->prefixlen = 24; 36562306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key_ipv4->data); 36662306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, &value, 0) == 0); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci value = 3; 36962306a36Sopenharmony_ci key_ipv4->prefixlen = 24; 37062306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.0", key_ipv4->data); 37162306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, &value, 0) == 0); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci value = 5; 37462306a36Sopenharmony_ci key_ipv4->prefixlen = 24; 37562306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.0", key_ipv4->data); 37662306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, &value, 0) == 0); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci value = 4; 37962306a36Sopenharmony_ci key_ipv4->prefixlen = 23; 38062306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key_ipv4->data); 38162306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, &value, 0) == 0); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci value = 0xdeadbeef; 38462306a36Sopenharmony_ci key_ipv6->prefixlen = 64; 38562306a36Sopenharmony_ci inet_pton(AF_INET6, "2a00:1450:4001:814::200e", key_ipv6->data); 38662306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd_ipv6, key_ipv6, &value, 0) == 0); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Set tprefixlen to maximum for lookups */ 38962306a36Sopenharmony_ci key_ipv4->prefixlen = 32; 39062306a36Sopenharmony_ci key_ipv6->prefixlen = 128; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Test some lookups that should come back with a value */ 39362306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.23", key_ipv4->data); 39462306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, &value) == 0); 39562306a36Sopenharmony_ci assert(value == 3); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.1", key_ipv4->data); 39862306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, &value) == 0); 39962306a36Sopenharmony_ci assert(value == 2); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci inet_pton(AF_INET6, "2a00:1450:4001:814::", key_ipv6->data); 40262306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, &value) == 0); 40362306a36Sopenharmony_ci assert(value == 0xdeadbeef); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci inet_pton(AF_INET6, "2a00:1450:4001:814::1", key_ipv6->data); 40662306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, &value) == 0); 40762306a36Sopenharmony_ci assert(value == 0xdeadbeef); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Test some lookups that should not match any entry */ 41062306a36Sopenharmony_ci inet_pton(AF_INET, "10.0.0.1", key_ipv4->data); 41162306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, &value) == -ENOENT); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci inet_pton(AF_INET, "11.11.11.11", key_ipv4->data); 41462306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, &value) == -ENOENT); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci inet_pton(AF_INET6, "2a00:ffff::", key_ipv6->data); 41762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, &value) == -ENOENT); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci close(map_fd_ipv4); 42062306a36Sopenharmony_ci close(map_fd_ipv6); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void test_lpm_delete(void) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); 42662306a36Sopenharmony_ci struct bpf_lpm_trie_key *key; 42762306a36Sopenharmony_ci size_t key_size; 42862306a36Sopenharmony_ci int map_fd; 42962306a36Sopenharmony_ci __u64 value; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci key_size = sizeof(*key) + sizeof(__u32); 43262306a36Sopenharmony_ci key = alloca(key_size); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci map_fd = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, 43562306a36Sopenharmony_ci key_size, sizeof(value), 43662306a36Sopenharmony_ci 100, &opts); 43762306a36Sopenharmony_ci assert(map_fd >= 0); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Add nodes: 44062306a36Sopenharmony_ci * 192.168.0.0/16 (1) 44162306a36Sopenharmony_ci * 192.168.0.0/24 (2) 44262306a36Sopenharmony_ci * 192.168.128.0/24 (3) 44362306a36Sopenharmony_ci * 192.168.1.0/24 (4) 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * (1) 44662306a36Sopenharmony_ci * / \ 44762306a36Sopenharmony_ci * (IM) (3) 44862306a36Sopenharmony_ci * / \ 44962306a36Sopenharmony_ci * (2) (4) 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_ci value = 1; 45262306a36Sopenharmony_ci key->prefixlen = 16; 45362306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key->data); 45462306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci value = 2; 45762306a36Sopenharmony_ci key->prefixlen = 24; 45862306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key->data); 45962306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci value = 3; 46262306a36Sopenharmony_ci key->prefixlen = 24; 46362306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.0", key->data); 46462306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci value = 4; 46762306a36Sopenharmony_ci key->prefixlen = 24; 46862306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.0", key->data); 46962306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* remove non-existent node */ 47262306a36Sopenharmony_ci key->prefixlen = 32; 47362306a36Sopenharmony_ci inet_pton(AF_INET, "10.0.0.1", key->data); 47462306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, key, &value) == -ENOENT); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci key->prefixlen = 30; // unused prefix so far 47762306a36Sopenharmony_ci inet_pton(AF_INET, "192.255.0.0", key->data); 47862306a36Sopenharmony_ci assert(bpf_map_delete_elem(map_fd, key) == -ENOENT); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci key->prefixlen = 16; // same prefix as the root node 48162306a36Sopenharmony_ci inet_pton(AF_INET, "192.255.0.0", key->data); 48262306a36Sopenharmony_ci assert(bpf_map_delete_elem(map_fd, key) == -ENOENT); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* assert initial lookup */ 48562306a36Sopenharmony_ci key->prefixlen = 32; 48662306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.1", key->data); 48762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); 48862306a36Sopenharmony_ci assert(value == 2); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* remove leaf node */ 49162306a36Sopenharmony_ci key->prefixlen = 24; 49262306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key->data); 49362306a36Sopenharmony_ci assert(bpf_map_delete_elem(map_fd, key) == 0); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci key->prefixlen = 32; 49662306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.1", key->data); 49762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); 49862306a36Sopenharmony_ci assert(value == 1); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* remove leaf (and intermediary) node */ 50162306a36Sopenharmony_ci key->prefixlen = 24; 50262306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.0", key->data); 50362306a36Sopenharmony_ci assert(bpf_map_delete_elem(map_fd, key) == 0); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci key->prefixlen = 32; 50662306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.1", key->data); 50762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); 50862306a36Sopenharmony_ci assert(value == 1); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* remove root node */ 51162306a36Sopenharmony_ci key->prefixlen = 16; 51262306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key->data); 51362306a36Sopenharmony_ci assert(bpf_map_delete_elem(map_fd, key) == 0); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci key->prefixlen = 32; 51662306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.1", key->data); 51762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); 51862306a36Sopenharmony_ci assert(value == 3); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* remove last node */ 52162306a36Sopenharmony_ci key->prefixlen = 24; 52262306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.0", key->data); 52362306a36Sopenharmony_ci assert(bpf_map_delete_elem(map_fd, key) == 0); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci key->prefixlen = 32; 52662306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.1", key->data); 52762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, key, &value) == -ENOENT); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci close(map_fd); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic void test_lpm_get_next_key(void) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); 53562306a36Sopenharmony_ci struct bpf_lpm_trie_key *key_p, *next_key_p; 53662306a36Sopenharmony_ci size_t key_size; 53762306a36Sopenharmony_ci __u32 value = 0; 53862306a36Sopenharmony_ci int map_fd; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci key_size = sizeof(*key_p) + sizeof(__u32); 54162306a36Sopenharmony_ci key_p = alloca(key_size); 54262306a36Sopenharmony_ci next_key_p = alloca(key_size); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci map_fd = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, key_size, sizeof(value), 100, &opts); 54562306a36Sopenharmony_ci assert(map_fd >= 0); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* empty tree. get_next_key should return ENOENT */ 54862306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == -ENOENT); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* get and verify the first key, get the second one should fail. */ 55162306a36Sopenharmony_ci key_p->prefixlen = 16; 55262306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key_p->data); 55362306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci memset(key_p, 0, key_size); 55662306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0); 55762306a36Sopenharmony_ci assert(key_p->prefixlen == 16 && key_p->data[0] == 192 && 55862306a36Sopenharmony_ci key_p->data[1] == 168); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -ENOENT); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* no exact matching key should get the first one in post order. */ 56362306a36Sopenharmony_ci key_p->prefixlen = 8; 56462306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0); 56562306a36Sopenharmony_ci assert(key_p->prefixlen == 16 && key_p->data[0] == 192 && 56662306a36Sopenharmony_ci key_p->data[1] == 168); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* add one more element (total two) */ 56962306a36Sopenharmony_ci key_p->prefixlen = 24; 57062306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.0", key_p->data); 57162306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci memset(key_p, 0, key_size); 57462306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0); 57562306a36Sopenharmony_ci assert(key_p->prefixlen == 24 && key_p->data[0] == 192 && 57662306a36Sopenharmony_ci key_p->data[1] == 168 && key_p->data[2] == 128); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci memset(next_key_p, 0, key_size); 57962306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 58062306a36Sopenharmony_ci assert(next_key_p->prefixlen == 16 && next_key_p->data[0] == 192 && 58162306a36Sopenharmony_ci next_key_p->data[1] == 168); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 58462306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -ENOENT); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Add one more element (total three) */ 58762306a36Sopenharmony_ci key_p->prefixlen = 24; 58862306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", key_p->data); 58962306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci memset(key_p, 0, key_size); 59262306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0); 59362306a36Sopenharmony_ci assert(key_p->prefixlen == 24 && key_p->data[0] == 192 && 59462306a36Sopenharmony_ci key_p->data[1] == 168 && key_p->data[2] == 0); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci memset(next_key_p, 0, key_size); 59762306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 59862306a36Sopenharmony_ci assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 && 59962306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 128); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 60262306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 60362306a36Sopenharmony_ci assert(next_key_p->prefixlen == 16 && next_key_p->data[0] == 192 && 60462306a36Sopenharmony_ci next_key_p->data[1] == 168); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 60762306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -ENOENT); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Add one more element (total four) */ 61062306a36Sopenharmony_ci key_p->prefixlen = 24; 61162306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.0", key_p->data); 61262306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci memset(key_p, 0, key_size); 61562306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0); 61662306a36Sopenharmony_ci assert(key_p->prefixlen == 24 && key_p->data[0] == 192 && 61762306a36Sopenharmony_ci key_p->data[1] == 168 && key_p->data[2] == 0); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci memset(next_key_p, 0, key_size); 62062306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 62162306a36Sopenharmony_ci assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 && 62262306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 1); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 62562306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 62662306a36Sopenharmony_ci assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 && 62762306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 128); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 63062306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 63162306a36Sopenharmony_ci assert(next_key_p->prefixlen == 16 && next_key_p->data[0] == 192 && 63262306a36Sopenharmony_ci next_key_p->data[1] == 168); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 63562306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -ENOENT); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Add one more element (total five) */ 63862306a36Sopenharmony_ci key_p->prefixlen = 28; 63962306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.128", key_p->data); 64062306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci memset(key_p, 0, key_size); 64362306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0); 64462306a36Sopenharmony_ci assert(key_p->prefixlen == 24 && key_p->data[0] == 192 && 64562306a36Sopenharmony_ci key_p->data[1] == 168 && key_p->data[2] == 0); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci memset(next_key_p, 0, key_size); 64862306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 64962306a36Sopenharmony_ci assert(next_key_p->prefixlen == 28 && next_key_p->data[0] == 192 && 65062306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 1 && 65162306a36Sopenharmony_ci next_key_p->data[3] == 128); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 65462306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 65562306a36Sopenharmony_ci assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 && 65662306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 1); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 65962306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 66062306a36Sopenharmony_ci assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 && 66162306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 128); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 66462306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 66562306a36Sopenharmony_ci assert(next_key_p->prefixlen == 16 && next_key_p->data[0] == 192 && 66662306a36Sopenharmony_ci next_key_p->data[1] == 168); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci memcpy(key_p, next_key_p, key_size); 66962306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -ENOENT); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* no exact matching key should return the first one in post order */ 67262306a36Sopenharmony_ci key_p->prefixlen = 22; 67362306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.0", key_p->data); 67462306a36Sopenharmony_ci assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0); 67562306a36Sopenharmony_ci assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 && 67662306a36Sopenharmony_ci next_key_p->data[1] == 168 && next_key_p->data[2] == 0); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci close(map_fd); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci#define MAX_TEST_KEYS 4 68262306a36Sopenharmony_cistruct lpm_mt_test_info { 68362306a36Sopenharmony_ci int cmd; /* 0: update, 1: delete, 2: lookup, 3: get_next_key */ 68462306a36Sopenharmony_ci int iter; 68562306a36Sopenharmony_ci int map_fd; 68662306a36Sopenharmony_ci struct { 68762306a36Sopenharmony_ci __u32 prefixlen; 68862306a36Sopenharmony_ci __u32 data; 68962306a36Sopenharmony_ci } key[MAX_TEST_KEYS]; 69062306a36Sopenharmony_ci}; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void *lpm_test_command(void *arg) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci int i, j, ret, iter, key_size; 69562306a36Sopenharmony_ci struct lpm_mt_test_info *info = arg; 69662306a36Sopenharmony_ci struct bpf_lpm_trie_key *key_p; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci key_size = sizeof(struct bpf_lpm_trie_key) + sizeof(__u32); 69962306a36Sopenharmony_ci key_p = alloca(key_size); 70062306a36Sopenharmony_ci for (iter = 0; iter < info->iter; iter++) 70162306a36Sopenharmony_ci for (i = 0; i < MAX_TEST_KEYS; i++) { 70262306a36Sopenharmony_ci /* first half of iterations in forward order, 70362306a36Sopenharmony_ci * and second half in backward order. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci j = (iter < (info->iter / 2)) ? i : MAX_TEST_KEYS - i - 1; 70662306a36Sopenharmony_ci key_p->prefixlen = info->key[j].prefixlen; 70762306a36Sopenharmony_ci memcpy(key_p->data, &info->key[j].data, sizeof(__u32)); 70862306a36Sopenharmony_ci if (info->cmd == 0) { 70962306a36Sopenharmony_ci __u32 value = j; 71062306a36Sopenharmony_ci /* update must succeed */ 71162306a36Sopenharmony_ci assert(bpf_map_update_elem(info->map_fd, key_p, &value, 0) == 0); 71262306a36Sopenharmony_ci } else if (info->cmd == 1) { 71362306a36Sopenharmony_ci ret = bpf_map_delete_elem(info->map_fd, key_p); 71462306a36Sopenharmony_ci assert(ret == 0 || errno == ENOENT); 71562306a36Sopenharmony_ci } else if (info->cmd == 2) { 71662306a36Sopenharmony_ci __u32 value; 71762306a36Sopenharmony_ci ret = bpf_map_lookup_elem(info->map_fd, key_p, &value); 71862306a36Sopenharmony_ci assert(ret == 0 || errno == ENOENT); 71962306a36Sopenharmony_ci } else { 72062306a36Sopenharmony_ci struct bpf_lpm_trie_key *next_key_p = alloca(key_size); 72162306a36Sopenharmony_ci ret = bpf_map_get_next_key(info->map_fd, key_p, next_key_p); 72262306a36Sopenharmony_ci assert(ret == 0 || errno == ENOENT || errno == ENOMEM); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci // Pass successful exit info back to the main thread 72762306a36Sopenharmony_ci pthread_exit((void *)info); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic void setup_lpm_mt_test_info(struct lpm_mt_test_info *info, int map_fd) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci info->iter = 2000; 73362306a36Sopenharmony_ci info->map_fd = map_fd; 73462306a36Sopenharmony_ci info->key[0].prefixlen = 16; 73562306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", &info->key[0].data); 73662306a36Sopenharmony_ci info->key[1].prefixlen = 24; 73762306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.0.0", &info->key[1].data); 73862306a36Sopenharmony_ci info->key[2].prefixlen = 24; 73962306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.128.0", &info->key[2].data); 74062306a36Sopenharmony_ci info->key[3].prefixlen = 24; 74162306a36Sopenharmony_ci inet_pton(AF_INET, "192.168.1.0", &info->key[3].data); 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic void test_lpm_multi_thread(void) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); 74762306a36Sopenharmony_ci struct lpm_mt_test_info info[4]; 74862306a36Sopenharmony_ci size_t key_size, value_size; 74962306a36Sopenharmony_ci pthread_t thread_id[4]; 75062306a36Sopenharmony_ci int i, map_fd; 75162306a36Sopenharmony_ci void *ret; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* create a trie */ 75462306a36Sopenharmony_ci value_size = sizeof(__u32); 75562306a36Sopenharmony_ci key_size = sizeof(struct bpf_lpm_trie_key) + value_size; 75662306a36Sopenharmony_ci map_fd = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, key_size, value_size, 100, &opts); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* create 4 threads to test update, delete, lookup and get_next_key */ 75962306a36Sopenharmony_ci setup_lpm_mt_test_info(&info[0], map_fd); 76062306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 76162306a36Sopenharmony_ci if (i != 0) 76262306a36Sopenharmony_ci memcpy(&info[i], &info[0], sizeof(info[i])); 76362306a36Sopenharmony_ci info[i].cmd = i; 76462306a36Sopenharmony_ci assert(pthread_create(&thread_id[i], NULL, &lpm_test_command, &info[i]) == 0); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 76862306a36Sopenharmony_ci assert(pthread_join(thread_id[i], &ret) == 0 && ret == (void *)&info[i]); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci close(map_fd); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ciint main(void) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci int i; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* we want predictable, pseudo random tests */ 77862306a36Sopenharmony_ci srand(0xf00ba1); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* Use libbpf 1.0 API mode */ 78162306a36Sopenharmony_ci libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci test_lpm_basic(); 78462306a36Sopenharmony_ci test_lpm_order(); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* Test with 8, 16, 24, 32, ... 128 bit prefix length */ 78762306a36Sopenharmony_ci for (i = 1; i <= 16; ++i) 78862306a36Sopenharmony_ci test_lpm_map(i); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci test_lpm_ipaddr(); 79162306a36Sopenharmony_ci test_lpm_delete(); 79262306a36Sopenharmony_ci test_lpm_get_next_key(); 79362306a36Sopenharmony_ci test_lpm_multi_thread(); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci printf("test_lpm: OK\n"); 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_ci} 798