162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Testsuite for eBPF maps 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014 PLUMgrid, http://plumgrid.com 662306a36Sopenharmony_ci * Copyright (c) 2016 Facebook 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <errno.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <assert.h> 1462306a36Sopenharmony_ci#include <stdlib.h> 1562306a36Sopenharmony_ci#include <time.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <sys/wait.h> 1862306a36Sopenharmony_ci#include <sys/socket.h> 1962306a36Sopenharmony_ci#include <netinet/in.h> 2062306a36Sopenharmony_ci#include <linux/bpf.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <bpf/bpf.h> 2362306a36Sopenharmony_ci#include <bpf/libbpf.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "bpf_util.h" 2662306a36Sopenharmony_ci#include "test_maps.h" 2762306a36Sopenharmony_ci#include "testing_helpers.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#ifndef ENOTSUPP 3062306a36Sopenharmony_ci#define ENOTSUPP 524 3162306a36Sopenharmony_ci#endif 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciint skips; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic struct bpf_map_create_opts map_opts = { .sz = sizeof(map_opts) }; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void test_hashmap(unsigned int task, void *data) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci long long key, next_key, first_key, value; 4062306a36Sopenharmony_ci int fd; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 2, &map_opts); 4362306a36Sopenharmony_ci if (fd < 0) { 4462306a36Sopenharmony_ci printf("Failed to create hashmap '%s'!\n", strerror(errno)); 4562306a36Sopenharmony_ci exit(1); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci key = 1; 4962306a36Sopenharmony_ci value = 1234; 5062306a36Sopenharmony_ci /* Insert key=1 element. */ 5162306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci value = 0; 5462306a36Sopenharmony_ci /* BPF_NOEXIST means add new element if it doesn't exist. */ 5562306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 && 5662306a36Sopenharmony_ci /* key=1 already exists. */ 5762306a36Sopenharmony_ci errno == EEXIST); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* -1 is an invalid flag. */ 6062306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, -1) < 0 && 6162306a36Sopenharmony_ci errno == EINVAL); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Check that key=1 can be found. */ 6462306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci key = 2; 6762306a36Sopenharmony_ci value = 1234; 6862306a36Sopenharmony_ci /* Insert key=2 element. */ 6962306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Check that key=2 matches the value and delete it */ 7262306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, &key, &value) == 0 && value == 1234); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Check that key=2 is not found. */ 7562306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* BPF_EXIST means update existing element. */ 7862306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) < 0 && 7962306a36Sopenharmony_ci /* key=2 is not there. */ 8062306a36Sopenharmony_ci errno == ENOENT); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Insert key=2 element. */ 8362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* key=1 and key=2 were inserted, check that key=0 cannot be 8662306a36Sopenharmony_ci * inserted due to max_entries limit. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci key = 0; 8962306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 && 9062306a36Sopenharmony_ci errno == E2BIG); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Update existing element, though the map is full. */ 9362306a36Sopenharmony_ci key = 1; 9462306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0); 9562306a36Sopenharmony_ci key = 2; 9662306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); 9762306a36Sopenharmony_ci key = 3; 9862306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 && 9962306a36Sopenharmony_ci errno == E2BIG); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Check that key = 0 doesn't exist. */ 10262306a36Sopenharmony_ci key = 0; 10362306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Iterate over two elements. */ 10662306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 && 10762306a36Sopenharmony_ci (first_key == 1 || first_key == 2)); 10862306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && 10962306a36Sopenharmony_ci (next_key == first_key)); 11062306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && 11162306a36Sopenharmony_ci (next_key == 1 || next_key == 2) && 11262306a36Sopenharmony_ci (next_key != first_key)); 11362306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 && 11462306a36Sopenharmony_ci errno == ENOENT); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Delete both elements. */ 11762306a36Sopenharmony_ci key = 1; 11862306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) == 0); 11962306a36Sopenharmony_ci key = 2; 12062306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) == 0); 12162306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci key = 0; 12462306a36Sopenharmony_ci /* Check that map is empty. */ 12562306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &next_key) < 0 && 12662306a36Sopenharmony_ci errno == ENOENT); 12762306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &next_key) < 0 && 12862306a36Sopenharmony_ci errno == ENOENT); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci close(fd); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void test_hashmap_sizes(unsigned int task, void *data) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci int fd, i, j; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci for (i = 1; i <= 512; i <<= 1) 13862306a36Sopenharmony_ci for (j = 1; j <= 1 << 18; j <<= 1) { 13962306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, i, j, 2, &map_opts); 14062306a36Sopenharmony_ci if (fd < 0) { 14162306a36Sopenharmony_ci if (errno == ENOMEM) 14262306a36Sopenharmony_ci return; 14362306a36Sopenharmony_ci printf("Failed to create hashmap key=%d value=%d '%s'\n", 14462306a36Sopenharmony_ci i, j, strerror(errno)); 14562306a36Sopenharmony_ci exit(1); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci close(fd); 14862306a36Sopenharmony_ci usleep(10); /* give kernel time to destroy */ 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void test_hashmap_percpu(unsigned int task, void *data) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci unsigned int nr_cpus = bpf_num_possible_cpus(); 15562306a36Sopenharmony_ci BPF_DECLARE_PERCPU(long, value); 15662306a36Sopenharmony_ci long long key, next_key, first_key; 15762306a36Sopenharmony_ci int expected_key_mask = 0; 15862306a36Sopenharmony_ci int fd, i; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_HASH, NULL, sizeof(key), 16162306a36Sopenharmony_ci sizeof(bpf_percpu(value, 0)), 2, &map_opts); 16262306a36Sopenharmony_ci if (fd < 0) { 16362306a36Sopenharmony_ci printf("Failed to create hashmap '%s'!\n", strerror(errno)); 16462306a36Sopenharmony_ci exit(1); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 16862306a36Sopenharmony_ci bpf_percpu(value, i) = i + 100; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci key = 1; 17162306a36Sopenharmony_ci /* Insert key=1 element. */ 17262306a36Sopenharmony_ci assert(!(expected_key_mask & key)); 17362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_ANY) == 0); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Lookup and delete elem key=1 and check value. */ 17662306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, &key, value) == 0 && 17762306a36Sopenharmony_ci bpf_percpu(value,0) == 100); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 18062306a36Sopenharmony_ci bpf_percpu(value,i) = i + 100; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Insert key=1 element which should not exist. */ 18362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0); 18462306a36Sopenharmony_ci expected_key_mask |= key; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* BPF_NOEXIST means add new element if it doesn't exist. */ 18762306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) < 0 && 18862306a36Sopenharmony_ci /* key=1 already exists. */ 18962306a36Sopenharmony_ci errno == EEXIST); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* -1 is an invalid flag. */ 19262306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, -1) < 0 && 19362306a36Sopenharmony_ci errno == EINVAL); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Check that key=1 can be found. Value could be 0 if the lookup 19662306a36Sopenharmony_ci * was run from a different CPU. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci bpf_percpu(value, 0) = 1; 19962306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, value) == 0 && 20062306a36Sopenharmony_ci bpf_percpu(value, 0) == 100); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci key = 2; 20362306a36Sopenharmony_ci /* Check that key=2 is not found. */ 20462306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, value) < 0 && errno == ENOENT); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* BPF_EXIST means update existing element. */ 20762306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) < 0 && 20862306a36Sopenharmony_ci /* key=2 is not there. */ 20962306a36Sopenharmony_ci errno == ENOENT); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Insert key=2 element. */ 21262306a36Sopenharmony_ci assert(!(expected_key_mask & key)); 21362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0); 21462306a36Sopenharmony_ci expected_key_mask |= key; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* key=1 and key=2 were inserted, check that key=0 cannot be 21762306a36Sopenharmony_ci * inserted due to max_entries limit. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci key = 0; 22062306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) < 0 && 22162306a36Sopenharmony_ci errno == E2BIG); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Check that key = 0 doesn't exist. */ 22462306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Iterate over two elements. */ 22762306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 && 22862306a36Sopenharmony_ci ((expected_key_mask & first_key) == first_key)); 22962306a36Sopenharmony_ci while (!bpf_map_get_next_key(fd, &key, &next_key)) { 23062306a36Sopenharmony_ci if (first_key) { 23162306a36Sopenharmony_ci assert(next_key == first_key); 23262306a36Sopenharmony_ci first_key = 0; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci assert((expected_key_mask & next_key) == next_key); 23562306a36Sopenharmony_ci expected_key_mask &= ~next_key; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &next_key, value) == 0); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 24062306a36Sopenharmony_ci assert(bpf_percpu(value, i) == i + 100); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci key = next_key; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci assert(errno == ENOENT); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Update with BPF_EXIST. */ 24762306a36Sopenharmony_ci key = 1; 24862306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Delete both elements. */ 25162306a36Sopenharmony_ci key = 1; 25262306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) == 0); 25362306a36Sopenharmony_ci key = 2; 25462306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) == 0); 25562306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci key = 0; 25862306a36Sopenharmony_ci /* Check that map is empty. */ 25962306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &next_key) < 0 && 26062306a36Sopenharmony_ci errno == ENOENT); 26162306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &next_key) < 0 && 26262306a36Sopenharmony_ci errno == ENOENT); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci close(fd); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci#define VALUE_SIZE 3 26862306a36Sopenharmony_cistatic int helper_fill_hashmap(int max_entries) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int i, fd, ret; 27162306a36Sopenharmony_ci long long key, value[VALUE_SIZE] = {}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 27462306a36Sopenharmony_ci max_entries, &map_opts); 27562306a36Sopenharmony_ci CHECK(fd < 0, 27662306a36Sopenharmony_ci "failed to create hashmap", 27762306a36Sopenharmony_ci "err: %s, flags: 0x%x\n", strerror(errno), map_opts.map_flags); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci for (i = 0; i < max_entries; i++) { 28062306a36Sopenharmony_ci key = i; value[0] = key; 28162306a36Sopenharmony_ci ret = bpf_map_update_elem(fd, &key, value, BPF_NOEXIST); 28262306a36Sopenharmony_ci CHECK(ret != 0, 28362306a36Sopenharmony_ci "can't update hashmap", 28462306a36Sopenharmony_ci "err: %s\n", strerror(ret)); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return fd; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void test_hashmap_walk(unsigned int task, void *data) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci int fd, i, max_entries = 10000; 29362306a36Sopenharmony_ci long long key, value[VALUE_SIZE], next_key; 29462306a36Sopenharmony_ci bool next_key_valid = true; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci fd = helper_fill_hashmap(max_entries); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key, 29962306a36Sopenharmony_ci &next_key) == 0; i++) { 30062306a36Sopenharmony_ci key = next_key; 30162306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, value) == 0); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci assert(i == max_entries); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &key) == 0); 30762306a36Sopenharmony_ci for (i = 0; next_key_valid; i++) { 30862306a36Sopenharmony_ci next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0; 30962306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, value) == 0); 31062306a36Sopenharmony_ci value[0]++; 31162306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0); 31262306a36Sopenharmony_ci key = next_key; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci assert(i == max_entries); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key, 31862306a36Sopenharmony_ci &next_key) == 0; i++) { 31962306a36Sopenharmony_ci key = next_key; 32062306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, value) == 0); 32162306a36Sopenharmony_ci assert(value[0] - 1 == key); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci assert(i == max_entries); 32562306a36Sopenharmony_ci close(fd); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void test_hashmap_zero_seed(void) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci int i, first, second, old_flags; 33162306a36Sopenharmony_ci long long key, next_first, next_second; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci old_flags = map_opts.map_flags; 33462306a36Sopenharmony_ci map_opts.map_flags |= BPF_F_ZERO_SEED; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci first = helper_fill_hashmap(3); 33762306a36Sopenharmony_ci second = helper_fill_hashmap(3); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci for (i = 0; ; i++) { 34062306a36Sopenharmony_ci void *key_ptr = !i ? NULL : &key; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (bpf_map_get_next_key(first, key_ptr, &next_first) != 0) 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci CHECK(bpf_map_get_next_key(second, key_ptr, &next_second) != 0, 34662306a36Sopenharmony_ci "next_key for second map must succeed", 34762306a36Sopenharmony_ci "key_ptr: %p", key_ptr); 34862306a36Sopenharmony_ci CHECK(next_first != next_second, 34962306a36Sopenharmony_ci "keys must match", 35062306a36Sopenharmony_ci "i: %d first: %lld second: %lld\n", i, 35162306a36Sopenharmony_ci next_first, next_second); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci key = next_first; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci map_opts.map_flags = old_flags; 35762306a36Sopenharmony_ci close(first); 35862306a36Sopenharmony_ci close(second); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void test_arraymap(unsigned int task, void *data) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci int key, next_key, fd; 36462306a36Sopenharmony_ci long long value; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(key), sizeof(value), 2, NULL); 36762306a36Sopenharmony_ci if (fd < 0) { 36862306a36Sopenharmony_ci printf("Failed to create arraymap '%s'!\n", strerror(errno)); 36962306a36Sopenharmony_ci exit(1); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci key = 1; 37362306a36Sopenharmony_ci value = 1234; 37462306a36Sopenharmony_ci /* Insert key=1 element. */ 37562306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci value = 0; 37862306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 && 37962306a36Sopenharmony_ci errno == EEXIST); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Check that key=1 can be found. */ 38262306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci key = 0; 38562306a36Sopenharmony_ci /* Check that key=0 is also found and zero initialized. */ 38662306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* key=0 and key=1 were inserted, check that key=2 cannot be inserted 38962306a36Sopenharmony_ci * due to max_entries limit. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci key = 2; 39262306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) < 0 && 39362306a36Sopenharmony_ci errno == E2BIG); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* Check that key = 2 doesn't exist. */ 39662306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Iterate over two elements. */ 39962306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 && 40062306a36Sopenharmony_ci next_key == 0); 40162306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && 40262306a36Sopenharmony_ci next_key == 0); 40362306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && 40462306a36Sopenharmony_ci next_key == 1); 40562306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 && 40662306a36Sopenharmony_ci errno == ENOENT); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* Delete shouldn't succeed. */ 40962306a36Sopenharmony_ci key = 1; 41062306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) < 0 && errno == EINVAL); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci close(fd); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void test_arraymap_percpu(unsigned int task, void *data) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci unsigned int nr_cpus = bpf_num_possible_cpus(); 41862306a36Sopenharmony_ci BPF_DECLARE_PERCPU(long, values); 41962306a36Sopenharmony_ci int key, next_key, fd, i; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, sizeof(key), 42262306a36Sopenharmony_ci sizeof(bpf_percpu(values, 0)), 2, NULL); 42362306a36Sopenharmony_ci if (fd < 0) { 42462306a36Sopenharmony_ci printf("Failed to create arraymap '%s'!\n", strerror(errno)); 42562306a36Sopenharmony_ci exit(1); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 42962306a36Sopenharmony_ci bpf_percpu(values, i) = i + 100; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci key = 1; 43262306a36Sopenharmony_ci /* Insert key=1 element. */ 43362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci bpf_percpu(values, 0) = 0; 43662306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) < 0 && 43762306a36Sopenharmony_ci errno == EEXIST); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Check that key=1 can be found. */ 44062306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, values) == 0 && 44162306a36Sopenharmony_ci bpf_percpu(values, 0) == 100); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci key = 0; 44462306a36Sopenharmony_ci /* Check that key=0 is also found and zero initialized. */ 44562306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, values) == 0 && 44662306a36Sopenharmony_ci bpf_percpu(values, 0) == 0 && 44762306a36Sopenharmony_ci bpf_percpu(values, nr_cpus - 1) == 0); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Check that key=2 cannot be inserted due to max_entries limit. */ 45062306a36Sopenharmony_ci key = 2; 45162306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, values, BPF_EXIST) < 0 && 45262306a36Sopenharmony_ci errno == E2BIG); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Check that key = 2 doesn't exist. */ 45562306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, values) < 0 && errno == ENOENT); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Iterate over two elements. */ 45862306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 && 45962306a36Sopenharmony_ci next_key == 0); 46062306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && 46162306a36Sopenharmony_ci next_key == 0); 46262306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && 46362306a36Sopenharmony_ci next_key == 1); 46462306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 && 46562306a36Sopenharmony_ci errno == ENOENT); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Delete shouldn't succeed. */ 46862306a36Sopenharmony_ci key = 1; 46962306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, &key) < 0 && errno == EINVAL); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci close(fd); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void test_arraymap_percpu_many_keys(void) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci unsigned int nr_cpus = bpf_num_possible_cpus(); 47762306a36Sopenharmony_ci BPF_DECLARE_PERCPU(long, values); 47862306a36Sopenharmony_ci /* nr_keys is not too large otherwise the test stresses percpu 47962306a36Sopenharmony_ci * allocator more than anything else 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci unsigned int nr_keys = 2000; 48262306a36Sopenharmony_ci int key, fd, i; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, sizeof(key), 48562306a36Sopenharmony_ci sizeof(bpf_percpu(values, 0)), nr_keys, NULL); 48662306a36Sopenharmony_ci if (fd < 0) { 48762306a36Sopenharmony_ci printf("Failed to create per-cpu arraymap '%s'!\n", 48862306a36Sopenharmony_ci strerror(errno)); 48962306a36Sopenharmony_ci exit(1); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 49362306a36Sopenharmony_ci bpf_percpu(values, i) = i + 10; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci for (key = 0; key < nr_keys; key++) 49662306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci for (key = 0; key < nr_keys; key++) { 49962306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 50062306a36Sopenharmony_ci bpf_percpu(values, i) = 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, values) == 0); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 50562306a36Sopenharmony_ci assert(bpf_percpu(values, i) == i + 10); 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci close(fd); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic void test_devmap(unsigned int task, void *data) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci int fd; 51462306a36Sopenharmony_ci __u32 key, value; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, NULL, sizeof(key), sizeof(value), 2, NULL); 51762306a36Sopenharmony_ci if (fd < 0) { 51862306a36Sopenharmony_ci printf("Failed to create devmap '%s'!\n", strerror(errno)); 51962306a36Sopenharmony_ci exit(1); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci close(fd); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void test_devmap_hash(unsigned int task, void *data) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci int fd; 52862306a36Sopenharmony_ci __u32 key, value; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP_HASH, NULL, sizeof(key), sizeof(value), 2, NULL); 53162306a36Sopenharmony_ci if (fd < 0) { 53262306a36Sopenharmony_ci printf("Failed to create devmap_hash '%s'!\n", strerror(errno)); 53362306a36Sopenharmony_ci exit(1); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci close(fd); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void test_queuemap(unsigned int task, void *data) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci const int MAP_SIZE = 32; 54262306a36Sopenharmony_ci __u32 vals[MAP_SIZE + MAP_SIZE/2], val; 54362306a36Sopenharmony_ci int fd, i; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* Fill test values to be used */ 54662306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++) 54762306a36Sopenharmony_ci vals[i] = rand(); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Invalid key size */ 55062306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 4, sizeof(val), MAP_SIZE, &map_opts); 55162306a36Sopenharmony_ci assert(fd < 0 && errno == EINVAL); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, sizeof(val), MAP_SIZE, &map_opts); 55462306a36Sopenharmony_ci /* Queue map does not support BPF_F_NO_PREALLOC */ 55562306a36Sopenharmony_ci if (map_opts.map_flags & BPF_F_NO_PREALLOC) { 55662306a36Sopenharmony_ci assert(fd < 0 && errno == EINVAL); 55762306a36Sopenharmony_ci return; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci if (fd < 0) { 56062306a36Sopenharmony_ci printf("Failed to create queuemap '%s'!\n", strerror(errno)); 56162306a36Sopenharmony_ci exit(1); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* Push MAP_SIZE elements */ 56562306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE; i++) 56662306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Check that element cannot be pushed due to max_entries limit */ 56962306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &val, 0) < 0 && 57062306a36Sopenharmony_ci errno == E2BIG); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Peek element */ 57362306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Replace half elements */ 57662306a36Sopenharmony_ci for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++) 57762306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* Pop all elements */ 58062306a36Sopenharmony_ci for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++) 58162306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 && 58262306a36Sopenharmony_ci val == vals[i]); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Check that there are not elements left */ 58562306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) < 0 && 58662306a36Sopenharmony_ci errno == ENOENT); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Check that non supported functions set errno to EINVAL */ 58962306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, NULL) < 0 && errno == EINVAL); 59062306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, NULL) < 0 && errno == EINVAL); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci close(fd); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void test_stackmap(unsigned int task, void *data) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci const int MAP_SIZE = 32; 59862306a36Sopenharmony_ci __u32 vals[MAP_SIZE + MAP_SIZE/2], val; 59962306a36Sopenharmony_ci int fd, i; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Fill test values to be used */ 60262306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++) 60362306a36Sopenharmony_ci vals[i] = rand(); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Invalid key size */ 60662306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 4, sizeof(val), MAP_SIZE, &map_opts); 60762306a36Sopenharmony_ci assert(fd < 0 && errno == EINVAL); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, sizeof(val), MAP_SIZE, &map_opts); 61062306a36Sopenharmony_ci /* Stack map does not support BPF_F_NO_PREALLOC */ 61162306a36Sopenharmony_ci if (map_opts.map_flags & BPF_F_NO_PREALLOC) { 61262306a36Sopenharmony_ci assert(fd < 0 && errno == EINVAL); 61362306a36Sopenharmony_ci return; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci if (fd < 0) { 61662306a36Sopenharmony_ci printf("Failed to create stackmap '%s'!\n", strerror(errno)); 61762306a36Sopenharmony_ci exit(1); 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Push MAP_SIZE elements */ 62162306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE; i++) 62262306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Check that element cannot be pushed due to max_entries limit */ 62562306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &val, 0) < 0 && 62662306a36Sopenharmony_ci errno == E2BIG); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Peek element */ 62962306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Replace half elements */ 63262306a36Sopenharmony_ci for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++) 63362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* Pop all elements */ 63662306a36Sopenharmony_ci for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--) 63762306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 && 63862306a36Sopenharmony_ci val == vals[i]); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Check that there are not elements left */ 64162306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) < 0 && 64262306a36Sopenharmony_ci errno == ENOENT); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Check that non supported functions set errno to EINVAL */ 64562306a36Sopenharmony_ci assert(bpf_map_delete_elem(fd, NULL) < 0 && errno == EINVAL); 64662306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, NULL) < 0 && errno == EINVAL); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci close(fd); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci#include <sys/ioctl.h> 65262306a36Sopenharmony_ci#include <arpa/inet.h> 65362306a36Sopenharmony_ci#include <sys/select.h> 65462306a36Sopenharmony_ci#include <linux/err.h> 65562306a36Sopenharmony_ci#define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.bpf.o" 65662306a36Sopenharmony_ci#define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.bpf.o" 65762306a36Sopenharmony_ci#define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.bpf.o" 65862306a36Sopenharmony_cistatic void test_sockmap(unsigned int tasks, void *data) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break; 66162306a36Sopenharmony_ci int map_fd_msg = 0, map_fd_rx = 0, map_fd_tx = 0, map_fd_break; 66262306a36Sopenharmony_ci struct bpf_object *parse_obj, *verdict_obj, *msg_obj; 66362306a36Sopenharmony_ci int ports[] = {50200, 50201, 50202, 50204}; 66462306a36Sopenharmony_ci int err, i, fd, udp, sfd[6] = {0xdeadbeef}; 66562306a36Sopenharmony_ci u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0}; 66662306a36Sopenharmony_ci int parse_prog, verdict_prog, msg_prog; 66762306a36Sopenharmony_ci struct sockaddr_in addr; 66862306a36Sopenharmony_ci int one = 1, s, sc, rc; 66962306a36Sopenharmony_ci struct timeval to; 67062306a36Sopenharmony_ci __u32 key, value; 67162306a36Sopenharmony_ci pid_t pid[tasks]; 67262306a36Sopenharmony_ci fd_set w; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* Create some sockets to use with sockmap */ 67562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 67662306a36Sopenharmony_ci sfd[i] = socket(AF_INET, SOCK_STREAM, 0); 67762306a36Sopenharmony_ci if (sfd[i] < 0) 67862306a36Sopenharmony_ci goto out; 67962306a36Sopenharmony_ci err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR, 68062306a36Sopenharmony_ci (char *)&one, sizeof(one)); 68162306a36Sopenharmony_ci if (err) { 68262306a36Sopenharmony_ci printf("failed to setsockopt\n"); 68362306a36Sopenharmony_ci goto out; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci err = ioctl(sfd[i], FIONBIO, (char *)&one); 68662306a36Sopenharmony_ci if (err < 0) { 68762306a36Sopenharmony_ci printf("failed to ioctl\n"); 68862306a36Sopenharmony_ci goto out; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci memset(&addr, 0, sizeof(struct sockaddr_in)); 69162306a36Sopenharmony_ci addr.sin_family = AF_INET; 69262306a36Sopenharmony_ci addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 69362306a36Sopenharmony_ci addr.sin_port = htons(ports[i]); 69462306a36Sopenharmony_ci err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr)); 69562306a36Sopenharmony_ci if (err < 0) { 69662306a36Sopenharmony_ci printf("failed to bind: err %i: %i:%i\n", 69762306a36Sopenharmony_ci err, i, sfd[i]); 69862306a36Sopenharmony_ci goto out; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci err = listen(sfd[i], 32); 70162306a36Sopenharmony_ci if (err < 0) { 70262306a36Sopenharmony_ci printf("failed to listen\n"); 70362306a36Sopenharmony_ci goto out; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci for (i = 2; i < 4; i++) { 70862306a36Sopenharmony_ci sfd[i] = socket(AF_INET, SOCK_STREAM, 0); 70962306a36Sopenharmony_ci if (sfd[i] < 0) 71062306a36Sopenharmony_ci goto out; 71162306a36Sopenharmony_ci err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR, 71262306a36Sopenharmony_ci (char *)&one, sizeof(one)); 71362306a36Sopenharmony_ci if (err) { 71462306a36Sopenharmony_ci printf("set sock opt\n"); 71562306a36Sopenharmony_ci goto out; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci memset(&addr, 0, sizeof(struct sockaddr_in)); 71862306a36Sopenharmony_ci addr.sin_family = AF_INET; 71962306a36Sopenharmony_ci addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 72062306a36Sopenharmony_ci addr.sin_port = htons(ports[i - 2]); 72162306a36Sopenharmony_ci err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr)); 72262306a36Sopenharmony_ci if (err) { 72362306a36Sopenharmony_ci printf("failed to connect\n"); 72462306a36Sopenharmony_ci goto out; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci for (i = 4; i < 6; i++) { 73062306a36Sopenharmony_ci sfd[i] = accept(sfd[i - 4], NULL, NULL); 73162306a36Sopenharmony_ci if (sfd[i] < 0) { 73262306a36Sopenharmony_ci printf("accept failed\n"); 73362306a36Sopenharmony_ci goto out; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* Test sockmap with connected sockets */ 73862306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL, 73962306a36Sopenharmony_ci sizeof(key), sizeof(value), 74062306a36Sopenharmony_ci 6, NULL); 74162306a36Sopenharmony_ci if (fd < 0) { 74262306a36Sopenharmony_ci if (!libbpf_probe_bpf_map_type(BPF_MAP_TYPE_SOCKMAP, NULL)) { 74362306a36Sopenharmony_ci printf("%s SKIP (unsupported map type BPF_MAP_TYPE_SOCKMAP)\n", 74462306a36Sopenharmony_ci __func__); 74562306a36Sopenharmony_ci skips++; 74662306a36Sopenharmony_ci for (i = 0; i < 6; i++) 74762306a36Sopenharmony_ci close(sfd[i]); 74862306a36Sopenharmony_ci return; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci printf("Failed to create sockmap %i\n", fd); 75262306a36Sopenharmony_ci goto out_sockmap; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* Test update with unsupported UDP socket */ 75662306a36Sopenharmony_ci udp = socket(AF_INET, SOCK_DGRAM, 0); 75762306a36Sopenharmony_ci i = 0; 75862306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &udp, BPF_ANY); 75962306a36Sopenharmony_ci if (err) { 76062306a36Sopenharmony_ci printf("Failed socket update SOCK_DGRAM '%i:%i'\n", 76162306a36Sopenharmony_ci i, udp); 76262306a36Sopenharmony_ci goto out_sockmap; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci close(udp); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Test update without programs */ 76762306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 76862306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); 76962306a36Sopenharmony_ci if (err) { 77062306a36Sopenharmony_ci printf("Failed noprog update sockmap '%i:%i'\n", 77162306a36Sopenharmony_ci i, sfd[i]); 77262306a36Sopenharmony_ci goto out_sockmap; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* Test attaching/detaching bad fds */ 77762306a36Sopenharmony_ci err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0); 77862306a36Sopenharmony_ci if (!err) { 77962306a36Sopenharmony_ci printf("Failed invalid parser prog attach\n"); 78062306a36Sopenharmony_ci goto out_sockmap; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_VERDICT, 0); 78462306a36Sopenharmony_ci if (!err) { 78562306a36Sopenharmony_ci printf("Failed invalid verdict prog attach\n"); 78662306a36Sopenharmony_ci goto out_sockmap; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci err = bpf_prog_attach(-1, fd, BPF_SK_MSG_VERDICT, 0); 79062306a36Sopenharmony_ci if (!err) { 79162306a36Sopenharmony_ci printf("Failed invalid msg verdict prog attach\n"); 79262306a36Sopenharmony_ci goto out_sockmap; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0); 79662306a36Sopenharmony_ci if (!err) { 79762306a36Sopenharmony_ci printf("Failed unknown prog attach\n"); 79862306a36Sopenharmony_ci goto out_sockmap; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER); 80262306a36Sopenharmony_ci if (!err) { 80362306a36Sopenharmony_ci printf("Failed empty parser prog detach\n"); 80462306a36Sopenharmony_ci goto out_sockmap; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT); 80862306a36Sopenharmony_ci if (!err) { 80962306a36Sopenharmony_ci printf("Failed empty verdict prog detach\n"); 81062306a36Sopenharmony_ci goto out_sockmap; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT); 81462306a36Sopenharmony_ci if (!err) { 81562306a36Sopenharmony_ci printf("Failed empty msg verdict prog detach\n"); 81662306a36Sopenharmony_ci goto out_sockmap; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE); 82062306a36Sopenharmony_ci if (!err) { 82162306a36Sopenharmony_ci printf("Detach invalid prog successful\n"); 82262306a36Sopenharmony_ci goto out_sockmap; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* Load SK_SKB program and Attach */ 82662306a36Sopenharmony_ci err = bpf_prog_test_load(SOCKMAP_PARSE_PROG, 82762306a36Sopenharmony_ci BPF_PROG_TYPE_SK_SKB, &parse_obj, &parse_prog); 82862306a36Sopenharmony_ci if (err) { 82962306a36Sopenharmony_ci printf("Failed to load SK_SKB parse prog\n"); 83062306a36Sopenharmony_ci goto out_sockmap; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci err = bpf_prog_test_load(SOCKMAP_TCP_MSG_PROG, 83462306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, &msg_obj, &msg_prog); 83562306a36Sopenharmony_ci if (err) { 83662306a36Sopenharmony_ci printf("Failed to load SK_SKB msg prog\n"); 83762306a36Sopenharmony_ci goto out_sockmap; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci err = bpf_prog_test_load(SOCKMAP_VERDICT_PROG, 84162306a36Sopenharmony_ci BPF_PROG_TYPE_SK_SKB, &verdict_obj, &verdict_prog); 84262306a36Sopenharmony_ci if (err) { 84362306a36Sopenharmony_ci printf("Failed to load SK_SKB verdict prog\n"); 84462306a36Sopenharmony_ci goto out_sockmap; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci bpf_map_rx = bpf_object__find_map_by_name(verdict_obj, "sock_map_rx"); 84862306a36Sopenharmony_ci if (!bpf_map_rx) { 84962306a36Sopenharmony_ci printf("Failed to load map rx from verdict prog\n"); 85062306a36Sopenharmony_ci goto out_sockmap; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci map_fd_rx = bpf_map__fd(bpf_map_rx); 85462306a36Sopenharmony_ci if (map_fd_rx < 0) { 85562306a36Sopenharmony_ci printf("Failed to get map rx fd\n"); 85662306a36Sopenharmony_ci goto out_sockmap; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci bpf_map_tx = bpf_object__find_map_by_name(verdict_obj, "sock_map_tx"); 86062306a36Sopenharmony_ci if (!bpf_map_tx) { 86162306a36Sopenharmony_ci printf("Failed to load map tx from verdict prog\n"); 86262306a36Sopenharmony_ci goto out_sockmap; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci map_fd_tx = bpf_map__fd(bpf_map_tx); 86662306a36Sopenharmony_ci if (map_fd_tx < 0) { 86762306a36Sopenharmony_ci printf("Failed to get map tx fd\n"); 86862306a36Sopenharmony_ci goto out_sockmap; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci bpf_map_msg = bpf_object__find_map_by_name(verdict_obj, "sock_map_msg"); 87262306a36Sopenharmony_ci if (!bpf_map_msg) { 87362306a36Sopenharmony_ci printf("Failed to load map msg from msg_verdict prog\n"); 87462306a36Sopenharmony_ci goto out_sockmap; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci map_fd_msg = bpf_map__fd(bpf_map_msg); 87862306a36Sopenharmony_ci if (map_fd_msg < 0) { 87962306a36Sopenharmony_ci printf("Failed to get map msg fd\n"); 88062306a36Sopenharmony_ci goto out_sockmap; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci bpf_map_break = bpf_object__find_map_by_name(verdict_obj, "sock_map_break"); 88462306a36Sopenharmony_ci if (!bpf_map_break) { 88562306a36Sopenharmony_ci printf("Failed to load map tx from verdict prog\n"); 88662306a36Sopenharmony_ci goto out_sockmap; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci map_fd_break = bpf_map__fd(bpf_map_break); 89062306a36Sopenharmony_ci if (map_fd_break < 0) { 89162306a36Sopenharmony_ci printf("Failed to get map tx fd\n"); 89262306a36Sopenharmony_ci goto out_sockmap; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci err = bpf_prog_attach(parse_prog, map_fd_break, 89662306a36Sopenharmony_ci BPF_SK_SKB_STREAM_PARSER, 0); 89762306a36Sopenharmony_ci if (!err) { 89862306a36Sopenharmony_ci printf("Allowed attaching SK_SKB program to invalid map\n"); 89962306a36Sopenharmony_ci goto out_sockmap; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci err = bpf_prog_attach(parse_prog, map_fd_rx, 90362306a36Sopenharmony_ci BPF_SK_SKB_STREAM_PARSER, 0); 90462306a36Sopenharmony_ci if (err) { 90562306a36Sopenharmony_ci printf("Failed stream parser bpf prog attach\n"); 90662306a36Sopenharmony_ci goto out_sockmap; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci err = bpf_prog_attach(verdict_prog, map_fd_rx, 91062306a36Sopenharmony_ci BPF_SK_SKB_STREAM_VERDICT, 0); 91162306a36Sopenharmony_ci if (err) { 91262306a36Sopenharmony_ci printf("Failed stream verdict bpf prog attach\n"); 91362306a36Sopenharmony_ci goto out_sockmap; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci err = bpf_prog_attach(msg_prog, map_fd_msg, BPF_SK_MSG_VERDICT, 0); 91762306a36Sopenharmony_ci if (err) { 91862306a36Sopenharmony_ci printf("Failed msg verdict bpf prog attach\n"); 91962306a36Sopenharmony_ci goto out_sockmap; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci err = bpf_prog_attach(verdict_prog, map_fd_rx, 92362306a36Sopenharmony_ci __MAX_BPF_ATTACH_TYPE, 0); 92462306a36Sopenharmony_ci if (!err) { 92562306a36Sopenharmony_ci printf("Attached unknown bpf prog\n"); 92662306a36Sopenharmony_ci goto out_sockmap; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* Test map update elem afterwards fd lives in fd and map_fd */ 93062306a36Sopenharmony_ci for (i = 2; i < 6; i++) { 93162306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY); 93262306a36Sopenharmony_ci if (err) { 93362306a36Sopenharmony_ci printf("Failed map_fd_rx update sockmap %i '%i:%i'\n", 93462306a36Sopenharmony_ci err, i, sfd[i]); 93562306a36Sopenharmony_ci goto out_sockmap; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd_tx, &i, &sfd[i], BPF_ANY); 93862306a36Sopenharmony_ci if (err) { 93962306a36Sopenharmony_ci printf("Failed map_fd_tx update sockmap %i '%i:%i'\n", 94062306a36Sopenharmony_ci err, i, sfd[i]); 94162306a36Sopenharmony_ci goto out_sockmap; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Test map delete elem and remove send/recv sockets */ 94662306a36Sopenharmony_ci for (i = 2; i < 4; i++) { 94762306a36Sopenharmony_ci err = bpf_map_delete_elem(map_fd_rx, &i); 94862306a36Sopenharmony_ci if (err) { 94962306a36Sopenharmony_ci printf("Failed delete sockmap rx %i '%i:%i'\n", 95062306a36Sopenharmony_ci err, i, sfd[i]); 95162306a36Sopenharmony_ci goto out_sockmap; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci err = bpf_map_delete_elem(map_fd_tx, &i); 95462306a36Sopenharmony_ci if (err) { 95562306a36Sopenharmony_ci printf("Failed delete sockmap tx %i '%i:%i'\n", 95662306a36Sopenharmony_ci err, i, sfd[i]); 95762306a36Sopenharmony_ci goto out_sockmap; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* Put sfd[2] (sending fd below) into msg map to test sendmsg bpf */ 96262306a36Sopenharmony_ci i = 0; 96362306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd_msg, &i, &sfd[2], BPF_ANY); 96462306a36Sopenharmony_ci if (err) { 96562306a36Sopenharmony_ci printf("Failed map_fd_msg update sockmap %i\n", err); 96662306a36Sopenharmony_ci goto out_sockmap; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* Test map send/recv */ 97062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 97162306a36Sopenharmony_ci buf[0] = i; 97262306a36Sopenharmony_ci buf[1] = 0x5; 97362306a36Sopenharmony_ci sc = send(sfd[2], buf, 20, 0); 97462306a36Sopenharmony_ci if (sc < 0) { 97562306a36Sopenharmony_ci printf("Failed sockmap send\n"); 97662306a36Sopenharmony_ci goto out_sockmap; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci FD_ZERO(&w); 98062306a36Sopenharmony_ci FD_SET(sfd[3], &w); 98162306a36Sopenharmony_ci to.tv_sec = 30; 98262306a36Sopenharmony_ci to.tv_usec = 0; 98362306a36Sopenharmony_ci s = select(sfd[3] + 1, &w, NULL, NULL, &to); 98462306a36Sopenharmony_ci if (s == -1) { 98562306a36Sopenharmony_ci perror("Failed sockmap select()"); 98662306a36Sopenharmony_ci goto out_sockmap; 98762306a36Sopenharmony_ci } else if (!s) { 98862306a36Sopenharmony_ci printf("Failed sockmap unexpected timeout\n"); 98962306a36Sopenharmony_ci goto out_sockmap; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (!FD_ISSET(sfd[3], &w)) { 99362306a36Sopenharmony_ci printf("Failed sockmap select/recv\n"); 99462306a36Sopenharmony_ci goto out_sockmap; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci rc = recv(sfd[3], buf, sizeof(buf), 0); 99862306a36Sopenharmony_ci if (rc < 0) { 99962306a36Sopenharmony_ci printf("Failed sockmap recv\n"); 100062306a36Sopenharmony_ci goto out_sockmap; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* Negative null entry lookup from datapath should be dropped */ 100562306a36Sopenharmony_ci buf[0] = 1; 100662306a36Sopenharmony_ci buf[1] = 12; 100762306a36Sopenharmony_ci sc = send(sfd[2], buf, 20, 0); 100862306a36Sopenharmony_ci if (sc < 0) { 100962306a36Sopenharmony_ci printf("Failed sockmap send\n"); 101062306a36Sopenharmony_ci goto out_sockmap; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* Push fd into same slot */ 101462306a36Sopenharmony_ci i = 2; 101562306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST); 101662306a36Sopenharmony_ci if (!err) { 101762306a36Sopenharmony_ci printf("Failed allowed sockmap dup slot BPF_NOEXIST\n"); 101862306a36Sopenharmony_ci goto out_sockmap; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); 102262306a36Sopenharmony_ci if (err) { 102362306a36Sopenharmony_ci printf("Failed sockmap update new slot BPF_ANY\n"); 102462306a36Sopenharmony_ci goto out_sockmap; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST); 102862306a36Sopenharmony_ci if (err) { 102962306a36Sopenharmony_ci printf("Failed sockmap update new slot BPF_EXIST\n"); 103062306a36Sopenharmony_ci goto out_sockmap; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* Delete the elems without programs */ 103462306a36Sopenharmony_ci for (i = 2; i < 6; i++) { 103562306a36Sopenharmony_ci err = bpf_map_delete_elem(fd, &i); 103662306a36Sopenharmony_ci if (err) { 103762306a36Sopenharmony_ci printf("Failed delete sockmap %i '%i:%i'\n", 103862306a36Sopenharmony_ci err, i, sfd[i]); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* Test having multiple maps open and set with programs on same fds */ 104362306a36Sopenharmony_ci err = bpf_prog_attach(parse_prog, fd, 104462306a36Sopenharmony_ci BPF_SK_SKB_STREAM_PARSER, 0); 104562306a36Sopenharmony_ci if (err) { 104662306a36Sopenharmony_ci printf("Failed fd bpf parse prog attach\n"); 104762306a36Sopenharmony_ci goto out_sockmap; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci err = bpf_prog_attach(verdict_prog, fd, 105062306a36Sopenharmony_ci BPF_SK_SKB_STREAM_VERDICT, 0); 105162306a36Sopenharmony_ci if (err) { 105262306a36Sopenharmony_ci printf("Failed fd bpf verdict prog attach\n"); 105362306a36Sopenharmony_ci goto out_sockmap; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci for (i = 4; i < 6; i++) { 105762306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); 105862306a36Sopenharmony_ci if (!err) { 105962306a36Sopenharmony_ci printf("Failed allowed duplicate programs in update ANY sockmap %i '%i:%i'\n", 106062306a36Sopenharmony_ci err, i, sfd[i]); 106162306a36Sopenharmony_ci goto out_sockmap; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST); 106462306a36Sopenharmony_ci if (!err) { 106562306a36Sopenharmony_ci printf("Failed allowed duplicate program in update NOEXIST sockmap %i '%i:%i'\n", 106662306a36Sopenharmony_ci err, i, sfd[i]); 106762306a36Sopenharmony_ci goto out_sockmap; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST); 107062306a36Sopenharmony_ci if (!err) { 107162306a36Sopenharmony_ci printf("Failed allowed duplicate program in update EXIST sockmap %i '%i:%i'\n", 107262306a36Sopenharmony_ci err, i, sfd[i]); 107362306a36Sopenharmony_ci goto out_sockmap; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* Test tasks number of forked operations */ 107862306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 107962306a36Sopenharmony_ci pid[i] = fork(); 108062306a36Sopenharmony_ci if (pid[i] == 0) { 108162306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 108262306a36Sopenharmony_ci bpf_map_delete_elem(map_fd_tx, &i); 108362306a36Sopenharmony_ci bpf_map_delete_elem(map_fd_rx, &i); 108462306a36Sopenharmony_ci bpf_map_update_elem(map_fd_tx, &i, 108562306a36Sopenharmony_ci &sfd[i], BPF_ANY); 108662306a36Sopenharmony_ci bpf_map_update_elem(map_fd_rx, &i, 108762306a36Sopenharmony_ci &sfd[i], BPF_ANY); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci exit(0); 109062306a36Sopenharmony_ci } else if (pid[i] == -1) { 109162306a36Sopenharmony_ci printf("Couldn't spawn #%d process!\n", i); 109262306a36Sopenharmony_ci exit(1); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 109762306a36Sopenharmony_ci int status; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci assert(waitpid(pid[i], &status, 0) == pid[i]); 110062306a36Sopenharmony_ci assert(status == 0); 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci err = bpf_prog_detach2(parse_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE); 110462306a36Sopenharmony_ci if (!err) { 110562306a36Sopenharmony_ci printf("Detached an invalid prog type.\n"); 110662306a36Sopenharmony_ci goto out_sockmap; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci err = bpf_prog_detach2(parse_prog, map_fd_rx, BPF_SK_SKB_STREAM_PARSER); 111062306a36Sopenharmony_ci if (err) { 111162306a36Sopenharmony_ci printf("Failed parser prog detach\n"); 111262306a36Sopenharmony_ci goto out_sockmap; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci err = bpf_prog_detach2(verdict_prog, map_fd_rx, BPF_SK_SKB_STREAM_VERDICT); 111662306a36Sopenharmony_ci if (err) { 111762306a36Sopenharmony_ci printf("Failed parser prog detach\n"); 111862306a36Sopenharmony_ci goto out_sockmap; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* Test map close sockets and empty maps */ 112262306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 112362306a36Sopenharmony_ci bpf_map_delete_elem(map_fd_tx, &i); 112462306a36Sopenharmony_ci bpf_map_delete_elem(map_fd_rx, &i); 112562306a36Sopenharmony_ci close(sfd[i]); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci close(fd); 112862306a36Sopenharmony_ci close(map_fd_rx); 112962306a36Sopenharmony_ci bpf_object__close(parse_obj); 113062306a36Sopenharmony_ci bpf_object__close(msg_obj); 113162306a36Sopenharmony_ci bpf_object__close(verdict_obj); 113262306a36Sopenharmony_ci return; 113362306a36Sopenharmony_ciout: 113462306a36Sopenharmony_ci for (i = 0; i < 6; i++) 113562306a36Sopenharmony_ci close(sfd[i]); 113662306a36Sopenharmony_ci printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno)); 113762306a36Sopenharmony_ci exit(1); 113862306a36Sopenharmony_ciout_sockmap: 113962306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 114062306a36Sopenharmony_ci if (map_fd_tx) 114162306a36Sopenharmony_ci bpf_map_delete_elem(map_fd_tx, &i); 114262306a36Sopenharmony_ci if (map_fd_rx) 114362306a36Sopenharmony_ci bpf_map_delete_elem(map_fd_rx, &i); 114462306a36Sopenharmony_ci close(sfd[i]); 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci close(fd); 114762306a36Sopenharmony_ci exit(1); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci#define MAPINMAP_PROG "./test_map_in_map.bpf.o" 115162306a36Sopenharmony_ci#define MAPINMAP_INVALID_PROG "./test_map_in_map_invalid.bpf.o" 115262306a36Sopenharmony_cistatic void test_map_in_map(void) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct bpf_object *obj; 115562306a36Sopenharmony_ci struct bpf_map *map; 115662306a36Sopenharmony_ci int mim_fd, fd, err; 115762306a36Sopenharmony_ci int pos = 0; 115862306a36Sopenharmony_ci struct bpf_map_info info = {}; 115962306a36Sopenharmony_ci __u32 len = sizeof(info); 116062306a36Sopenharmony_ci __u32 id = 0; 116162306a36Sopenharmony_ci libbpf_print_fn_t old_print_fn; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci obj = bpf_object__open(MAPINMAP_PROG); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(int), sizeof(int), 2, NULL); 116662306a36Sopenharmony_ci if (fd < 0) { 116762306a36Sopenharmony_ci printf("Failed to create hashmap '%s'!\n", strerror(errno)); 116862306a36Sopenharmony_ci exit(1); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci map = bpf_object__find_map_by_name(obj, "mim_array"); 117262306a36Sopenharmony_ci if (!map) { 117362306a36Sopenharmony_ci printf("Failed to load array of maps from test prog\n"); 117462306a36Sopenharmony_ci goto out_map_in_map; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci err = bpf_map__set_inner_map_fd(map, fd); 117762306a36Sopenharmony_ci if (err) { 117862306a36Sopenharmony_ci printf("Failed to set inner_map_fd for array of maps\n"); 117962306a36Sopenharmony_ci goto out_map_in_map; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci map = bpf_object__find_map_by_name(obj, "mim_hash"); 118362306a36Sopenharmony_ci if (!map) { 118462306a36Sopenharmony_ci printf("Failed to load hash of maps from test prog\n"); 118562306a36Sopenharmony_ci goto out_map_in_map; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci err = bpf_map__set_inner_map_fd(map, fd); 118862306a36Sopenharmony_ci if (err) { 118962306a36Sopenharmony_ci printf("Failed to set inner_map_fd for hash of maps\n"); 119062306a36Sopenharmony_ci goto out_map_in_map; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci err = bpf_object__load(obj); 119462306a36Sopenharmony_ci if (err) { 119562306a36Sopenharmony_ci printf("Failed to load test prog\n"); 119662306a36Sopenharmony_ci goto out_map_in_map; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci map = bpf_object__find_map_by_name(obj, "mim_array"); 120062306a36Sopenharmony_ci if (!map) { 120162306a36Sopenharmony_ci printf("Failed to load array of maps from test prog\n"); 120262306a36Sopenharmony_ci goto out_map_in_map; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci mim_fd = bpf_map__fd(map); 120562306a36Sopenharmony_ci if (mim_fd < 0) { 120662306a36Sopenharmony_ci printf("Failed to get descriptor for array of maps\n"); 120762306a36Sopenharmony_ci goto out_map_in_map; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci err = bpf_map_update_elem(mim_fd, &pos, &fd, 0); 121162306a36Sopenharmony_ci if (err) { 121262306a36Sopenharmony_ci printf("Failed to update array of maps\n"); 121362306a36Sopenharmony_ci goto out_map_in_map; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci map = bpf_object__find_map_by_name(obj, "mim_hash"); 121762306a36Sopenharmony_ci if (!map) { 121862306a36Sopenharmony_ci printf("Failed to load hash of maps from test prog\n"); 121962306a36Sopenharmony_ci goto out_map_in_map; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci mim_fd = bpf_map__fd(map); 122262306a36Sopenharmony_ci if (mim_fd < 0) { 122362306a36Sopenharmony_ci printf("Failed to get descriptor for hash of maps\n"); 122462306a36Sopenharmony_ci goto out_map_in_map; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci err = bpf_map_update_elem(mim_fd, &pos, &fd, 0); 122862306a36Sopenharmony_ci if (err) { 122962306a36Sopenharmony_ci printf("Failed to update hash of maps\n"); 123062306a36Sopenharmony_ci goto out_map_in_map; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci close(fd); 123462306a36Sopenharmony_ci fd = -1; 123562306a36Sopenharmony_ci bpf_object__close(obj); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* Test that failing bpf_object__create_map() destroys the inner map */ 123862306a36Sopenharmony_ci obj = bpf_object__open(MAPINMAP_INVALID_PROG); 123962306a36Sopenharmony_ci err = libbpf_get_error(obj); 124062306a36Sopenharmony_ci if (err) { 124162306a36Sopenharmony_ci printf("Failed to load %s program: %d %d", 124262306a36Sopenharmony_ci MAPINMAP_INVALID_PROG, err, errno); 124362306a36Sopenharmony_ci goto out_map_in_map; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci map = bpf_object__find_map_by_name(obj, "mim"); 124762306a36Sopenharmony_ci if (!map) { 124862306a36Sopenharmony_ci printf("Failed to load array of maps from test prog\n"); 124962306a36Sopenharmony_ci goto out_map_in_map; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci old_print_fn = libbpf_set_print(NULL); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci err = bpf_object__load(obj); 125562306a36Sopenharmony_ci if (!err) { 125662306a36Sopenharmony_ci printf("Loading obj supposed to fail\n"); 125762306a36Sopenharmony_ci goto out_map_in_map; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci libbpf_set_print(old_print_fn); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* Iterate over all maps to check whether the internal map 126362306a36Sopenharmony_ci * ("mim.internal") has been destroyed. 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_ci while (true) { 126662306a36Sopenharmony_ci err = bpf_map_get_next_id(id, &id); 126762306a36Sopenharmony_ci if (err) { 126862306a36Sopenharmony_ci if (errno == ENOENT) 126962306a36Sopenharmony_ci break; 127062306a36Sopenharmony_ci printf("Failed to get next map: %d", errno); 127162306a36Sopenharmony_ci goto out_map_in_map; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci fd = bpf_map_get_fd_by_id(id); 127562306a36Sopenharmony_ci if (fd < 0) { 127662306a36Sopenharmony_ci if (errno == ENOENT) 127762306a36Sopenharmony_ci continue; 127862306a36Sopenharmony_ci printf("Failed to get map by id %u: %d", id, errno); 127962306a36Sopenharmony_ci goto out_map_in_map; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci err = bpf_map_get_info_by_fd(fd, &info, &len); 128362306a36Sopenharmony_ci if (err) { 128462306a36Sopenharmony_ci printf("Failed to get map info by fd %d: %d", fd, 128562306a36Sopenharmony_ci errno); 128662306a36Sopenharmony_ci goto out_map_in_map; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (!strcmp(info.name, "mim.inner")) { 129062306a36Sopenharmony_ci printf("Inner map mim.inner was not destroyed\n"); 129162306a36Sopenharmony_ci goto out_map_in_map; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci close(fd); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci bpf_object__close(obj); 129862306a36Sopenharmony_ci return; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ciout_map_in_map: 130162306a36Sopenharmony_ci if (fd >= 0) 130262306a36Sopenharmony_ci close(fd); 130362306a36Sopenharmony_ci exit(1); 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci#define MAP_SIZE (32 * 1024) 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic void test_map_large(void) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci struct bigkey { 131262306a36Sopenharmony_ci int a; 131362306a36Sopenharmony_ci char b[4096]; 131462306a36Sopenharmony_ci long long c; 131562306a36Sopenharmony_ci } key; 131662306a36Sopenharmony_ci int fd, i, value; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 131962306a36Sopenharmony_ci MAP_SIZE, &map_opts); 132062306a36Sopenharmony_ci if (fd < 0) { 132162306a36Sopenharmony_ci printf("Failed to create large map '%s'!\n", strerror(errno)); 132262306a36Sopenharmony_ci exit(1); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE; i++) { 132662306a36Sopenharmony_ci key = (struct bigkey) { .c = i }; 132762306a36Sopenharmony_ci value = i; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0); 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci key.c = -1; 133362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 && 133462306a36Sopenharmony_ci errno == E2BIG); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* Iterate through all elements. */ 133762306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &key) == 0); 133862306a36Sopenharmony_ci key.c = -1; 133962306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE; i++) 134062306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &key) == 0); 134162306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci key.c = 0; 134462306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0); 134562306a36Sopenharmony_ci key.a = 1; 134662306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci close(fd); 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci#define run_parallel(N, FN, DATA) \ 135262306a36Sopenharmony_ci printf("Fork %u tasks to '" #FN "'\n", N); \ 135362306a36Sopenharmony_ci __run_parallel(N, FN, DATA) 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_cistatic void __run_parallel(unsigned int tasks, 135662306a36Sopenharmony_ci void (*fn)(unsigned int task, void *data), 135762306a36Sopenharmony_ci void *data) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci pid_t pid[tasks]; 136062306a36Sopenharmony_ci int i; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci fflush(stdout); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 136562306a36Sopenharmony_ci pid[i] = fork(); 136662306a36Sopenharmony_ci if (pid[i] == 0) { 136762306a36Sopenharmony_ci fn(i, data); 136862306a36Sopenharmony_ci exit(0); 136962306a36Sopenharmony_ci } else if (pid[i] == -1) { 137062306a36Sopenharmony_ci printf("Couldn't spawn #%d process!\n", i); 137162306a36Sopenharmony_ci exit(1); 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 137662306a36Sopenharmony_ci int status; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci assert(waitpid(pid[i], &status, 0) == pid[i]); 137962306a36Sopenharmony_ci assert(status == 0); 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic void test_map_stress(void) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci run_parallel(100, test_hashmap_walk, NULL); 138662306a36Sopenharmony_ci run_parallel(100, test_hashmap, NULL); 138762306a36Sopenharmony_ci run_parallel(100, test_hashmap_percpu, NULL); 138862306a36Sopenharmony_ci run_parallel(100, test_hashmap_sizes, NULL); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci run_parallel(100, test_arraymap, NULL); 139162306a36Sopenharmony_ci run_parallel(100, test_arraymap_percpu, NULL); 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci#define TASKS 100 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci#define DO_UPDATE 1 139762306a36Sopenharmony_ci#define DO_DELETE 0 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci#define MAP_RETRIES 20 140062306a36Sopenharmony_ci#define MAX_DELAY_US 50000 140162306a36Sopenharmony_ci#define MIN_DELAY_RANGE_US 5000 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic int map_update_retriable(int map_fd, const void *key, const void *value, 140462306a36Sopenharmony_ci int flags, int attempts) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci int delay = rand() % MIN_DELAY_RANGE_US; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci while (bpf_map_update_elem(map_fd, key, value, flags)) { 140962306a36Sopenharmony_ci if (!attempts || (errno != EAGAIN && errno != EBUSY)) 141062306a36Sopenharmony_ci return -errno; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (delay <= MAX_DELAY_US / 2) 141362306a36Sopenharmony_ci delay *= 2; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci usleep(delay); 141662306a36Sopenharmony_ci attempts--; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci return 0; 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cistatic int map_delete_retriable(int map_fd, const void *key, int attempts) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci int delay = rand() % MIN_DELAY_RANGE_US; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci while (bpf_map_delete_elem(map_fd, key)) { 142762306a36Sopenharmony_ci if (!attempts || (errno != EAGAIN && errno != EBUSY)) 142862306a36Sopenharmony_ci return -errno; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (delay <= MAX_DELAY_US / 2) 143162306a36Sopenharmony_ci delay *= 2; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci usleep(delay); 143462306a36Sopenharmony_ci attempts--; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci return 0; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_cistatic void test_update_delete(unsigned int fn, void *data) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci int do_update = ((int *)data)[1]; 144362306a36Sopenharmony_ci int fd = ((int *)data)[0]; 144462306a36Sopenharmony_ci int i, key, value, err; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if (fn & 1) 144762306a36Sopenharmony_ci test_hashmap_walk(fn, NULL); 144862306a36Sopenharmony_ci for (i = fn; i < MAP_SIZE; i += TASKS) { 144962306a36Sopenharmony_ci key = value = i; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (do_update) { 145262306a36Sopenharmony_ci err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES); 145362306a36Sopenharmony_ci if (err) 145462306a36Sopenharmony_ci printf("error %d %d\n", err, errno); 145562306a36Sopenharmony_ci assert(err == 0); 145662306a36Sopenharmony_ci err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES); 145762306a36Sopenharmony_ci if (err) 145862306a36Sopenharmony_ci printf("error %d %d\n", err, errno); 145962306a36Sopenharmony_ci assert(err == 0); 146062306a36Sopenharmony_ci } else { 146162306a36Sopenharmony_ci err = map_delete_retriable(fd, &key, MAP_RETRIES); 146262306a36Sopenharmony_ci if (err) 146362306a36Sopenharmony_ci printf("error %d %d\n", err, errno); 146462306a36Sopenharmony_ci assert(err == 0); 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cistatic void test_map_parallel(void) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci int i, fd, key = 0, value = 0, j = 0; 147262306a36Sopenharmony_ci int data[2]; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 147562306a36Sopenharmony_ci MAP_SIZE, &map_opts); 147662306a36Sopenharmony_ci if (fd < 0) { 147762306a36Sopenharmony_ci printf("Failed to create map for parallel test '%s'!\n", 147862306a36Sopenharmony_ci strerror(errno)); 147962306a36Sopenharmony_ci exit(1); 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ciagain: 148362306a36Sopenharmony_ci /* Use the same fd in children to add elements to this map: 148462306a36Sopenharmony_ci * child_0 adds key=0, key=1024, key=2048, ... 148562306a36Sopenharmony_ci * child_1 adds key=1, key=1025, key=2049, ... 148662306a36Sopenharmony_ci * child_1023 adds key=1023, ... 148762306a36Sopenharmony_ci */ 148862306a36Sopenharmony_ci data[0] = fd; 148962306a36Sopenharmony_ci data[1] = DO_UPDATE; 149062306a36Sopenharmony_ci run_parallel(TASKS, test_update_delete, data); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* Check that key=0 is already there. */ 149362306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 && 149462306a36Sopenharmony_ci errno == EEXIST); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Check that all elements were inserted. */ 149762306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &key) == 0); 149862306a36Sopenharmony_ci key = -1; 149962306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE; i++) 150062306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &key) == 0); 150162306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* Another check for all elements */ 150462306a36Sopenharmony_ci for (i = 0; i < MAP_SIZE; i++) { 150562306a36Sopenharmony_ci key = MAP_SIZE - i - 1; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && 150862306a36Sopenharmony_ci value == key); 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* Now let's delete all elemenets in parallel. */ 151262306a36Sopenharmony_ci data[1] = DO_DELETE; 151362306a36Sopenharmony_ci run_parallel(TASKS, test_update_delete, data); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* Nothing should be left. */ 151662306a36Sopenharmony_ci key = -1; 151762306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, NULL, &key) < 0 && errno == ENOENT); 151862306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci key = 0; 152162306a36Sopenharmony_ci bpf_map_delete_elem(fd, &key); 152262306a36Sopenharmony_ci if (j++ < 5) 152362306a36Sopenharmony_ci goto again; 152462306a36Sopenharmony_ci close(fd); 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic void test_map_rdonly(void) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci int fd, key = 0, value = 0; 153062306a36Sopenharmony_ci __u32 old_flags; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci old_flags = map_opts.map_flags; 153362306a36Sopenharmony_ci map_opts.map_flags |= BPF_F_RDONLY; 153462306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 153562306a36Sopenharmony_ci MAP_SIZE, &map_opts); 153662306a36Sopenharmony_ci map_opts.map_flags = old_flags; 153762306a36Sopenharmony_ci if (fd < 0) { 153862306a36Sopenharmony_ci printf("Failed to create map for read only test '%s'!\n", 153962306a36Sopenharmony_ci strerror(errno)); 154062306a36Sopenharmony_ci exit(1); 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci key = 1; 154462306a36Sopenharmony_ci value = 1234; 154562306a36Sopenharmony_ci /* Try to insert key=1 element. */ 154662306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) < 0 && 154762306a36Sopenharmony_ci errno == EPERM); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* Check that key=1 is not found. */ 155062306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT); 155162306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &value) < 0 && errno == ENOENT); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci close(fd); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic void test_map_wronly_hash(void) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci int fd, key = 0, value = 0; 155962306a36Sopenharmony_ci __u32 old_flags; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci old_flags = map_opts.map_flags; 156262306a36Sopenharmony_ci map_opts.map_flags |= BPF_F_WRONLY; 156362306a36Sopenharmony_ci fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 156462306a36Sopenharmony_ci MAP_SIZE, &map_opts); 156562306a36Sopenharmony_ci map_opts.map_flags = old_flags; 156662306a36Sopenharmony_ci if (fd < 0) { 156762306a36Sopenharmony_ci printf("Failed to create map for write only test '%s'!\n", 156862306a36Sopenharmony_ci strerror(errno)); 156962306a36Sopenharmony_ci exit(1); 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci key = 1; 157362306a36Sopenharmony_ci value = 1234; 157462306a36Sopenharmony_ci /* Insert key=1 element. */ 157562306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci /* Check that reading elements and keys from the map is not allowed. */ 157862306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == EPERM); 157962306a36Sopenharmony_ci assert(bpf_map_get_next_key(fd, &key, &value) < 0 && errno == EPERM); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci close(fd); 158262306a36Sopenharmony_ci} 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_cistatic void test_map_wronly_stack_or_queue(enum bpf_map_type map_type) 158562306a36Sopenharmony_ci{ 158662306a36Sopenharmony_ci int fd, value = 0; 158762306a36Sopenharmony_ci __u32 old_flags; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci assert(map_type == BPF_MAP_TYPE_QUEUE || 159162306a36Sopenharmony_ci map_type == BPF_MAP_TYPE_STACK); 159262306a36Sopenharmony_ci old_flags = map_opts.map_flags; 159362306a36Sopenharmony_ci map_opts.map_flags |= BPF_F_WRONLY; 159462306a36Sopenharmony_ci fd = bpf_map_create(map_type, NULL, 0, sizeof(value), MAP_SIZE, &map_opts); 159562306a36Sopenharmony_ci map_opts.map_flags = old_flags; 159662306a36Sopenharmony_ci /* Stack/Queue maps do not support BPF_F_NO_PREALLOC */ 159762306a36Sopenharmony_ci if (map_opts.map_flags & BPF_F_NO_PREALLOC) { 159862306a36Sopenharmony_ci assert(fd < 0 && errno == EINVAL); 159962306a36Sopenharmony_ci return; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci if (fd < 0) { 160262306a36Sopenharmony_ci printf("Failed to create map '%s'!\n", strerror(errno)); 160362306a36Sopenharmony_ci exit(1); 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci value = 1234; 160762306a36Sopenharmony_ci assert(bpf_map_update_elem(fd, NULL, &value, BPF_ANY) == 0); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci /* Peek element should fail */ 161062306a36Sopenharmony_ci assert(bpf_map_lookup_elem(fd, NULL, &value) < 0 && errno == EPERM); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* Pop element should fail */ 161362306a36Sopenharmony_ci assert(bpf_map_lookup_and_delete_elem(fd, NULL, &value) < 0 && 161462306a36Sopenharmony_ci errno == EPERM); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci close(fd); 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_cistatic void test_map_wronly(void) 162062306a36Sopenharmony_ci{ 162162306a36Sopenharmony_ci test_map_wronly_hash(); 162262306a36Sopenharmony_ci test_map_wronly_stack_or_queue(BPF_MAP_TYPE_STACK); 162362306a36Sopenharmony_ci test_map_wronly_stack_or_queue(BPF_MAP_TYPE_QUEUE); 162462306a36Sopenharmony_ci} 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_cistatic void prepare_reuseport_grp(int type, int map_fd, size_t map_elem_size, 162762306a36Sopenharmony_ci __s64 *fds64, __u64 *sk_cookies, 162862306a36Sopenharmony_ci unsigned int n) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci socklen_t optlen, addrlen; 163162306a36Sopenharmony_ci struct sockaddr_in6 s6; 163262306a36Sopenharmony_ci const __u32 index0 = 0; 163362306a36Sopenharmony_ci const int optval = 1; 163462306a36Sopenharmony_ci unsigned int i; 163562306a36Sopenharmony_ci u64 sk_cookie; 163662306a36Sopenharmony_ci void *value; 163762306a36Sopenharmony_ci __s32 fd32; 163862306a36Sopenharmony_ci __s64 fd64; 163962306a36Sopenharmony_ci int err; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci s6.sin6_family = AF_INET6; 164262306a36Sopenharmony_ci s6.sin6_addr = in6addr_any; 164362306a36Sopenharmony_ci s6.sin6_port = 0; 164462306a36Sopenharmony_ci addrlen = sizeof(s6); 164562306a36Sopenharmony_ci optlen = sizeof(sk_cookie); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci for (i = 0; i < n; i++) { 164862306a36Sopenharmony_ci fd64 = socket(AF_INET6, type, 0); 164962306a36Sopenharmony_ci CHECK(fd64 == -1, "socket()", 165062306a36Sopenharmony_ci "sock_type:%d fd64:%lld errno:%d\n", 165162306a36Sopenharmony_ci type, fd64, errno); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT, 165462306a36Sopenharmony_ci &optval, sizeof(optval)); 165562306a36Sopenharmony_ci CHECK(err == -1, "setsockopt(SO_REUSEPORT)", 165662306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* reuseport_array does not allow unbound sk */ 165962306a36Sopenharmony_ci if (map_elem_size == sizeof(__u64)) 166062306a36Sopenharmony_ci value = &fd64; 166162306a36Sopenharmony_ci else { 166262306a36Sopenharmony_ci assert(map_elem_size == sizeof(__u32)); 166362306a36Sopenharmony_ci fd32 = (__s32)fd64; 166462306a36Sopenharmony_ci value = &fd32; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index0, value, BPF_ANY); 166762306a36Sopenharmony_ci CHECK(err >= 0 || errno != EINVAL, 166862306a36Sopenharmony_ci "reuseport array update unbound sk", 166962306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 167062306a36Sopenharmony_ci type, err, errno); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6)); 167362306a36Sopenharmony_ci CHECK(err == -1, "bind()", 167462306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", type, err, errno); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci if (i == 0) { 167762306a36Sopenharmony_ci err = getsockname(fd64, (struct sockaddr *)&s6, 167862306a36Sopenharmony_ci &addrlen); 167962306a36Sopenharmony_ci CHECK(err == -1, "getsockname()", 168062306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 168162306a36Sopenharmony_ci type, err, errno); 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie, 168562306a36Sopenharmony_ci &optlen); 168662306a36Sopenharmony_ci CHECK(err == -1, "getsockopt(SO_COOKIE)", 168762306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", type, err, errno); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if (type == SOCK_STREAM) { 169062306a36Sopenharmony_ci /* 169162306a36Sopenharmony_ci * reuseport_array does not allow 169262306a36Sopenharmony_ci * non-listening tcp sk. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index0, value, 169562306a36Sopenharmony_ci BPF_ANY); 169662306a36Sopenharmony_ci CHECK(err >= 0 || errno != EINVAL, 169762306a36Sopenharmony_ci "reuseport array update non-listening sk", 169862306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 169962306a36Sopenharmony_ci type, err, errno); 170062306a36Sopenharmony_ci err = listen(fd64, 0); 170162306a36Sopenharmony_ci CHECK(err == -1, "listen()", 170262306a36Sopenharmony_ci "sock_type:%d, err:%d errno:%d\n", 170362306a36Sopenharmony_ci type, err, errno); 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci fds64[i] = fd64; 170762306a36Sopenharmony_ci sk_cookies[i] = sk_cookie; 170862306a36Sopenharmony_ci } 170962306a36Sopenharmony_ci} 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic void test_reuseport_array(void) 171262306a36Sopenharmony_ci{ 171362306a36Sopenharmony_ci#define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; }) 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci const __u32 array_size = 4, index0 = 0, index3 = 3; 171662306a36Sopenharmony_ci int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type; 171762306a36Sopenharmony_ci __u64 grpa_cookies[2], sk_cookie, map_cookie; 171862306a36Sopenharmony_ci __s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1; 171962306a36Sopenharmony_ci const __u32 bad_index = array_size; 172062306a36Sopenharmony_ci int map_fd, err, t, f; 172162306a36Sopenharmony_ci __u32 fds_idx = 0; 172262306a36Sopenharmony_ci int fd; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci map_fd = bpf_map_create(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, NULL, 172562306a36Sopenharmony_ci sizeof(__u32), sizeof(__u64), array_size, NULL); 172662306a36Sopenharmony_ci CHECK(map_fd < 0, "reuseport array create", 172762306a36Sopenharmony_ci "map_fd:%d, errno:%d\n", map_fd, errno); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci /* Test lookup/update/delete with invalid index */ 173062306a36Sopenharmony_ci err = bpf_map_delete_elem(map_fd, &bad_index); 173162306a36Sopenharmony_ci CHECK(err >= 0 || errno != E2BIG, "reuseport array del >=max_entries", 173262306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY); 173562306a36Sopenharmony_ci CHECK(err >= 0 || errno != E2BIG, 173662306a36Sopenharmony_ci "reuseport array update >=max_entries", 173762306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie); 174062306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOENT, 174162306a36Sopenharmony_ci "reuseport array update >=max_entries", 174262306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci /* Test lookup/delete non existence elem */ 174562306a36Sopenharmony_ci err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); 174662306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOENT, 174762306a36Sopenharmony_ci "reuseport array lookup not-exist elem", 174862306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 174962306a36Sopenharmony_ci err = bpf_map_delete_elem(map_fd, &index3); 175062306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOENT, 175162306a36Sopenharmony_ci "reuseport array del not-exist elem", 175262306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci for (t = 0; t < ARRAY_SIZE(types); t++) { 175562306a36Sopenharmony_ci type = types[t]; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci prepare_reuseport_grp(type, map_fd, sizeof(__u64), grpa_fds64, 175862306a36Sopenharmony_ci grpa_cookies, ARRAY_SIZE(grpa_fds64)); 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci /* Test BPF_* update flags */ 176162306a36Sopenharmony_ci /* BPF_EXIST failure case */ 176262306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], 176362306a36Sopenharmony_ci BPF_EXIST); 176462306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOENT, 176562306a36Sopenharmony_ci "reuseport array update empty elem BPF_EXIST", 176662306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 176762306a36Sopenharmony_ci type, err, errno); 176862306a36Sopenharmony_ci fds_idx = REUSEPORT_FD_IDX(err, fds_idx); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci /* BPF_NOEXIST success case */ 177162306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], 177262306a36Sopenharmony_ci BPF_NOEXIST); 177362306a36Sopenharmony_ci CHECK(err < 0, 177462306a36Sopenharmony_ci "reuseport array update empty elem BPF_NOEXIST", 177562306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 177662306a36Sopenharmony_ci type, err, errno); 177762306a36Sopenharmony_ci fds_idx = REUSEPORT_FD_IDX(err, fds_idx); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci /* BPF_EXIST success case. */ 178062306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], 178162306a36Sopenharmony_ci BPF_EXIST); 178262306a36Sopenharmony_ci CHECK(err < 0, 178362306a36Sopenharmony_ci "reuseport array update same elem BPF_EXIST", 178462306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", type, err, errno); 178562306a36Sopenharmony_ci fds_idx = REUSEPORT_FD_IDX(err, fds_idx); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci /* BPF_NOEXIST failure case */ 178862306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], 178962306a36Sopenharmony_ci BPF_NOEXIST); 179062306a36Sopenharmony_ci CHECK(err >= 0 || errno != EEXIST, 179162306a36Sopenharmony_ci "reuseport array update non-empty elem BPF_NOEXIST", 179262306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 179362306a36Sopenharmony_ci type, err, errno); 179462306a36Sopenharmony_ci fds_idx = REUSEPORT_FD_IDX(err, fds_idx); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci /* BPF_ANY case (always succeed) */ 179762306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], 179862306a36Sopenharmony_ci BPF_ANY); 179962306a36Sopenharmony_ci CHECK(err < 0, 180062306a36Sopenharmony_ci "reuseport array update same sk with BPF_ANY", 180162306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", type, err, errno); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci fd64 = grpa_fds64[fds_idx]; 180462306a36Sopenharmony_ci sk_cookie = grpa_cookies[fds_idx]; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci /* The same sk cannot be added to reuseport_array twice */ 180762306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY); 180862306a36Sopenharmony_ci CHECK(err >= 0 || errno != EBUSY, 180962306a36Sopenharmony_ci "reuseport array update same sk with same index", 181062306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 181162306a36Sopenharmony_ci type, err, errno); 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY); 181462306a36Sopenharmony_ci CHECK(err >= 0 || errno != EBUSY, 181562306a36Sopenharmony_ci "reuseport array update same sk with different index", 181662306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 181762306a36Sopenharmony_ci type, err, errno); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* Test delete elem */ 182062306a36Sopenharmony_ci err = bpf_map_delete_elem(map_fd, &index3); 182162306a36Sopenharmony_ci CHECK(err < 0, "reuseport array delete sk", 182262306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 182362306a36Sopenharmony_ci type, err, errno); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci /* Add it back with BPF_NOEXIST */ 182662306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST); 182762306a36Sopenharmony_ci CHECK(err < 0, 182862306a36Sopenharmony_ci "reuseport array re-add with BPF_NOEXIST after del", 182962306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", type, err, errno); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* Test cookie */ 183262306a36Sopenharmony_ci err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); 183362306a36Sopenharmony_ci CHECK(err < 0 || sk_cookie != map_cookie, 183462306a36Sopenharmony_ci "reuseport array lookup re-added sk", 183562306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn", 183662306a36Sopenharmony_ci type, err, errno, sk_cookie, map_cookie); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci /* Test elem removed by close() */ 183962306a36Sopenharmony_ci for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++) 184062306a36Sopenharmony_ci close(grpa_fds64[f]); 184162306a36Sopenharmony_ci err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); 184262306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOENT, 184362306a36Sopenharmony_ci "reuseport array lookup after close()", 184462306a36Sopenharmony_ci "sock_type:%d err:%d errno:%d\n", 184562306a36Sopenharmony_ci type, err, errno); 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* Test SOCK_RAW */ 184962306a36Sopenharmony_ci fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP); 185062306a36Sopenharmony_ci CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n", 185162306a36Sopenharmony_ci err, errno); 185262306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST); 185362306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOTSUPP, "reuseport array update SOCK_RAW", 185462306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 185562306a36Sopenharmony_ci close(fd64); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci /* Close the 64 bit value map */ 185862306a36Sopenharmony_ci close(map_fd); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci /* Test 32 bit fd */ 186162306a36Sopenharmony_ci map_fd = bpf_map_create(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, NULL, 186262306a36Sopenharmony_ci sizeof(__u32), sizeof(__u32), array_size, NULL); 186362306a36Sopenharmony_ci CHECK(map_fd < 0, "reuseport array create", 186462306a36Sopenharmony_ci "map_fd:%d, errno:%d\n", map_fd, errno); 186562306a36Sopenharmony_ci prepare_reuseport_grp(SOCK_STREAM, map_fd, sizeof(__u32), &fd64, 186662306a36Sopenharmony_ci &sk_cookie, 1); 186762306a36Sopenharmony_ci fd = fd64; 186862306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST); 186962306a36Sopenharmony_ci CHECK(err < 0, "reuseport array update 32 bit fd", 187062306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 187162306a36Sopenharmony_ci err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); 187262306a36Sopenharmony_ci CHECK(err >= 0 || errno != ENOSPC, 187362306a36Sopenharmony_ci "reuseport array lookup 32 bit fd", 187462306a36Sopenharmony_ci "err:%d errno:%d\n", err, errno); 187562306a36Sopenharmony_ci close(fd); 187662306a36Sopenharmony_ci close(map_fd); 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_cistatic void run_all_tests(void) 188062306a36Sopenharmony_ci{ 188162306a36Sopenharmony_ci test_hashmap(0, NULL); 188262306a36Sopenharmony_ci test_hashmap_percpu(0, NULL); 188362306a36Sopenharmony_ci test_hashmap_walk(0, NULL); 188462306a36Sopenharmony_ci test_hashmap_zero_seed(); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci test_arraymap(0, NULL); 188762306a36Sopenharmony_ci test_arraymap_percpu(0, NULL); 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci test_arraymap_percpu_many_keys(); 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci test_devmap(0, NULL); 189262306a36Sopenharmony_ci test_devmap_hash(0, NULL); 189362306a36Sopenharmony_ci test_sockmap(0, NULL); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci test_map_large(); 189662306a36Sopenharmony_ci test_map_parallel(); 189762306a36Sopenharmony_ci test_map_stress(); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci test_map_rdonly(); 190062306a36Sopenharmony_ci test_map_wronly(); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci test_reuseport_array(); 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci test_queuemap(0, NULL); 190562306a36Sopenharmony_ci test_stackmap(0, NULL); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci test_map_in_map(); 190862306a36Sopenharmony_ci} 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci#define DEFINE_TEST(name) extern void test_##name(void); 191162306a36Sopenharmony_ci#include <map_tests/tests.h> 191262306a36Sopenharmony_ci#undef DEFINE_TEST 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ciint main(void) 191562306a36Sopenharmony_ci{ 191662306a36Sopenharmony_ci srand(time(NULL)); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci map_opts.map_flags = 0; 192162306a36Sopenharmony_ci run_all_tests(); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci map_opts.map_flags = BPF_F_NO_PREALLOC; 192462306a36Sopenharmony_ci run_all_tests(); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci#define DEFINE_TEST(name) test_##name(); 192762306a36Sopenharmony_ci#include <map_tests/tests.h> 192862306a36Sopenharmony_ci#undef DEFINE_TEST 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci printf("test_maps: OK, %d SKIPPED\n", skips); 193162306a36Sopenharmony_ci return 0; 193262306a36Sopenharmony_ci} 1933