125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25aa5bd14SDaniel Borkmann /*
35aa5bd14SDaniel Borkmann * Testsuite for eBPF maps
45aa5bd14SDaniel Borkmann *
55aa5bd14SDaniel Borkmann * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
65aa5bd14SDaniel Borkmann * Copyright (c) 2016 Facebook
75aa5bd14SDaniel Borkmann */
85aa5bd14SDaniel Borkmann
95aa5bd14SDaniel Borkmann #include <stdio.h>
105aa5bd14SDaniel Borkmann #include <unistd.h>
115aa5bd14SDaniel Borkmann #include <errno.h>
125aa5bd14SDaniel Borkmann #include <string.h>
135aa5bd14SDaniel Borkmann #include <assert.h>
145aa5bd14SDaniel Borkmann #include <stdlib.h>
1543b987d2SMauricio Vasquez B #include <time.h>
165aa5bd14SDaniel Borkmann
175aa5bd14SDaniel Borkmann #include <sys/wait.h>
186bc8529cSMartin KaFai Lau #include <sys/socket.h>
196bc8529cSMartin KaFai Lau #include <netinet/in.h>
205aa5bd14SDaniel Borkmann #include <linux/bpf.h>
215aa5bd14SDaniel Borkmann
2210ecc728SMickaël Salaün #include <bpf/bpf.h>
236f6d33f3SJohn Fastabend #include <bpf/libbpf.h>
24fe8d662aSDaniel Borkmann
25e00c7b21SDaniel Borkmann #include "bpf_util.h"
2651a0e301SMartin KaFai Lau #include "test_maps.h"
27cbdb1461SAndrii Nakryiko #include "testing_helpers.h"
285aa5bd14SDaniel Borkmann
296bc8529cSMartin KaFai Lau #ifndef ENOTSUPP
306bc8529cSMartin KaFai Lau #define ENOTSUPP 524
316bc8529cSMartin KaFai Lau #endif
326bc8529cSMartin KaFai Lau
33a7e85406SHou Tao int skips;
34e8ddbfb4SStanislav Fomichev
352fe256a4SAndrii Nakryiko static struct bpf_map_create_opts map_opts = { .sz = sizeof(map_opts) };
365aa5bd14SDaniel Borkmann
test_hashmap(unsigned int task,void * data)37dd9cef43SBreno Leitao static void test_hashmap(unsigned int task, void *data)
385aa5bd14SDaniel Borkmann {
398fe45924STeng Qin long long key, next_key, first_key, value;
405aa5bd14SDaniel Borkmann int fd;
415aa5bd14SDaniel Borkmann
422fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 2, &map_opts);
435aa5bd14SDaniel Borkmann if (fd < 0) {
445aa5bd14SDaniel Borkmann printf("Failed to create hashmap '%s'!\n", strerror(errno));
455aa5bd14SDaniel Borkmann exit(1);
465aa5bd14SDaniel Borkmann }
475aa5bd14SDaniel Borkmann
485aa5bd14SDaniel Borkmann key = 1;
495aa5bd14SDaniel Borkmann value = 1234;
505aa5bd14SDaniel Borkmann /* Insert key=1 element. */
5110ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
525aa5bd14SDaniel Borkmann
535aa5bd14SDaniel Borkmann value = 0;
545aa5bd14SDaniel Borkmann /* BPF_NOEXIST means add new element if it doesn't exist. */
55bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
565aa5bd14SDaniel Borkmann /* key=1 already exists. */
575aa5bd14SDaniel Borkmann errno == EEXIST);
585aa5bd14SDaniel Borkmann
595aa5bd14SDaniel Borkmann /* -1 is an invalid flag. */
60bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, -1) < 0 &&
6110ecc728SMickaël Salaün errno == EINVAL);
625aa5bd14SDaniel Borkmann
635aa5bd14SDaniel Borkmann /* Check that key=1 can be found. */
64e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
655aa5bd14SDaniel Borkmann
665aa5bd14SDaniel Borkmann key = 2;
6749c299b6SDenis Salopek value = 1234;
6849c299b6SDenis Salopek /* Insert key=2 element. */
6949c299b6SDenis Salopek assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
7049c299b6SDenis Salopek
7149c299b6SDenis Salopek /* Check that key=2 matches the value and delete it */
7249c299b6SDenis Salopek assert(bpf_map_lookup_and_delete_elem(fd, &key, &value) == 0 && value == 1234);
7349c299b6SDenis Salopek
745aa5bd14SDaniel Borkmann /* Check that key=2 is not found. */
75bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
765aa5bd14SDaniel Borkmann
775aa5bd14SDaniel Borkmann /* BPF_EXIST means update existing element. */
78bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) < 0 &&
795aa5bd14SDaniel Borkmann /* key=2 is not there. */
805aa5bd14SDaniel Borkmann errno == ENOENT);
815aa5bd14SDaniel Borkmann
825aa5bd14SDaniel Borkmann /* Insert key=2 element. */
8310ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
845aa5bd14SDaniel Borkmann
855aa5bd14SDaniel Borkmann /* key=1 and key=2 were inserted, check that key=0 cannot be
865aa5bd14SDaniel Borkmann * inserted due to max_entries limit.
875aa5bd14SDaniel Borkmann */
885aa5bd14SDaniel Borkmann key = 0;
89bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
905aa5bd14SDaniel Borkmann errno == E2BIG);
915aa5bd14SDaniel Borkmann
925aa5bd14SDaniel Borkmann /* Update existing element, though the map is full. */
935aa5bd14SDaniel Borkmann key = 1;
9410ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);
955aa5bd14SDaniel Borkmann key = 2;
9610ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
978c290e60SAlexei Starovoitov key = 3;
98bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
998c290e60SAlexei Starovoitov errno == E2BIG);
1005aa5bd14SDaniel Borkmann
1015aa5bd14SDaniel Borkmann /* Check that key = 0 doesn't exist. */
1025aa5bd14SDaniel Borkmann key = 0;
103bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
1045aa5bd14SDaniel Borkmann
1055aa5bd14SDaniel Borkmann /* Iterate over two elements. */
1068fe45924STeng Qin assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
1078fe45924STeng Qin (first_key == 1 || first_key == 2));
1085f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
1098fe45924STeng Qin (next_key == first_key));
1105f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
1118fe45924STeng Qin (next_key == 1 || next_key == 2) &&
1128fe45924STeng Qin (next_key != first_key));
113bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 &&
1145aa5bd14SDaniel Borkmann errno == ENOENT);
1155aa5bd14SDaniel Borkmann
1165aa5bd14SDaniel Borkmann /* Delete both elements. */
1175aa5bd14SDaniel Borkmann key = 1;
118e58383b8SMickaël Salaün assert(bpf_map_delete_elem(fd, &key) == 0);
1195aa5bd14SDaniel Borkmann key = 2;
120e58383b8SMickaël Salaün assert(bpf_map_delete_elem(fd, &key) == 0);
121bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
1225aa5bd14SDaniel Borkmann
1235aa5bd14SDaniel Borkmann key = 0;
1245aa5bd14SDaniel Borkmann /* Check that map is empty. */
125bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, NULL, &next_key) < 0 &&
1268fe45924STeng Qin errno == ENOENT);
127bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &next_key) < 0 &&
1285aa5bd14SDaniel Borkmann errno == ENOENT);
1295aa5bd14SDaniel Borkmann
1305aa5bd14SDaniel Borkmann close(fd);
1315aa5bd14SDaniel Borkmann }
1325aa5bd14SDaniel Borkmann
test_hashmap_sizes(unsigned int task,void * data)133dd9cef43SBreno Leitao static void test_hashmap_sizes(unsigned int task, void *data)
1348c290e60SAlexei Starovoitov {
1358c290e60SAlexei Starovoitov int fd, i, j;
1368c290e60SAlexei Starovoitov
1378c290e60SAlexei Starovoitov for (i = 1; i <= 512; i <<= 1)
1388c290e60SAlexei Starovoitov for (j = 1; j <= 1 << 18; j <<= 1) {
1392fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, i, j, 2, &map_opts);
1408c290e60SAlexei Starovoitov if (fd < 0) {
14180475c48SLi Zhijian if (errno == ENOMEM)
14280475c48SLi Zhijian return;
1438c290e60SAlexei Starovoitov printf("Failed to create hashmap key=%d value=%d '%s'\n",
1448c290e60SAlexei Starovoitov i, j, strerror(errno));
1458c290e60SAlexei Starovoitov exit(1);
1468c290e60SAlexei Starovoitov }
1478c290e60SAlexei Starovoitov close(fd);
1488c290e60SAlexei Starovoitov usleep(10); /* give kernel time to destroy */
1498c290e60SAlexei Starovoitov }
1508c290e60SAlexei Starovoitov }
1518c290e60SAlexei Starovoitov
test_hashmap_percpu(unsigned int task,void * data)152dd9cef43SBreno Leitao static void test_hashmap_percpu(unsigned int task, void *data)
1535aa5bd14SDaniel Borkmann {
154e00c7b21SDaniel Borkmann unsigned int nr_cpus = bpf_num_possible_cpus();
155f3515b5dSDaniel Borkmann BPF_DECLARE_PERCPU(long, value);
1568fe45924STeng Qin long long key, next_key, first_key;
1575aa5bd14SDaniel Borkmann int expected_key_mask = 0;
1585aa5bd14SDaniel Borkmann int fd, i;
1595aa5bd14SDaniel Borkmann
1602fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_HASH, NULL, sizeof(key),
1612fe256a4SAndrii Nakryiko sizeof(bpf_percpu(value, 0)), 2, &map_opts);
1625aa5bd14SDaniel Borkmann if (fd < 0) {
1635aa5bd14SDaniel Borkmann printf("Failed to create hashmap '%s'!\n", strerror(errno));
1645aa5bd14SDaniel Borkmann exit(1);
1655aa5bd14SDaniel Borkmann }
1665aa5bd14SDaniel Borkmann
1675aa5bd14SDaniel Borkmann for (i = 0; i < nr_cpus; i++)
168f3515b5dSDaniel Borkmann bpf_percpu(value, i) = i + 100;
1695aa5bd14SDaniel Borkmann
1705aa5bd14SDaniel Borkmann key = 1;
1715aa5bd14SDaniel Borkmann /* Insert key=1 element. */
1725aa5bd14SDaniel Borkmann assert(!(expected_key_mask & key));
17310ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, value, BPF_ANY) == 0);
17449c299b6SDenis Salopek
17549c299b6SDenis Salopek /* Lookup and delete elem key=1 and check value. */
17649c299b6SDenis Salopek assert(bpf_map_lookup_and_delete_elem(fd, &key, value) == 0 &&
17749c299b6SDenis Salopek bpf_percpu(value,0) == 100);
17849c299b6SDenis Salopek
17949c299b6SDenis Salopek for (i = 0; i < nr_cpus; i++)
18049c299b6SDenis Salopek bpf_percpu(value,i) = i + 100;
18149c299b6SDenis Salopek
18249c299b6SDenis Salopek /* Insert key=1 element which should not exist. */
18349c299b6SDenis Salopek assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0);
1845aa5bd14SDaniel Borkmann expected_key_mask |= key;
1855aa5bd14SDaniel Borkmann
1865aa5bd14SDaniel Borkmann /* BPF_NOEXIST means add new element if it doesn't exist. */
187bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) < 0 &&
1885aa5bd14SDaniel Borkmann /* key=1 already exists. */
1895aa5bd14SDaniel Borkmann errno == EEXIST);
1905aa5bd14SDaniel Borkmann
1915aa5bd14SDaniel Borkmann /* -1 is an invalid flag. */
192bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, value, -1) < 0 &&
19310ecc728SMickaël Salaün errno == EINVAL);
1945aa5bd14SDaniel Borkmann
1955aa5bd14SDaniel Borkmann /* Check that key=1 can be found. Value could be 0 if the lookup
1965aa5bd14SDaniel Borkmann * was run from a different CPU.
1975aa5bd14SDaniel Borkmann */
198f3515b5dSDaniel Borkmann bpf_percpu(value, 0) = 1;
199f3515b5dSDaniel Borkmann assert(bpf_map_lookup_elem(fd, &key, value) == 0 &&
200f3515b5dSDaniel Borkmann bpf_percpu(value, 0) == 100);
2015aa5bd14SDaniel Borkmann
2025aa5bd14SDaniel Borkmann key = 2;
2035aa5bd14SDaniel Borkmann /* Check that key=2 is not found. */
204bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, value) < 0 && errno == ENOENT);
2055aa5bd14SDaniel Borkmann
2065aa5bd14SDaniel Borkmann /* BPF_EXIST means update existing element. */
207bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) < 0 &&
2085aa5bd14SDaniel Borkmann /* key=2 is not there. */
2095aa5bd14SDaniel Borkmann errno == ENOENT);
2105aa5bd14SDaniel Borkmann
2115aa5bd14SDaniel Borkmann /* Insert key=2 element. */
2125aa5bd14SDaniel Borkmann assert(!(expected_key_mask & key));
21310ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0);
2145aa5bd14SDaniel Borkmann expected_key_mask |= key;
2155aa5bd14SDaniel Borkmann
2165aa5bd14SDaniel Borkmann /* key=1 and key=2 were inserted, check that key=0 cannot be
2175aa5bd14SDaniel Borkmann * inserted due to max_entries limit.
2185aa5bd14SDaniel Borkmann */
2195aa5bd14SDaniel Borkmann key = 0;
220bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) < 0 &&
2215aa5bd14SDaniel Borkmann errno == E2BIG);
2225aa5bd14SDaniel Borkmann
2235aa5bd14SDaniel Borkmann /* Check that key = 0 doesn't exist. */
224bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
2255aa5bd14SDaniel Borkmann
2265aa5bd14SDaniel Borkmann /* Iterate over two elements. */
2278fe45924STeng Qin assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
2288fe45924STeng Qin ((expected_key_mask & first_key) == first_key));
2295f155c25SMickaël Salaün while (!bpf_map_get_next_key(fd, &key, &next_key)) {
2308fe45924STeng Qin if (first_key) {
2318fe45924STeng Qin assert(next_key == first_key);
2328fe45924STeng Qin first_key = 0;
2338fe45924STeng Qin }
2345aa5bd14SDaniel Borkmann assert((expected_key_mask & next_key) == next_key);
2355aa5bd14SDaniel Borkmann expected_key_mask &= ~next_key;
2365aa5bd14SDaniel Borkmann
237e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &next_key, value) == 0);
2385aa5bd14SDaniel Borkmann
2395aa5bd14SDaniel Borkmann for (i = 0; i < nr_cpus; i++)
240f3515b5dSDaniel Borkmann assert(bpf_percpu(value, i) == i + 100);
2415aa5bd14SDaniel Borkmann
2425aa5bd14SDaniel Borkmann key = next_key;
2435aa5bd14SDaniel Borkmann }
2445aa5bd14SDaniel Borkmann assert(errno == ENOENT);
2455aa5bd14SDaniel Borkmann
2465aa5bd14SDaniel Borkmann /* Update with BPF_EXIST. */
2475aa5bd14SDaniel Borkmann key = 1;
24810ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
2495aa5bd14SDaniel Borkmann
2505aa5bd14SDaniel Borkmann /* Delete both elements. */
2515aa5bd14SDaniel Borkmann key = 1;
252e58383b8SMickaël Salaün assert(bpf_map_delete_elem(fd, &key) == 0);
2535aa5bd14SDaniel Borkmann key = 2;
254e58383b8SMickaël Salaün assert(bpf_map_delete_elem(fd, &key) == 0);
255bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
2565aa5bd14SDaniel Borkmann
2575aa5bd14SDaniel Borkmann key = 0;
2585aa5bd14SDaniel Borkmann /* Check that map is empty. */
259bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, NULL, &next_key) < 0 &&
2608fe45924STeng Qin errno == ENOENT);
261bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &next_key) < 0 &&
2625aa5bd14SDaniel Borkmann errno == ENOENT);
2635aa5bd14SDaniel Borkmann
2645aa5bd14SDaniel Borkmann close(fd);
2655aa5bd14SDaniel Borkmann }
2665aa5bd14SDaniel Borkmann
26737521bffSAlexei Starovoitov #define VALUE_SIZE 3
helper_fill_hashmap(int max_entries)268bf5d68c7SLorenz Bauer static int helper_fill_hashmap(int max_entries)
269bf5d68c7SLorenz Bauer {
270bf5d68c7SLorenz Bauer int i, fd, ret;
27137521bffSAlexei Starovoitov long long key, value[VALUE_SIZE] = {};
272bf5d68c7SLorenz Bauer
2732fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
2742fe256a4SAndrii Nakryiko max_entries, &map_opts);
275bf5d68c7SLorenz Bauer CHECK(fd < 0,
276bf5d68c7SLorenz Bauer "failed to create hashmap",
2772fe256a4SAndrii Nakryiko "err: %s, flags: 0x%x\n", strerror(errno), map_opts.map_flags);
278bf5d68c7SLorenz Bauer
279bf5d68c7SLorenz Bauer for (i = 0; i < max_entries; i++) {
28037521bffSAlexei Starovoitov key = i; value[0] = key;
28137521bffSAlexei Starovoitov ret = bpf_map_update_elem(fd, &key, value, BPF_NOEXIST);
282bf5d68c7SLorenz Bauer CHECK(ret != 0,
283bf5d68c7SLorenz Bauer "can't update hashmap",
284bf5d68c7SLorenz Bauer "err: %s\n", strerror(ret));
285bf5d68c7SLorenz Bauer }
286bf5d68c7SLorenz Bauer
287bf5d68c7SLorenz Bauer return fd;
288bf5d68c7SLorenz Bauer }
289bf5d68c7SLorenz Bauer
test_hashmap_walk(unsigned int task,void * data)290dd9cef43SBreno Leitao static void test_hashmap_walk(unsigned int task, void *data)
2915ecf51fdSDaniel Borkmann {
29237521bffSAlexei Starovoitov int fd, i, max_entries = 10000;
29337521bffSAlexei Starovoitov long long key, value[VALUE_SIZE], next_key;
2945ecf51fdSDaniel Borkmann bool next_key_valid = true;
2955ecf51fdSDaniel Borkmann
296bf5d68c7SLorenz Bauer fd = helper_fill_hashmap(max_entries);
2975ecf51fdSDaniel Borkmann
2985ecf51fdSDaniel Borkmann for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
2995ecf51fdSDaniel Borkmann &next_key) == 0; i++) {
3005ecf51fdSDaniel Borkmann key = next_key;
30137521bffSAlexei Starovoitov assert(bpf_map_lookup_elem(fd, &key, value) == 0);
3025ecf51fdSDaniel Borkmann }
3035ecf51fdSDaniel Borkmann
3045ecf51fdSDaniel Borkmann assert(i == max_entries);
3055ecf51fdSDaniel Borkmann
3065ecf51fdSDaniel Borkmann assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
3075ecf51fdSDaniel Borkmann for (i = 0; next_key_valid; i++) {
3085ecf51fdSDaniel Borkmann next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0;
30937521bffSAlexei Starovoitov assert(bpf_map_lookup_elem(fd, &key, value) == 0);
31037521bffSAlexei Starovoitov value[0]++;
31137521bffSAlexei Starovoitov assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
3125ecf51fdSDaniel Borkmann key = next_key;
3135ecf51fdSDaniel Borkmann }
3145ecf51fdSDaniel Borkmann
3155ecf51fdSDaniel Borkmann assert(i == max_entries);
3165ecf51fdSDaniel Borkmann
3175ecf51fdSDaniel Borkmann for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
3185ecf51fdSDaniel Borkmann &next_key) == 0; i++) {
3195ecf51fdSDaniel Borkmann key = next_key;
32037521bffSAlexei Starovoitov assert(bpf_map_lookup_elem(fd, &key, value) == 0);
32137521bffSAlexei Starovoitov assert(value[0] - 1 == key);
3225ecf51fdSDaniel Borkmann }
3235ecf51fdSDaniel Borkmann
3245ecf51fdSDaniel Borkmann assert(i == max_entries);
3255ecf51fdSDaniel Borkmann close(fd);
3265ecf51fdSDaniel Borkmann }
3275ecf51fdSDaniel Borkmann
test_hashmap_zero_seed(void)328bf5d68c7SLorenz Bauer static void test_hashmap_zero_seed(void)
329bf5d68c7SLorenz Bauer {
330bf5d68c7SLorenz Bauer int i, first, second, old_flags;
331bf5d68c7SLorenz Bauer long long key, next_first, next_second;
332bf5d68c7SLorenz Bauer
3332fe256a4SAndrii Nakryiko old_flags = map_opts.map_flags;
3342fe256a4SAndrii Nakryiko map_opts.map_flags |= BPF_F_ZERO_SEED;
335bf5d68c7SLorenz Bauer
336bf5d68c7SLorenz Bauer first = helper_fill_hashmap(3);
337bf5d68c7SLorenz Bauer second = helper_fill_hashmap(3);
338bf5d68c7SLorenz Bauer
339bf5d68c7SLorenz Bauer for (i = 0; ; i++) {
340bf5d68c7SLorenz Bauer void *key_ptr = !i ? NULL : &key;
341bf5d68c7SLorenz Bauer
342bf5d68c7SLorenz Bauer if (bpf_map_get_next_key(first, key_ptr, &next_first) != 0)
343bf5d68c7SLorenz Bauer break;
344bf5d68c7SLorenz Bauer
345bf5d68c7SLorenz Bauer CHECK(bpf_map_get_next_key(second, key_ptr, &next_second) != 0,
346bf5d68c7SLorenz Bauer "next_key for second map must succeed",
347bf5d68c7SLorenz Bauer "key_ptr: %p", key_ptr);
348bf5d68c7SLorenz Bauer CHECK(next_first != next_second,
349bf5d68c7SLorenz Bauer "keys must match",
350bf5d68c7SLorenz Bauer "i: %d first: %lld second: %lld\n", i,
351bf5d68c7SLorenz Bauer next_first, next_second);
352bf5d68c7SLorenz Bauer
353bf5d68c7SLorenz Bauer key = next_first;
354bf5d68c7SLorenz Bauer }
355bf5d68c7SLorenz Bauer
3562fe256a4SAndrii Nakryiko map_opts.map_flags = old_flags;
357bf5d68c7SLorenz Bauer close(first);
358bf5d68c7SLorenz Bauer close(second);
359bf5d68c7SLorenz Bauer }
360bf5d68c7SLorenz Bauer
test_arraymap(unsigned int task,void * data)361dd9cef43SBreno Leitao static void test_arraymap(unsigned int task, void *data)
3625aa5bd14SDaniel Borkmann {
3635aa5bd14SDaniel Borkmann int key, next_key, fd;
3645aa5bd14SDaniel Borkmann long long value;
3655aa5bd14SDaniel Borkmann
3662fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(key), sizeof(value), 2, NULL);
3675aa5bd14SDaniel Borkmann if (fd < 0) {
3685aa5bd14SDaniel Borkmann printf("Failed to create arraymap '%s'!\n", strerror(errno));
3695aa5bd14SDaniel Borkmann exit(1);
3705aa5bd14SDaniel Borkmann }
3715aa5bd14SDaniel Borkmann
3725aa5bd14SDaniel Borkmann key = 1;
3735aa5bd14SDaniel Borkmann value = 1234;
3745aa5bd14SDaniel Borkmann /* Insert key=1 element. */
37510ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
3765aa5bd14SDaniel Borkmann
3775aa5bd14SDaniel Borkmann value = 0;
378bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
3795aa5bd14SDaniel Borkmann errno == EEXIST);
3805aa5bd14SDaniel Borkmann
3815aa5bd14SDaniel Borkmann /* Check that key=1 can be found. */
382e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
3835aa5bd14SDaniel Borkmann
3845aa5bd14SDaniel Borkmann key = 0;
3855aa5bd14SDaniel Borkmann /* Check that key=0 is also found and zero initialized. */
386e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
3875aa5bd14SDaniel Borkmann
3885aa5bd14SDaniel Borkmann /* key=0 and key=1 were inserted, check that key=2 cannot be inserted
3895aa5bd14SDaniel Borkmann * due to max_entries limit.
3905aa5bd14SDaniel Borkmann */
3915aa5bd14SDaniel Borkmann key = 2;
392bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) < 0 &&
3935aa5bd14SDaniel Borkmann errno == E2BIG);
3945aa5bd14SDaniel Borkmann
3955aa5bd14SDaniel Borkmann /* Check that key = 2 doesn't exist. */
396bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
3975aa5bd14SDaniel Borkmann
3985aa5bd14SDaniel Borkmann /* Iterate over two elements. */
3998fe45924STeng Qin assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
4008fe45924STeng Qin next_key == 0);
4015f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
4025aa5bd14SDaniel Borkmann next_key == 0);
4035f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
4045aa5bd14SDaniel Borkmann next_key == 1);
405bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 &&
4065aa5bd14SDaniel Borkmann errno == ENOENT);
4075aa5bd14SDaniel Borkmann
4085aa5bd14SDaniel Borkmann /* Delete shouldn't succeed. */
4095aa5bd14SDaniel Borkmann key = 1;
410bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, &key) < 0 && errno == EINVAL);
4115aa5bd14SDaniel Borkmann
4125aa5bd14SDaniel Borkmann close(fd);
4135aa5bd14SDaniel Borkmann }
4145aa5bd14SDaniel Borkmann
test_arraymap_percpu(unsigned int task,void * data)415dd9cef43SBreno Leitao static void test_arraymap_percpu(unsigned int task, void *data)
4165aa5bd14SDaniel Borkmann {
417e00c7b21SDaniel Borkmann unsigned int nr_cpus = bpf_num_possible_cpus();
418f3515b5dSDaniel Borkmann BPF_DECLARE_PERCPU(long, values);
4195aa5bd14SDaniel Borkmann int key, next_key, fd, i;
4205aa5bd14SDaniel Borkmann
4212fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, sizeof(key),
4222fe256a4SAndrii Nakryiko sizeof(bpf_percpu(values, 0)), 2, NULL);
4235aa5bd14SDaniel Borkmann if (fd < 0) {
4245aa5bd14SDaniel Borkmann printf("Failed to create arraymap '%s'!\n", strerror(errno));
4255aa5bd14SDaniel Borkmann exit(1);
4265aa5bd14SDaniel Borkmann }
4275aa5bd14SDaniel Borkmann
4285aa5bd14SDaniel Borkmann for (i = 0; i < nr_cpus; i++)
429f3515b5dSDaniel Borkmann bpf_percpu(values, i) = i + 100;
4305aa5bd14SDaniel Borkmann
4315aa5bd14SDaniel Borkmann key = 1;
4325aa5bd14SDaniel Borkmann /* Insert key=1 element. */
43310ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
4345aa5bd14SDaniel Borkmann
435f3515b5dSDaniel Borkmann bpf_percpu(values, 0) = 0;
436bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) < 0 &&
4375aa5bd14SDaniel Borkmann errno == EEXIST);
4385aa5bd14SDaniel Borkmann
4395aa5bd14SDaniel Borkmann /* Check that key=1 can be found. */
440f3515b5dSDaniel Borkmann assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
441f3515b5dSDaniel Borkmann bpf_percpu(values, 0) == 100);
4425aa5bd14SDaniel Borkmann
4435aa5bd14SDaniel Borkmann key = 0;
4445aa5bd14SDaniel Borkmann /* Check that key=0 is also found and zero initialized. */
445e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
446f3515b5dSDaniel Borkmann bpf_percpu(values, 0) == 0 &&
447f3515b5dSDaniel Borkmann bpf_percpu(values, nr_cpus - 1) == 0);
4485aa5bd14SDaniel Borkmann
4495aa5bd14SDaniel Borkmann /* Check that key=2 cannot be inserted due to max_entries limit. */
4505aa5bd14SDaniel Borkmann key = 2;
451bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, values, BPF_EXIST) < 0 &&
4525aa5bd14SDaniel Borkmann errno == E2BIG);
4535aa5bd14SDaniel Borkmann
4545aa5bd14SDaniel Borkmann /* Check that key = 2 doesn't exist. */
455bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, values) < 0 && errno == ENOENT);
4565aa5bd14SDaniel Borkmann
4575aa5bd14SDaniel Borkmann /* Iterate over two elements. */
4588fe45924STeng Qin assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
4598fe45924STeng Qin next_key == 0);
4605f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
4615aa5bd14SDaniel Borkmann next_key == 0);
4625f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
4635aa5bd14SDaniel Borkmann next_key == 1);
464bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 &&
4655aa5bd14SDaniel Borkmann errno == ENOENT);
4665aa5bd14SDaniel Borkmann
4675aa5bd14SDaniel Borkmann /* Delete shouldn't succeed. */
4685aa5bd14SDaniel Borkmann key = 1;
469bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, &key) < 0 && errno == EINVAL);
4705aa5bd14SDaniel Borkmann
4715aa5bd14SDaniel Borkmann close(fd);
4725aa5bd14SDaniel Borkmann }
4735aa5bd14SDaniel Borkmann
test_arraymap_percpu_many_keys(void)4745aa5bd14SDaniel Borkmann static void test_arraymap_percpu_many_keys(void)
4755aa5bd14SDaniel Borkmann {
476e00c7b21SDaniel Borkmann unsigned int nr_cpus = bpf_num_possible_cpus();
477f3515b5dSDaniel Borkmann BPF_DECLARE_PERCPU(long, values);
4788c290e60SAlexei Starovoitov /* nr_keys is not too large otherwise the test stresses percpu
4798c290e60SAlexei Starovoitov * allocator more than anything else
4808c290e60SAlexei Starovoitov */
4818c290e60SAlexei Starovoitov unsigned int nr_keys = 2000;
4825aa5bd14SDaniel Borkmann int key, fd, i;
4835aa5bd14SDaniel Borkmann
4842fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, sizeof(key),
4852fe256a4SAndrii Nakryiko sizeof(bpf_percpu(values, 0)), nr_keys, NULL);
4865aa5bd14SDaniel Borkmann if (fd < 0) {
4875aa5bd14SDaniel Borkmann printf("Failed to create per-cpu arraymap '%s'!\n",
4885aa5bd14SDaniel Borkmann strerror(errno));
4895aa5bd14SDaniel Borkmann exit(1);
4905aa5bd14SDaniel Borkmann }
4915aa5bd14SDaniel Borkmann
4925aa5bd14SDaniel Borkmann for (i = 0; i < nr_cpus; i++)
493f3515b5dSDaniel Borkmann bpf_percpu(values, i) = i + 10;
4945aa5bd14SDaniel Borkmann
4955aa5bd14SDaniel Borkmann for (key = 0; key < nr_keys; key++)
49610ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
4975aa5bd14SDaniel Borkmann
4985aa5bd14SDaniel Borkmann for (key = 0; key < nr_keys; key++) {
4995aa5bd14SDaniel Borkmann for (i = 0; i < nr_cpus; i++)
500f3515b5dSDaniel Borkmann bpf_percpu(values, i) = 0;
5015aa5bd14SDaniel Borkmann
502e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, values) == 0);
5035aa5bd14SDaniel Borkmann
5045aa5bd14SDaniel Borkmann for (i = 0; i < nr_cpus; i++)
505f3515b5dSDaniel Borkmann assert(bpf_percpu(values, i) == i + 10);
5065aa5bd14SDaniel Borkmann }
5075aa5bd14SDaniel Borkmann
5085aa5bd14SDaniel Borkmann close(fd);
5095aa5bd14SDaniel Borkmann }
5105aa5bd14SDaniel Borkmann
test_devmap(unsigned int task,void * data)511dd9cef43SBreno Leitao static void test_devmap(unsigned int task, void *data)
512546ac1ffSJohn Fastabend {
51381f6bf81SJohn Fastabend int fd;
514546ac1ffSJohn Fastabend __u32 key, value;
515546ac1ffSJohn Fastabend
5162fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, NULL, sizeof(key), sizeof(value), 2, NULL);
517546ac1ffSJohn Fastabend if (fd < 0) {
5188b6b25cfSXiaozhou Liu printf("Failed to create devmap '%s'!\n", strerror(errno));
519546ac1ffSJohn Fastabend exit(1);
520546ac1ffSJohn Fastabend }
521546ac1ffSJohn Fastabend
522546ac1ffSJohn Fastabend close(fd);
523546ac1ffSJohn Fastabend }
524546ac1ffSJohn Fastabend
test_devmap_hash(unsigned int task,void * data)5251375dc4aSToke Høiland-Jørgensen static void test_devmap_hash(unsigned int task, void *data)
5261375dc4aSToke Høiland-Jørgensen {
5271375dc4aSToke Høiland-Jørgensen int fd;
5281375dc4aSToke Høiland-Jørgensen __u32 key, value;
5291375dc4aSToke Høiland-Jørgensen
5302fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP_HASH, NULL, sizeof(key), sizeof(value), 2, NULL);
5311375dc4aSToke Høiland-Jørgensen if (fd < 0) {
5321375dc4aSToke Høiland-Jørgensen printf("Failed to create devmap_hash '%s'!\n", strerror(errno));
5331375dc4aSToke Høiland-Jørgensen exit(1);
5341375dc4aSToke Høiland-Jørgensen }
5351375dc4aSToke Høiland-Jørgensen
5361375dc4aSToke Høiland-Jørgensen close(fd);
5371375dc4aSToke Høiland-Jørgensen }
5381375dc4aSToke Høiland-Jørgensen
test_queuemap(unsigned int task,void * data)539dd9cef43SBreno Leitao static void test_queuemap(unsigned int task, void *data)
54043b987d2SMauricio Vasquez B {
54143b987d2SMauricio Vasquez B const int MAP_SIZE = 32;
54243b987d2SMauricio Vasquez B __u32 vals[MAP_SIZE + MAP_SIZE/2], val;
54343b987d2SMauricio Vasquez B int fd, i;
54443b987d2SMauricio Vasquez B
54543b987d2SMauricio Vasquez B /* Fill test values to be used */
54643b987d2SMauricio Vasquez B for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
54743b987d2SMauricio Vasquez B vals[i] = rand();
54843b987d2SMauricio Vasquez B
54943b987d2SMauricio Vasquez B /* Invalid key size */
5502fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 4, sizeof(val), MAP_SIZE, &map_opts);
55143b987d2SMauricio Vasquez B assert(fd < 0 && errno == EINVAL);
55243b987d2SMauricio Vasquez B
5532fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, sizeof(val), MAP_SIZE, &map_opts);
55443b987d2SMauricio Vasquez B /* Queue map does not support BPF_F_NO_PREALLOC */
5552fe256a4SAndrii Nakryiko if (map_opts.map_flags & BPF_F_NO_PREALLOC) {
55643b987d2SMauricio Vasquez B assert(fd < 0 && errno == EINVAL);
55743b987d2SMauricio Vasquez B return;
55843b987d2SMauricio Vasquez B }
55943b987d2SMauricio Vasquez B if (fd < 0) {
56043b987d2SMauricio Vasquez B printf("Failed to create queuemap '%s'!\n", strerror(errno));
56143b987d2SMauricio Vasquez B exit(1);
56243b987d2SMauricio Vasquez B }
56343b987d2SMauricio Vasquez B
56443b987d2SMauricio Vasquez B /* Push MAP_SIZE elements */
56543b987d2SMauricio Vasquez B for (i = 0; i < MAP_SIZE; i++)
56643b987d2SMauricio Vasquez B assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);
56743b987d2SMauricio Vasquez B
56843b987d2SMauricio Vasquez B /* Check that element cannot be pushed due to max_entries limit */
569bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, NULL, &val, 0) < 0 &&
57043b987d2SMauricio Vasquez B errno == E2BIG);
57143b987d2SMauricio Vasquez B
57243b987d2SMauricio Vasquez B /* Peek element */
57343b987d2SMauricio Vasquez B assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]);
57443b987d2SMauricio Vasquez B
57543b987d2SMauricio Vasquez B /* Replace half elements */
57643b987d2SMauricio Vasquez B for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
57743b987d2SMauricio Vasquez B assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);
57843b987d2SMauricio Vasquez B
57943b987d2SMauricio Vasquez B /* Pop all elements */
58043b987d2SMauricio Vasquez B for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++)
58143b987d2SMauricio Vasquez B assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
58243b987d2SMauricio Vasquez B val == vals[i]);
58343b987d2SMauricio Vasquez B
58443b987d2SMauricio Vasquez B /* Check that there are not elements left */
585bad2e478SAndrii Nakryiko assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) < 0 &&
58643b987d2SMauricio Vasquez B errno == ENOENT);
58743b987d2SMauricio Vasquez B
58843b987d2SMauricio Vasquez B /* Check that non supported functions set errno to EINVAL */
589bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, NULL) < 0 && errno == EINVAL);
590bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, NULL, NULL) < 0 && errno == EINVAL);
59143b987d2SMauricio Vasquez B
59243b987d2SMauricio Vasquez B close(fd);
59343b987d2SMauricio Vasquez B }
59443b987d2SMauricio Vasquez B
test_stackmap(unsigned int task,void * data)595dd9cef43SBreno Leitao static void test_stackmap(unsigned int task, void *data)
59643b987d2SMauricio Vasquez B {
59743b987d2SMauricio Vasquez B const int MAP_SIZE = 32;
59843b987d2SMauricio Vasquez B __u32 vals[MAP_SIZE + MAP_SIZE/2], val;
59943b987d2SMauricio Vasquez B int fd, i;
60043b987d2SMauricio Vasquez B
60143b987d2SMauricio Vasquez B /* Fill test values to be used */
60243b987d2SMauricio Vasquez B for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
60343b987d2SMauricio Vasquez B vals[i] = rand();
60443b987d2SMauricio Vasquez B
60543b987d2SMauricio Vasquez B /* Invalid key size */
6062fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 4, sizeof(val), MAP_SIZE, &map_opts);
60743b987d2SMauricio Vasquez B assert(fd < 0 && errno == EINVAL);
60843b987d2SMauricio Vasquez B
6092fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, sizeof(val), MAP_SIZE, &map_opts);
61043b987d2SMauricio Vasquez B /* Stack map does not support BPF_F_NO_PREALLOC */
6112fe256a4SAndrii Nakryiko if (map_opts.map_flags & BPF_F_NO_PREALLOC) {
61243b987d2SMauricio Vasquez B assert(fd < 0 && errno == EINVAL);
61343b987d2SMauricio Vasquez B return;
61443b987d2SMauricio Vasquez B }
61543b987d2SMauricio Vasquez B if (fd < 0) {
61643b987d2SMauricio Vasquez B printf("Failed to create stackmap '%s'!\n", strerror(errno));
61743b987d2SMauricio Vasquez B exit(1);
61843b987d2SMauricio Vasquez B }
61943b987d2SMauricio Vasquez B
62043b987d2SMauricio Vasquez B /* Push MAP_SIZE elements */
62143b987d2SMauricio Vasquez B for (i = 0; i < MAP_SIZE; i++)
62243b987d2SMauricio Vasquez B assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);
62343b987d2SMauricio Vasquez B
62443b987d2SMauricio Vasquez B /* Check that element cannot be pushed due to max_entries limit */
625bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, NULL, &val, 0) < 0 &&
62643b987d2SMauricio Vasquez B errno == E2BIG);
62743b987d2SMauricio Vasquez B
62843b987d2SMauricio Vasquez B /* Peek element */
62943b987d2SMauricio Vasquez B assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]);
63043b987d2SMauricio Vasquez B
63143b987d2SMauricio Vasquez B /* Replace half elements */
63243b987d2SMauricio Vasquez B for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
63343b987d2SMauricio Vasquez B assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);
63443b987d2SMauricio Vasquez B
63543b987d2SMauricio Vasquez B /* Pop all elements */
63643b987d2SMauricio Vasquez B for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--)
63743b987d2SMauricio Vasquez B assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
63843b987d2SMauricio Vasquez B val == vals[i]);
63943b987d2SMauricio Vasquez B
64043b987d2SMauricio Vasquez B /* Check that there are not elements left */
641bad2e478SAndrii Nakryiko assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) < 0 &&
64243b987d2SMauricio Vasquez B errno == ENOENT);
64343b987d2SMauricio Vasquez B
64443b987d2SMauricio Vasquez B /* Check that non supported functions set errno to EINVAL */
645bad2e478SAndrii Nakryiko assert(bpf_map_delete_elem(fd, NULL) < 0 && errno == EINVAL);
646bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, NULL, NULL) < 0 && errno == EINVAL);
64743b987d2SMauricio Vasquez B
64843b987d2SMauricio Vasquez B close(fd);
64943b987d2SMauricio Vasquez B }
65043b987d2SMauricio Vasquez B
6516f6d33f3SJohn Fastabend #include <sys/ioctl.h>
6526f6d33f3SJohn Fastabend #include <arpa/inet.h>
6536f6d33f3SJohn Fastabend #include <sys/select.h>
6546f6d33f3SJohn Fastabend #include <linux/err.h>
655afef88e6SDaniel Müller #define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.bpf.o"
656afef88e6SDaniel Müller #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.bpf.o"
657afef88e6SDaniel Müller #define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.bpf.o"
test_sockmap(unsigned int tasks,void * data)658dd9cef43SBreno Leitao static void test_sockmap(unsigned int tasks, void *data)
6596f6d33f3SJohn Fastabend {
66082a86168SJohn Fastabend struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break;
66182a86168SJohn Fastabend int map_fd_msg = 0, map_fd_rx = 0, map_fd_tx = 0, map_fd_break;
662103d002fSHou Tao struct bpf_object *parse_obj, *verdict_obj, *msg_obj;
6636f6d33f3SJohn Fastabend int ports[] = {50200, 50201, 50202, 50204};
664435bf0d3SJohn Fastabend int err, i, fd, udp, sfd[6] = {0xdeadbeef};
6656fd28865SJohn Fastabend u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0};
66682a86168SJohn Fastabend int parse_prog, verdict_prog, msg_prog;
6676f6d33f3SJohn Fastabend struct sockaddr_in addr;
66882a86168SJohn Fastabend int one = 1, s, sc, rc;
6696f6d33f3SJohn Fastabend struct timeval to;
6706f6d33f3SJohn Fastabend __u32 key, value;
6713f0d6a16SJohn Fastabend pid_t pid[tasks];
6726f6d33f3SJohn Fastabend fd_set w;
6736f6d33f3SJohn Fastabend
6746f6d33f3SJohn Fastabend /* Create some sockets to use with sockmap */
6756f6d33f3SJohn Fastabend for (i = 0; i < 2; i++) {
6766f6d33f3SJohn Fastabend sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
6776f6d33f3SJohn Fastabend if (sfd[i] < 0)
6786f6d33f3SJohn Fastabend goto out;
6796f6d33f3SJohn Fastabend err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
6806f6d33f3SJohn Fastabend (char *)&one, sizeof(one));
6816f6d33f3SJohn Fastabend if (err) {
6826f6d33f3SJohn Fastabend printf("failed to setsockopt\n");
6836f6d33f3SJohn Fastabend goto out;
6846f6d33f3SJohn Fastabend }
6856f6d33f3SJohn Fastabend err = ioctl(sfd[i], FIONBIO, (char *)&one);
6866f6d33f3SJohn Fastabend if (err < 0) {
6876f6d33f3SJohn Fastabend printf("failed to ioctl\n");
6886f6d33f3SJohn Fastabend goto out;
6896f6d33f3SJohn Fastabend }
6906f6d33f3SJohn Fastabend memset(&addr, 0, sizeof(struct sockaddr_in));
6916f6d33f3SJohn Fastabend addr.sin_family = AF_INET;
6926f6d33f3SJohn Fastabend addr.sin_addr.s_addr = inet_addr("127.0.0.1");
6936f6d33f3SJohn Fastabend addr.sin_port = htons(ports[i]);
6946f6d33f3SJohn Fastabend err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
6956f6d33f3SJohn Fastabend if (err < 0) {
6966f6d33f3SJohn Fastabend printf("failed to bind: err %i: %i:%i\n",
6976f6d33f3SJohn Fastabend err, i, sfd[i]);
6986f6d33f3SJohn Fastabend goto out;
6996f6d33f3SJohn Fastabend }
7006f6d33f3SJohn Fastabend err = listen(sfd[i], 32);
7016f6d33f3SJohn Fastabend if (err < 0) {
70290774a93SColin Ian King printf("failed to listen\n");
7036f6d33f3SJohn Fastabend goto out;
7046f6d33f3SJohn Fastabend }
7056f6d33f3SJohn Fastabend }
7066f6d33f3SJohn Fastabend
7076f6d33f3SJohn Fastabend for (i = 2; i < 4; i++) {
7086f6d33f3SJohn Fastabend sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
7096f6d33f3SJohn Fastabend if (sfd[i] < 0)
7106f6d33f3SJohn Fastabend goto out;
7116f6d33f3SJohn Fastabend err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
7126f6d33f3SJohn Fastabend (char *)&one, sizeof(one));
7136f6d33f3SJohn Fastabend if (err) {
7146f6d33f3SJohn Fastabend printf("set sock opt\n");
7156f6d33f3SJohn Fastabend goto out;
7166f6d33f3SJohn Fastabend }
7176f6d33f3SJohn Fastabend memset(&addr, 0, sizeof(struct sockaddr_in));
7186f6d33f3SJohn Fastabend addr.sin_family = AF_INET;
7196f6d33f3SJohn Fastabend addr.sin_addr.s_addr = inet_addr("127.0.0.1");
7206f6d33f3SJohn Fastabend addr.sin_port = htons(ports[i - 2]);
7216f6d33f3SJohn Fastabend err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
7226f6d33f3SJohn Fastabend if (err) {
72390774a93SColin Ian King printf("failed to connect\n");
7246f6d33f3SJohn Fastabend goto out;
7256f6d33f3SJohn Fastabend }
7266f6d33f3SJohn Fastabend }
7276f6d33f3SJohn Fastabend
7286f6d33f3SJohn Fastabend
7296f6d33f3SJohn Fastabend for (i = 4; i < 6; i++) {
7306f6d33f3SJohn Fastabend sfd[i] = accept(sfd[i - 4], NULL, NULL);
7316f6d33f3SJohn Fastabend if (sfd[i] < 0) {
7326f6d33f3SJohn Fastabend printf("accept failed\n");
7336f6d33f3SJohn Fastabend goto out;
7346f6d33f3SJohn Fastabend }
7356f6d33f3SJohn Fastabend }
7366f6d33f3SJohn Fastabend
7376f6d33f3SJohn Fastabend /* Test sockmap with connected sockets */
7382fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL,
7396f6d33f3SJohn Fastabend sizeof(key), sizeof(value),
7402fe256a4SAndrii Nakryiko 6, NULL);
7416f6d33f3SJohn Fastabend if (fd < 0) {
74232e608f8SAndrii Nakryiko if (!libbpf_probe_bpf_map_type(BPF_MAP_TYPE_SOCKMAP, NULL)) {
743e8ddbfb4SStanislav Fomichev printf("%s SKIP (unsupported map type BPF_MAP_TYPE_SOCKMAP)\n",
744e8ddbfb4SStanislav Fomichev __func__);
745e8ddbfb4SStanislav Fomichev skips++;
746e8ddbfb4SStanislav Fomichev for (i = 0; i < 6; i++)
747e8ddbfb4SStanislav Fomichev close(sfd[i]);
748e8ddbfb4SStanislav Fomichev return;
749e8ddbfb4SStanislav Fomichev }
750e8ddbfb4SStanislav Fomichev
7516f6d33f3SJohn Fastabend printf("Failed to create sockmap %i\n", fd);
7526f6d33f3SJohn Fastabend goto out_sockmap;
7536f6d33f3SJohn Fastabend }
7546f6d33f3SJohn Fastabend
755435bf0d3SJohn Fastabend /* Test update with unsupported UDP socket */
756435bf0d3SJohn Fastabend udp = socket(AF_INET, SOCK_DGRAM, 0);
757435bf0d3SJohn Fastabend i = 0;
758435bf0d3SJohn Fastabend err = bpf_map_update_elem(fd, &i, &udp, BPF_ANY);
759c39aa215SJohn Fastabend if (err) {
760c39aa215SJohn Fastabend printf("Failed socket update SOCK_DGRAM '%i:%i'\n",
761435bf0d3SJohn Fastabend i, udp);
762435bf0d3SJohn Fastabend goto out_sockmap;
763435bf0d3SJohn Fastabend }
764103d002fSHou Tao close(udp);
765435bf0d3SJohn Fastabend
766464bc0fdSJohn Fastabend /* Test update without programs */
7676f6d33f3SJohn Fastabend for (i = 0; i < 6; i++) {
7686f6d33f3SJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
7698ca30379SJakub Sitnicki if (err) {
770464bc0fdSJohn Fastabend printf("Failed noprog update sockmap '%i:%i'\n",
7716f6d33f3SJohn Fastabend i, sfd[i]);
7726f6d33f3SJohn Fastabend goto out_sockmap;
7736f6d33f3SJohn Fastabend }
7746f6d33f3SJohn Fastabend }
7756f6d33f3SJohn Fastabend
7765a67da2aSJohn Fastabend /* Test attaching/detaching bad fds */
777464bc0fdSJohn Fastabend err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
7786f6d33f3SJohn Fastabend if (!err) {
779464bc0fdSJohn Fastabend printf("Failed invalid parser prog attach\n");
780464bc0fdSJohn Fastabend goto out_sockmap;
781464bc0fdSJohn Fastabend }
782464bc0fdSJohn Fastabend
783464bc0fdSJohn Fastabend err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_VERDICT, 0);
784464bc0fdSJohn Fastabend if (!err) {
785464bc0fdSJohn Fastabend printf("Failed invalid verdict prog attach\n");
7866f6d33f3SJohn Fastabend goto out_sockmap;
7876f6d33f3SJohn Fastabend }
7886f6d33f3SJohn Fastabend
78982a86168SJohn Fastabend err = bpf_prog_attach(-1, fd, BPF_SK_MSG_VERDICT, 0);
79082a86168SJohn Fastabend if (!err) {
79182a86168SJohn Fastabend printf("Failed invalid msg verdict prog attach\n");
79282a86168SJohn Fastabend goto out_sockmap;
79382a86168SJohn Fastabend }
79482a86168SJohn Fastabend
7955a67da2aSJohn Fastabend err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0);
7965a67da2aSJohn Fastabend if (!err) {
7975a67da2aSJohn Fastabend printf("Failed unknown prog attach\n");
7985a67da2aSJohn Fastabend goto out_sockmap;
7995a67da2aSJohn Fastabend }
8005a67da2aSJohn Fastabend
8015a67da2aSJohn Fastabend err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
802f43cb0d6SLorenz Bauer if (!err) {
8035a67da2aSJohn Fastabend printf("Failed empty parser prog detach\n");
8045a67da2aSJohn Fastabend goto out_sockmap;
8055a67da2aSJohn Fastabend }
8065a67da2aSJohn Fastabend
8075a67da2aSJohn Fastabend err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
808f43cb0d6SLorenz Bauer if (!err) {
8095a67da2aSJohn Fastabend printf("Failed empty verdict prog detach\n");
8105a67da2aSJohn Fastabend goto out_sockmap;
8115a67da2aSJohn Fastabend }
8125a67da2aSJohn Fastabend
81382a86168SJohn Fastabend err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT);
814f43cb0d6SLorenz Bauer if (!err) {
81582a86168SJohn Fastabend printf("Failed empty msg verdict prog detach\n");
81682a86168SJohn Fastabend goto out_sockmap;
81782a86168SJohn Fastabend }
81882a86168SJohn Fastabend
8195a67da2aSJohn Fastabend err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE);
8205a67da2aSJohn Fastabend if (!err) {
8215a67da2aSJohn Fastabend printf("Detach invalid prog successful\n");
8225a67da2aSJohn Fastabend goto out_sockmap;
8235a67da2aSJohn Fastabend }
8245a67da2aSJohn Fastabend
8256f6d33f3SJohn Fastabend /* Load SK_SKB program and Attach */
826cbdb1461SAndrii Nakryiko err = bpf_prog_test_load(SOCKMAP_PARSE_PROG,
827103d002fSHou Tao BPF_PROG_TYPE_SK_SKB, &parse_obj, &parse_prog);
8286f6d33f3SJohn Fastabend if (err) {
8296f6d33f3SJohn Fastabend printf("Failed to load SK_SKB parse prog\n");
8306f6d33f3SJohn Fastabend goto out_sockmap;
8316f6d33f3SJohn Fastabend }
8326f6d33f3SJohn Fastabend
833cbdb1461SAndrii Nakryiko err = bpf_prog_test_load(SOCKMAP_TCP_MSG_PROG,
834103d002fSHou Tao BPF_PROG_TYPE_SK_MSG, &msg_obj, &msg_prog);
83582a86168SJohn Fastabend if (err) {
83682a86168SJohn Fastabend printf("Failed to load SK_SKB msg prog\n");
83782a86168SJohn Fastabend goto out_sockmap;
83882a86168SJohn Fastabend }
83982a86168SJohn Fastabend
840cbdb1461SAndrii Nakryiko err = bpf_prog_test_load(SOCKMAP_VERDICT_PROG,
841103d002fSHou Tao BPF_PROG_TYPE_SK_SKB, &verdict_obj, &verdict_prog);
8426f6d33f3SJohn Fastabend if (err) {
8436f6d33f3SJohn Fastabend printf("Failed to load SK_SKB verdict prog\n");
8446f6d33f3SJohn Fastabend goto out_sockmap;
8456f6d33f3SJohn Fastabend }
8466f6d33f3SJohn Fastabend
847103d002fSHou Tao bpf_map_rx = bpf_object__find_map_by_name(verdict_obj, "sock_map_rx");
848bad2e478SAndrii Nakryiko if (!bpf_map_rx) {
8496fd28865SJohn Fastabend printf("Failed to load map rx from verdict prog\n");
8506f6d33f3SJohn Fastabend goto out_sockmap;
8516f6d33f3SJohn Fastabend }
8526f6d33f3SJohn Fastabend
8536fd28865SJohn Fastabend map_fd_rx = bpf_map__fd(bpf_map_rx);
8546fd28865SJohn Fastabend if (map_fd_rx < 0) {
85582a86168SJohn Fastabend printf("Failed to get map rx fd\n");
8566f6d33f3SJohn Fastabend goto out_sockmap;
8576f6d33f3SJohn Fastabend }
8586f6d33f3SJohn Fastabend
859103d002fSHou Tao bpf_map_tx = bpf_object__find_map_by_name(verdict_obj, "sock_map_tx");
860bad2e478SAndrii Nakryiko if (!bpf_map_tx) {
8616fd28865SJohn Fastabend printf("Failed to load map tx from verdict prog\n");
8626fd28865SJohn Fastabend goto out_sockmap;
8636fd28865SJohn Fastabend }
8646fd28865SJohn Fastabend
8656fd28865SJohn Fastabend map_fd_tx = bpf_map__fd(bpf_map_tx);
8666fd28865SJohn Fastabend if (map_fd_tx < 0) {
8676fd28865SJohn Fastabend printf("Failed to get map tx fd\n");
8686fd28865SJohn Fastabend goto out_sockmap;
8696fd28865SJohn Fastabend }
8706fd28865SJohn Fastabend
871103d002fSHou Tao bpf_map_msg = bpf_object__find_map_by_name(verdict_obj, "sock_map_msg");
872bad2e478SAndrii Nakryiko if (!bpf_map_msg) {
87382a86168SJohn Fastabend printf("Failed to load map msg from msg_verdict prog\n");
87482a86168SJohn Fastabend goto out_sockmap;
87582a86168SJohn Fastabend }
87682a86168SJohn Fastabend
87782a86168SJohn Fastabend map_fd_msg = bpf_map__fd(bpf_map_msg);
87882a86168SJohn Fastabend if (map_fd_msg < 0) {
87982a86168SJohn Fastabend printf("Failed to get map msg fd\n");
88082a86168SJohn Fastabend goto out_sockmap;
88182a86168SJohn Fastabend }
88282a86168SJohn Fastabend
883103d002fSHou Tao bpf_map_break = bpf_object__find_map_by_name(verdict_obj, "sock_map_break");
884bad2e478SAndrii Nakryiko if (!bpf_map_break) {
88581374aaaSJohn Fastabend printf("Failed to load map tx from verdict prog\n");
88681374aaaSJohn Fastabend goto out_sockmap;
88781374aaaSJohn Fastabend }
88881374aaaSJohn Fastabend
88981374aaaSJohn Fastabend map_fd_break = bpf_map__fd(bpf_map_break);
89081374aaaSJohn Fastabend if (map_fd_break < 0) {
89181374aaaSJohn Fastabend printf("Failed to get map tx fd\n");
89281374aaaSJohn Fastabend goto out_sockmap;
89381374aaaSJohn Fastabend }
89481374aaaSJohn Fastabend
89581374aaaSJohn Fastabend err = bpf_prog_attach(parse_prog, map_fd_break,
89681374aaaSJohn Fastabend BPF_SK_SKB_STREAM_PARSER, 0);
89781374aaaSJohn Fastabend if (!err) {
89881374aaaSJohn Fastabend printf("Allowed attaching SK_SKB program to invalid map\n");
89981374aaaSJohn Fastabend goto out_sockmap;
90081374aaaSJohn Fastabend }
90181374aaaSJohn Fastabend
9026fd28865SJohn Fastabend err = bpf_prog_attach(parse_prog, map_fd_rx,
903464bc0fdSJohn Fastabend BPF_SK_SKB_STREAM_PARSER, 0);
9046f6d33f3SJohn Fastabend if (err) {
90581374aaaSJohn Fastabend printf("Failed stream parser bpf prog attach\n");
9066f6d33f3SJohn Fastabend goto out_sockmap;
9076f6d33f3SJohn Fastabend }
9086f6d33f3SJohn Fastabend
9096fd28865SJohn Fastabend err = bpf_prog_attach(verdict_prog, map_fd_rx,
910464bc0fdSJohn Fastabend BPF_SK_SKB_STREAM_VERDICT, 0);
911464bc0fdSJohn Fastabend if (err) {
91281374aaaSJohn Fastabend printf("Failed stream verdict bpf prog attach\n");
913464bc0fdSJohn Fastabend goto out_sockmap;
914464bc0fdSJohn Fastabend }
915464bc0fdSJohn Fastabend
91682a86168SJohn Fastabend err = bpf_prog_attach(msg_prog, map_fd_msg, BPF_SK_MSG_VERDICT, 0);
91782a86168SJohn Fastabend if (err) {
91882a86168SJohn Fastabend printf("Failed msg verdict bpf prog attach\n");
91982a86168SJohn Fastabend goto out_sockmap;
92082a86168SJohn Fastabend }
92182a86168SJohn Fastabend
9225a67da2aSJohn Fastabend err = bpf_prog_attach(verdict_prog, map_fd_rx,
9235a67da2aSJohn Fastabend __MAX_BPF_ATTACH_TYPE, 0);
9245a67da2aSJohn Fastabend if (!err) {
9255a67da2aSJohn Fastabend printf("Attached unknown bpf prog\n");
9265a67da2aSJohn Fastabend goto out_sockmap;
9275a67da2aSJohn Fastabend }
9285a67da2aSJohn Fastabend
929464bc0fdSJohn Fastabend /* Test map update elem afterwards fd lives in fd and map_fd */
93050280278SJohn Fastabend for (i = 2; i < 6; i++) {
9316fd28865SJohn Fastabend err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
9326f6d33f3SJohn Fastabend if (err) {
9336fd28865SJohn Fastabend printf("Failed map_fd_rx update sockmap %i '%i:%i'\n",
9346fd28865SJohn Fastabend err, i, sfd[i]);
9356fd28865SJohn Fastabend goto out_sockmap;
9366fd28865SJohn Fastabend }
9376fd28865SJohn Fastabend err = bpf_map_update_elem(map_fd_tx, &i, &sfd[i], BPF_ANY);
9386fd28865SJohn Fastabend if (err) {
9396fd28865SJohn Fastabend printf("Failed map_fd_tx update sockmap %i '%i:%i'\n",
9406f6d33f3SJohn Fastabend err, i, sfd[i]);
9416f6d33f3SJohn Fastabend goto out_sockmap;
9426f6d33f3SJohn Fastabend }
9436f6d33f3SJohn Fastabend }
9446f6d33f3SJohn Fastabend
9456f6d33f3SJohn Fastabend /* Test map delete elem and remove send/recv sockets */
9466f6d33f3SJohn Fastabend for (i = 2; i < 4; i++) {
9476fd28865SJohn Fastabend err = bpf_map_delete_elem(map_fd_rx, &i);
9486f6d33f3SJohn Fastabend if (err) {
9496fd28865SJohn Fastabend printf("Failed delete sockmap rx %i '%i:%i'\n",
9506fd28865SJohn Fastabend err, i, sfd[i]);
9516fd28865SJohn Fastabend goto out_sockmap;
9526fd28865SJohn Fastabend }
9536fd28865SJohn Fastabend err = bpf_map_delete_elem(map_fd_tx, &i);
9546fd28865SJohn Fastabend if (err) {
9556fd28865SJohn Fastabend printf("Failed delete sockmap tx %i '%i:%i'\n",
9566f6d33f3SJohn Fastabend err, i, sfd[i]);
9576f6d33f3SJohn Fastabend goto out_sockmap;
9586f6d33f3SJohn Fastabend }
9596f6d33f3SJohn Fastabend }
9606f6d33f3SJohn Fastabend
96182a86168SJohn Fastabend /* Put sfd[2] (sending fd below) into msg map to test sendmsg bpf */
96282a86168SJohn Fastabend i = 0;
96382a86168SJohn Fastabend err = bpf_map_update_elem(map_fd_msg, &i, &sfd[2], BPF_ANY);
96482a86168SJohn Fastabend if (err) {
96582a86168SJohn Fastabend printf("Failed map_fd_msg update sockmap %i\n", err);
96682a86168SJohn Fastabend goto out_sockmap;
96782a86168SJohn Fastabend }
96882a86168SJohn Fastabend
9696f6d33f3SJohn Fastabend /* Test map send/recv */
9706fd28865SJohn Fastabend for (i = 0; i < 2; i++) {
9716fd28865SJohn Fastabend buf[0] = i;
9726fd28865SJohn Fastabend buf[1] = 0x5;
9736fd28865SJohn Fastabend sc = send(sfd[2], buf, 20, 0);
9746f6d33f3SJohn Fastabend if (sc < 0) {
9756f6d33f3SJohn Fastabend printf("Failed sockmap send\n");
9766f6d33f3SJohn Fastabend goto out_sockmap;
9776f6d33f3SJohn Fastabend }
9786f6d33f3SJohn Fastabend
9796f6d33f3SJohn Fastabend FD_ZERO(&w);
9806f6d33f3SJohn Fastabend FD_SET(sfd[3], &w);
9812d82d73dSLi Zhijian to.tv_sec = 30;
9826f6d33f3SJohn Fastabend to.tv_usec = 0;
9836f6d33f3SJohn Fastabend s = select(sfd[3] + 1, &w, NULL, NULL, &to);
9846f6d33f3SJohn Fastabend if (s == -1) {
9856f6d33f3SJohn Fastabend perror("Failed sockmap select()");
9866f6d33f3SJohn Fastabend goto out_sockmap;
9876f6d33f3SJohn Fastabend } else if (!s) {
9886f6d33f3SJohn Fastabend printf("Failed sockmap unexpected timeout\n");
9896f6d33f3SJohn Fastabend goto out_sockmap;
9906f6d33f3SJohn Fastabend }
9916f6d33f3SJohn Fastabend
9926f6d33f3SJohn Fastabend if (!FD_ISSET(sfd[3], &w)) {
9936f6d33f3SJohn Fastabend printf("Failed sockmap select/recv\n");
9946f6d33f3SJohn Fastabend goto out_sockmap;
9956f6d33f3SJohn Fastabend }
9966f6d33f3SJohn Fastabend
9976f6d33f3SJohn Fastabend rc = recv(sfd[3], buf, sizeof(buf), 0);
9986f6d33f3SJohn Fastabend if (rc < 0) {
9996f6d33f3SJohn Fastabend printf("Failed sockmap recv\n");
10006f6d33f3SJohn Fastabend goto out_sockmap;
10016f6d33f3SJohn Fastabend }
10026fd28865SJohn Fastabend }
10036fd28865SJohn Fastabend
10046fd28865SJohn Fastabend /* Negative null entry lookup from datapath should be dropped */
10056fd28865SJohn Fastabend buf[0] = 1;
10066fd28865SJohn Fastabend buf[1] = 12;
10076fd28865SJohn Fastabend sc = send(sfd[2], buf, 20, 0);
10086fd28865SJohn Fastabend if (sc < 0) {
10096fd28865SJohn Fastabend printf("Failed sockmap send\n");
10106fd28865SJohn Fastabend goto out_sockmap;
10116fd28865SJohn Fastabend }
10126f6d33f3SJohn Fastabend
1013464bc0fdSJohn Fastabend /* Push fd into same slot */
10146f6d33f3SJohn Fastabend i = 2;
10156f6d33f3SJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
10166f6d33f3SJohn Fastabend if (!err) {
1017464bc0fdSJohn Fastabend printf("Failed allowed sockmap dup slot BPF_NOEXIST\n");
10186f6d33f3SJohn Fastabend goto out_sockmap;
10196f6d33f3SJohn Fastabend }
10206f6d33f3SJohn Fastabend
10216f6d33f3SJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
10226f6d33f3SJohn Fastabend if (err) {
1023464bc0fdSJohn Fastabend printf("Failed sockmap update new slot BPF_ANY\n");
10246f6d33f3SJohn Fastabend goto out_sockmap;
10256f6d33f3SJohn Fastabend }
10266f6d33f3SJohn Fastabend
10276f6d33f3SJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
10286f6d33f3SJohn Fastabend if (err) {
1029464bc0fdSJohn Fastabend printf("Failed sockmap update new slot BPF_EXIST\n");
10306f6d33f3SJohn Fastabend goto out_sockmap;
10316f6d33f3SJohn Fastabend }
10326f6d33f3SJohn Fastabend
1033464bc0fdSJohn Fastabend /* Delete the elems without programs */
103450280278SJohn Fastabend for (i = 2; i < 6; i++) {
1035464bc0fdSJohn Fastabend err = bpf_map_delete_elem(fd, &i);
1036464bc0fdSJohn Fastabend if (err) {
1037464bc0fdSJohn Fastabend printf("Failed delete sockmap %i '%i:%i'\n",
1038464bc0fdSJohn Fastabend err, i, sfd[i]);
1039464bc0fdSJohn Fastabend }
1040464bc0fdSJohn Fastabend }
1041464bc0fdSJohn Fastabend
1042464bc0fdSJohn Fastabend /* Test having multiple maps open and set with programs on same fds */
1043464bc0fdSJohn Fastabend err = bpf_prog_attach(parse_prog, fd,
1044464bc0fdSJohn Fastabend BPF_SK_SKB_STREAM_PARSER, 0);
1045464bc0fdSJohn Fastabend if (err) {
1046464bc0fdSJohn Fastabend printf("Failed fd bpf parse prog attach\n");
1047464bc0fdSJohn Fastabend goto out_sockmap;
1048464bc0fdSJohn Fastabend }
1049464bc0fdSJohn Fastabend err = bpf_prog_attach(verdict_prog, fd,
1050464bc0fdSJohn Fastabend BPF_SK_SKB_STREAM_VERDICT, 0);
1051464bc0fdSJohn Fastabend if (err) {
1052464bc0fdSJohn Fastabend printf("Failed fd bpf verdict prog attach\n");
10536f6d33f3SJohn Fastabend goto out_sockmap;
10546f6d33f3SJohn Fastabend }
10556f6d33f3SJohn Fastabend
1056464bc0fdSJohn Fastabend for (i = 4; i < 6; i++) {
1057464bc0fdSJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
10586f6d33f3SJohn Fastabend if (!err) {
1059464bc0fdSJohn Fastabend printf("Failed allowed duplicate programs in update ANY sockmap %i '%i:%i'\n",
1060464bc0fdSJohn Fastabend err, i, sfd[i]);
10616f6d33f3SJohn Fastabend goto out_sockmap;
10626f6d33f3SJohn Fastabend }
1063464bc0fdSJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
10646f6d33f3SJohn Fastabend if (!err) {
1065464bc0fdSJohn Fastabend printf("Failed allowed duplicate program in update NOEXIST sockmap %i '%i:%i'\n",
1066464bc0fdSJohn Fastabend err, i, sfd[i]);
10676f6d33f3SJohn Fastabend goto out_sockmap;
10686f6d33f3SJohn Fastabend }
1069464bc0fdSJohn Fastabend err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
1070464bc0fdSJohn Fastabend if (!err) {
1071464bc0fdSJohn Fastabend printf("Failed allowed duplicate program in update EXIST sockmap %i '%i:%i'\n",
1072464bc0fdSJohn Fastabend err, i, sfd[i]);
1073464bc0fdSJohn Fastabend goto out_sockmap;
1074464bc0fdSJohn Fastabend }
1075464bc0fdSJohn Fastabend }
10766f6d33f3SJohn Fastabend
10773f0d6a16SJohn Fastabend /* Test tasks number of forked operations */
10783f0d6a16SJohn Fastabend for (i = 0; i < tasks; i++) {
10793f0d6a16SJohn Fastabend pid[i] = fork();
10803f0d6a16SJohn Fastabend if (pid[i] == 0) {
10813f0d6a16SJohn Fastabend for (i = 0; i < 6; i++) {
10823f0d6a16SJohn Fastabend bpf_map_delete_elem(map_fd_tx, &i);
10833f0d6a16SJohn Fastabend bpf_map_delete_elem(map_fd_rx, &i);
10843f0d6a16SJohn Fastabend bpf_map_update_elem(map_fd_tx, &i,
10853f0d6a16SJohn Fastabend &sfd[i], BPF_ANY);
10863f0d6a16SJohn Fastabend bpf_map_update_elem(map_fd_rx, &i,
10873f0d6a16SJohn Fastabend &sfd[i], BPF_ANY);
10883f0d6a16SJohn Fastabend }
10893f0d6a16SJohn Fastabend exit(0);
10903f0d6a16SJohn Fastabend } else if (pid[i] == -1) {
10913f0d6a16SJohn Fastabend printf("Couldn't spawn #%d process!\n", i);
10923f0d6a16SJohn Fastabend exit(1);
10933f0d6a16SJohn Fastabend }
10943f0d6a16SJohn Fastabend }
10953f0d6a16SJohn Fastabend
10963f0d6a16SJohn Fastabend for (i = 0; i < tasks; i++) {
10973f0d6a16SJohn Fastabend int status;
10983f0d6a16SJohn Fastabend
10993f0d6a16SJohn Fastabend assert(waitpid(pid[i], &status, 0) == pid[i]);
11003f0d6a16SJohn Fastabend assert(status == 0);
11013f0d6a16SJohn Fastabend }
11023f0d6a16SJohn Fastabend
1103f43cb0d6SLorenz Bauer err = bpf_prog_detach2(parse_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE);
11045a67da2aSJohn Fastabend if (!err) {
11055a67da2aSJohn Fastabend printf("Detached an invalid prog type.\n");
11065a67da2aSJohn Fastabend goto out_sockmap;
11075a67da2aSJohn Fastabend }
11085a67da2aSJohn Fastabend
1109f43cb0d6SLorenz Bauer err = bpf_prog_detach2(parse_prog, map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
11105a67da2aSJohn Fastabend if (err) {
11115a67da2aSJohn Fastabend printf("Failed parser prog detach\n");
11125a67da2aSJohn Fastabend goto out_sockmap;
11135a67da2aSJohn Fastabend }
11145a67da2aSJohn Fastabend
1115f43cb0d6SLorenz Bauer err = bpf_prog_detach2(verdict_prog, map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
11165a67da2aSJohn Fastabend if (err) {
11175a67da2aSJohn Fastabend printf("Failed parser prog detach\n");
11185a67da2aSJohn Fastabend goto out_sockmap;
11195a67da2aSJohn Fastabend }
11205a67da2aSJohn Fastabend
112178368781SPrashant Bhole /* Test map close sockets and empty maps */
112278368781SPrashant Bhole for (i = 0; i < 6; i++) {
112378368781SPrashant Bhole bpf_map_delete_elem(map_fd_tx, &i);
112478368781SPrashant Bhole bpf_map_delete_elem(map_fd_rx, &i);
11256f6d33f3SJohn Fastabend close(sfd[i]);
112678368781SPrashant Bhole }
11276f6d33f3SJohn Fastabend close(fd);
11286fd28865SJohn Fastabend close(map_fd_rx);
1129103d002fSHou Tao bpf_object__close(parse_obj);
1130103d002fSHou Tao bpf_object__close(msg_obj);
1131103d002fSHou Tao bpf_object__close(verdict_obj);
11326f6d33f3SJohn Fastabend return;
11336f6d33f3SJohn Fastabend out:
11346f6d33f3SJohn Fastabend for (i = 0; i < 6; i++)
11356f6d33f3SJohn Fastabend close(sfd[i]);
11366f6d33f3SJohn Fastabend printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno));
11376f6d33f3SJohn Fastabend exit(1);
11386f6d33f3SJohn Fastabend out_sockmap:
113978368781SPrashant Bhole for (i = 0; i < 6; i++) {
114078368781SPrashant Bhole if (map_fd_tx)
114178368781SPrashant Bhole bpf_map_delete_elem(map_fd_tx, &i);
114278368781SPrashant Bhole if (map_fd_rx)
114378368781SPrashant Bhole bpf_map_delete_elem(map_fd_rx, &i);
11446f6d33f3SJohn Fastabend close(sfd[i]);
114578368781SPrashant Bhole }
11466f6d33f3SJohn Fastabend close(fd);
11476f6d33f3SJohn Fastabend exit(1);
11486f6d33f3SJohn Fastabend }
11496f6d33f3SJohn Fastabend
1150afef88e6SDaniel Müller #define MAPINMAP_PROG "./test_map_in_map.bpf.o"
1151afef88e6SDaniel Müller #define MAPINMAP_INVALID_PROG "./test_map_in_map_invalid.bpf.o"
test_map_in_map(void)1152b1957c92SNikita V. Shirokov static void test_map_in_map(void)
1153b1957c92SNikita V. Shirokov {
1154b1957c92SNikita V. Shirokov struct bpf_object *obj;
1155b1957c92SNikita V. Shirokov struct bpf_map *map;
1156b1957c92SNikita V. Shirokov int mim_fd, fd, err;
1157b1957c92SNikita V. Shirokov int pos = 0;
115808f71a1eSMartynas Pumputis struct bpf_map_info info = {};
115908f71a1eSMartynas Pumputis __u32 len = sizeof(info);
116008f71a1eSMartynas Pumputis __u32 id = 0;
11619907442fSMartynas Pumputis libbpf_print_fn_t old_print_fn;
1162b1957c92SNikita V. Shirokov
1163b1957c92SNikita V. Shirokov obj = bpf_object__open(MAPINMAP_PROG);
1164b1957c92SNikita V. Shirokov
11652fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(int), sizeof(int), 2, NULL);
1166b1957c92SNikita V. Shirokov if (fd < 0) {
1167b1957c92SNikita V. Shirokov printf("Failed to create hashmap '%s'!\n", strerror(errno));
1168b1957c92SNikita V. Shirokov exit(1);
1169b1957c92SNikita V. Shirokov }
1170b1957c92SNikita V. Shirokov
1171b1957c92SNikita V. Shirokov map = bpf_object__find_map_by_name(obj, "mim_array");
1172bad2e478SAndrii Nakryiko if (!map) {
1173b1957c92SNikita V. Shirokov printf("Failed to load array of maps from test prog\n");
1174b1957c92SNikita V. Shirokov goto out_map_in_map;
1175b1957c92SNikita V. Shirokov }
1176b1957c92SNikita V. Shirokov err = bpf_map__set_inner_map_fd(map, fd);
1177b1957c92SNikita V. Shirokov if (err) {
1178b1957c92SNikita V. Shirokov printf("Failed to set inner_map_fd for array of maps\n");
1179b1957c92SNikita V. Shirokov goto out_map_in_map;
1180b1957c92SNikita V. Shirokov }
1181b1957c92SNikita V. Shirokov
1182b1957c92SNikita V. Shirokov map = bpf_object__find_map_by_name(obj, "mim_hash");
1183bad2e478SAndrii Nakryiko if (!map) {
1184b1957c92SNikita V. Shirokov printf("Failed to load hash of maps from test prog\n");
1185b1957c92SNikita V. Shirokov goto out_map_in_map;
1186b1957c92SNikita V. Shirokov }
1187b1957c92SNikita V. Shirokov err = bpf_map__set_inner_map_fd(map, fd);
1188b1957c92SNikita V. Shirokov if (err) {
1189b1957c92SNikita V. Shirokov printf("Failed to set inner_map_fd for hash of maps\n");
1190b1957c92SNikita V. Shirokov goto out_map_in_map;
1191b1957c92SNikita V. Shirokov }
1192b1957c92SNikita V. Shirokov
1193*fb9f3f36SAndrey Grafin err = bpf_object__load(obj);
1194*fb9f3f36SAndrey Grafin if (err) {
1195*fb9f3f36SAndrey Grafin printf("Failed to load test prog\n");
1196*fb9f3f36SAndrey Grafin goto out_map_in_map;
1197*fb9f3f36SAndrey Grafin }
1198b1957c92SNikita V. Shirokov
1199b1957c92SNikita V. Shirokov map = bpf_object__find_map_by_name(obj, "mim_array");
1200bad2e478SAndrii Nakryiko if (!map) {
1201b1957c92SNikita V. Shirokov printf("Failed to load array of maps from test prog\n");
1202b1957c92SNikita V. Shirokov goto out_map_in_map;
1203b1957c92SNikita V. Shirokov }
1204b1957c92SNikita V. Shirokov mim_fd = bpf_map__fd(map);
1205b1957c92SNikita V. Shirokov if (mim_fd < 0) {
1206b1957c92SNikita V. Shirokov printf("Failed to get descriptor for array of maps\n");
1207b1957c92SNikita V. Shirokov goto out_map_in_map;
1208b1957c92SNikita V. Shirokov }
1209b1957c92SNikita V. Shirokov
1210b1957c92SNikita V. Shirokov err = bpf_map_update_elem(mim_fd, &pos, &fd, 0);
1211b1957c92SNikita V. Shirokov if (err) {
1212b1957c92SNikita V. Shirokov printf("Failed to update array of maps\n");
1213b1957c92SNikita V. Shirokov goto out_map_in_map;
1214b1957c92SNikita V. Shirokov }
1215b1957c92SNikita V. Shirokov
1216b1957c92SNikita V. Shirokov map = bpf_object__find_map_by_name(obj, "mim_hash");
1217bad2e478SAndrii Nakryiko if (!map) {
1218b1957c92SNikita V. Shirokov printf("Failed to load hash of maps from test prog\n");
1219b1957c92SNikita V. Shirokov goto out_map_in_map;
1220b1957c92SNikita V. Shirokov }
1221b1957c92SNikita V. Shirokov mim_fd = bpf_map__fd(map);
1222b1957c92SNikita V. Shirokov if (mim_fd < 0) {
1223b1957c92SNikita V. Shirokov printf("Failed to get descriptor for hash of maps\n");
1224b1957c92SNikita V. Shirokov goto out_map_in_map;
1225b1957c92SNikita V. Shirokov }
1226b1957c92SNikita V. Shirokov
1227b1957c92SNikita V. Shirokov err = bpf_map_update_elem(mim_fd, &pos, &fd, 0);
1228b1957c92SNikita V. Shirokov if (err) {
1229b1957c92SNikita V. Shirokov printf("Failed to update hash of maps\n");
1230b1957c92SNikita V. Shirokov goto out_map_in_map;
1231b1957c92SNikita V. Shirokov }
1232b1957c92SNikita V. Shirokov
1233b1957c92SNikita V. Shirokov close(fd);
123408f71a1eSMartynas Pumputis fd = -1;
1235b1957c92SNikita V. Shirokov bpf_object__close(obj);
123608f71a1eSMartynas Pumputis
123708f71a1eSMartynas Pumputis /* Test that failing bpf_object__create_map() destroys the inner map */
123808f71a1eSMartynas Pumputis obj = bpf_object__open(MAPINMAP_INVALID_PROG);
123908f71a1eSMartynas Pumputis err = libbpf_get_error(obj);
124008f71a1eSMartynas Pumputis if (err) {
124108f71a1eSMartynas Pumputis printf("Failed to load %s program: %d %d",
124208f71a1eSMartynas Pumputis MAPINMAP_INVALID_PROG, err, errno);
124308f71a1eSMartynas Pumputis goto out_map_in_map;
124408f71a1eSMartynas Pumputis }
124508f71a1eSMartynas Pumputis
124608f71a1eSMartynas Pumputis map = bpf_object__find_map_by_name(obj, "mim");
124708f71a1eSMartynas Pumputis if (!map) {
124808f71a1eSMartynas Pumputis printf("Failed to load array of maps from test prog\n");
124908f71a1eSMartynas Pumputis goto out_map_in_map;
125008f71a1eSMartynas Pumputis }
125108f71a1eSMartynas Pumputis
12529907442fSMartynas Pumputis old_print_fn = libbpf_set_print(NULL);
12539907442fSMartynas Pumputis
125408f71a1eSMartynas Pumputis err = bpf_object__load(obj);
125508f71a1eSMartynas Pumputis if (!err) {
125608f71a1eSMartynas Pumputis printf("Loading obj supposed to fail\n");
125708f71a1eSMartynas Pumputis goto out_map_in_map;
125808f71a1eSMartynas Pumputis }
125908f71a1eSMartynas Pumputis
12609907442fSMartynas Pumputis libbpf_set_print(old_print_fn);
12619907442fSMartynas Pumputis
126208f71a1eSMartynas Pumputis /* Iterate over all maps to check whether the internal map
126308f71a1eSMartynas Pumputis * ("mim.internal") has been destroyed.
126408f71a1eSMartynas Pumputis */
126508f71a1eSMartynas Pumputis while (true) {
126608f71a1eSMartynas Pumputis err = bpf_map_get_next_id(id, &id);
126708f71a1eSMartynas Pumputis if (err) {
126808f71a1eSMartynas Pumputis if (errno == ENOENT)
126908f71a1eSMartynas Pumputis break;
127008f71a1eSMartynas Pumputis printf("Failed to get next map: %d", errno);
127108f71a1eSMartynas Pumputis goto out_map_in_map;
127208f71a1eSMartynas Pumputis }
127308f71a1eSMartynas Pumputis
127408f71a1eSMartynas Pumputis fd = bpf_map_get_fd_by_id(id);
127508f71a1eSMartynas Pumputis if (fd < 0) {
127608f71a1eSMartynas Pumputis if (errno == ENOENT)
127708f71a1eSMartynas Pumputis continue;
127808f71a1eSMartynas Pumputis printf("Failed to get map by id %u: %d", id, errno);
127908f71a1eSMartynas Pumputis goto out_map_in_map;
128008f71a1eSMartynas Pumputis }
128108f71a1eSMartynas Pumputis
1282c5a237a4SIlya Leoshkevich err = bpf_map_get_info_by_fd(fd, &info, &len);
128308f71a1eSMartynas Pumputis if (err) {
128408f71a1eSMartynas Pumputis printf("Failed to get map info by fd %d: %d", fd,
128508f71a1eSMartynas Pumputis errno);
128608f71a1eSMartynas Pumputis goto out_map_in_map;
128708f71a1eSMartynas Pumputis }
128808f71a1eSMartynas Pumputis
128908f71a1eSMartynas Pumputis if (!strcmp(info.name, "mim.inner")) {
129008f71a1eSMartynas Pumputis printf("Inner map mim.inner was not destroyed\n");
129108f71a1eSMartynas Pumputis goto out_map_in_map;
129208f71a1eSMartynas Pumputis }
1293103d002fSHou Tao
1294103d002fSHou Tao close(fd);
129508f71a1eSMartynas Pumputis }
129608f71a1eSMartynas Pumputis
1297103d002fSHou Tao bpf_object__close(obj);
1298b1957c92SNikita V. Shirokov return;
1299b1957c92SNikita V. Shirokov
1300b1957c92SNikita V. Shirokov out_map_in_map:
130108f71a1eSMartynas Pumputis if (fd >= 0)
1302b1957c92SNikita V. Shirokov close(fd);
1303b1957c92SNikita V. Shirokov exit(1);
1304b1957c92SNikita V. Shirokov }
1305b1957c92SNikita V. Shirokov
13065aa5bd14SDaniel Borkmann #define MAP_SIZE (32 * 1024)
13075aa5bd14SDaniel Borkmann
test_map_large(void)13085aa5bd14SDaniel Borkmann static void test_map_large(void)
13095aa5bd14SDaniel Borkmann {
1310c6bde958SFlorian Lehner
13115aa5bd14SDaniel Borkmann struct bigkey {
13125aa5bd14SDaniel Borkmann int a;
1313c6bde958SFlorian Lehner char b[4096];
13145aa5bd14SDaniel Borkmann long long c;
13155aa5bd14SDaniel Borkmann } key;
13165aa5bd14SDaniel Borkmann int fd, i, value;
13175aa5bd14SDaniel Borkmann
13182fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
13192fe256a4SAndrii Nakryiko MAP_SIZE, &map_opts);
13205aa5bd14SDaniel Borkmann if (fd < 0) {
13215aa5bd14SDaniel Borkmann printf("Failed to create large map '%s'!\n", strerror(errno));
13225aa5bd14SDaniel Borkmann exit(1);
13235aa5bd14SDaniel Borkmann }
13245aa5bd14SDaniel Borkmann
13255aa5bd14SDaniel Borkmann for (i = 0; i < MAP_SIZE; i++) {
13265aa5bd14SDaniel Borkmann key = (struct bigkey) { .c = i };
13275aa5bd14SDaniel Borkmann value = i;
13285aa5bd14SDaniel Borkmann
132910ecc728SMickaël Salaün assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
13305aa5bd14SDaniel Borkmann }
13315aa5bd14SDaniel Borkmann
13325aa5bd14SDaniel Borkmann key.c = -1;
1333bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
13345aa5bd14SDaniel Borkmann errno == E2BIG);
13355aa5bd14SDaniel Borkmann
13365aa5bd14SDaniel Borkmann /* Iterate through all elements. */
13378fe45924STeng Qin assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
13388fe45924STeng Qin key.c = -1;
13395aa5bd14SDaniel Borkmann for (i = 0; i < MAP_SIZE; i++)
13405f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &key, &key) == 0);
1341bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
13425aa5bd14SDaniel Borkmann
13435aa5bd14SDaniel Borkmann key.c = 0;
1344e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
13455aa5bd14SDaniel Borkmann key.a = 1;
1346bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
13475aa5bd14SDaniel Borkmann
13485aa5bd14SDaniel Borkmann close(fd);
13495aa5bd14SDaniel Borkmann }
13505aa5bd14SDaniel Borkmann
13511a97cf1fSAlexei Starovoitov #define run_parallel(N, FN, DATA) \
1352dd9cef43SBreno Leitao printf("Fork %u tasks to '" #FN "'\n", N); \
13531a97cf1fSAlexei Starovoitov __run_parallel(N, FN, DATA)
13541a97cf1fSAlexei Starovoitov
__run_parallel(unsigned int tasks,void (* fn)(unsigned int task,void * data),void * data)1355dd9cef43SBreno Leitao static void __run_parallel(unsigned int tasks,
1356dd9cef43SBreno Leitao void (*fn)(unsigned int task, void *data),
13575aa5bd14SDaniel Borkmann void *data)
13585aa5bd14SDaniel Borkmann {
13595aa5bd14SDaniel Borkmann pid_t pid[tasks];
13605aa5bd14SDaniel Borkmann int i;
13615aa5bd14SDaniel Borkmann
1362fa450567SJesper Dangaard Brouer fflush(stdout);
1363fa450567SJesper Dangaard Brouer
13645aa5bd14SDaniel Borkmann for (i = 0; i < tasks; i++) {
13655aa5bd14SDaniel Borkmann pid[i] = fork();
13665aa5bd14SDaniel Borkmann if (pid[i] == 0) {
13675aa5bd14SDaniel Borkmann fn(i, data);
13685aa5bd14SDaniel Borkmann exit(0);
13695aa5bd14SDaniel Borkmann } else if (pid[i] == -1) {
13705aa5bd14SDaniel Borkmann printf("Couldn't spawn #%d process!\n", i);
13715aa5bd14SDaniel Borkmann exit(1);
13725aa5bd14SDaniel Borkmann }
13735aa5bd14SDaniel Borkmann }
13745aa5bd14SDaniel Borkmann
13755aa5bd14SDaniel Borkmann for (i = 0; i < tasks; i++) {
13765aa5bd14SDaniel Borkmann int status;
13775aa5bd14SDaniel Borkmann
13785aa5bd14SDaniel Borkmann assert(waitpid(pid[i], &status, 0) == pid[i]);
13795aa5bd14SDaniel Borkmann assert(status == 0);
13805aa5bd14SDaniel Borkmann }
13815aa5bd14SDaniel Borkmann }
13825aa5bd14SDaniel Borkmann
test_map_stress(void)13835aa5bd14SDaniel Borkmann static void test_map_stress(void)
13845aa5bd14SDaniel Borkmann {
138537521bffSAlexei Starovoitov run_parallel(100, test_hashmap_walk, NULL);
13865aa5bd14SDaniel Borkmann run_parallel(100, test_hashmap, NULL);
13875aa5bd14SDaniel Borkmann run_parallel(100, test_hashmap_percpu, NULL);
13888c290e60SAlexei Starovoitov run_parallel(100, test_hashmap_sizes, NULL);
13895aa5bd14SDaniel Borkmann
13905aa5bd14SDaniel Borkmann run_parallel(100, test_arraymap, NULL);
13915aa5bd14SDaniel Borkmann run_parallel(100, test_arraymap_percpu, NULL);
13925aa5bd14SDaniel Borkmann }
13935aa5bd14SDaniel Borkmann
139437521bffSAlexei Starovoitov #define TASKS 100
13955aa5bd14SDaniel Borkmann
13965aa5bd14SDaniel Borkmann #define DO_UPDATE 1
13975aa5bd14SDaniel Borkmann #define DO_DELETE 0
13985aa5bd14SDaniel Borkmann
139911b844b0SAndrii Nakryiko #define MAP_RETRIES 20
14003c3bd542SYucong Sun #define MAX_DELAY_US 50000
14013c3bd542SYucong Sun #define MIN_DELAY_RANGE_US 5000
140211b844b0SAndrii Nakryiko
map_update_retriable(int map_fd,const void * key,const void * value,int flags,int attempts)140311b844b0SAndrii Nakryiko static int map_update_retriable(int map_fd, const void *key, const void *value,
140411b844b0SAndrii Nakryiko int flags, int attempts)
140511b844b0SAndrii Nakryiko {
14063c3bd542SYucong Sun int delay = rand() % MIN_DELAY_RANGE_US;
14073c3bd542SYucong Sun
140811b844b0SAndrii Nakryiko while (bpf_map_update_elem(map_fd, key, value, flags)) {
140911b844b0SAndrii Nakryiko if (!attempts || (errno != EAGAIN && errno != EBUSY))
141011b844b0SAndrii Nakryiko return -errno;
141111b844b0SAndrii Nakryiko
14123c3bd542SYucong Sun if (delay <= MAX_DELAY_US / 2)
14133c3bd542SYucong Sun delay *= 2;
14143c3bd542SYucong Sun
14153c3bd542SYucong Sun usleep(delay);
141611b844b0SAndrii Nakryiko attempts--;
141711b844b0SAndrii Nakryiko }
141811b844b0SAndrii Nakryiko
141911b844b0SAndrii Nakryiko return 0;
142011b844b0SAndrii Nakryiko }
142111b844b0SAndrii Nakryiko
map_delete_retriable(int map_fd,const void * key,int attempts)142211b844b0SAndrii Nakryiko static int map_delete_retriable(int map_fd, const void *key, int attempts)
142311b844b0SAndrii Nakryiko {
1424857f75eaSYucong Sun int delay = rand() % MIN_DELAY_RANGE_US;
1425857f75eaSYucong Sun
142611b844b0SAndrii Nakryiko while (bpf_map_delete_elem(map_fd, key)) {
142711b844b0SAndrii Nakryiko if (!attempts || (errno != EAGAIN && errno != EBUSY))
142811b844b0SAndrii Nakryiko return -errno;
142911b844b0SAndrii Nakryiko
1430857f75eaSYucong Sun if (delay <= MAX_DELAY_US / 2)
1431857f75eaSYucong Sun delay *= 2;
1432857f75eaSYucong Sun
1433857f75eaSYucong Sun usleep(delay);
143411b844b0SAndrii Nakryiko attempts--;
143511b844b0SAndrii Nakryiko }
143611b844b0SAndrii Nakryiko
143711b844b0SAndrii Nakryiko return 0;
143811b844b0SAndrii Nakryiko }
143911b844b0SAndrii Nakryiko
test_update_delete(unsigned int fn,void * data)1440dd9cef43SBreno Leitao static void test_update_delete(unsigned int fn, void *data)
14415aa5bd14SDaniel Borkmann {
14425aa5bd14SDaniel Borkmann int do_update = ((int *)data)[1];
14435aa5bd14SDaniel Borkmann int fd = ((int *)data)[0];
144411b844b0SAndrii Nakryiko int i, key, value, err;
14455aa5bd14SDaniel Borkmann
144637521bffSAlexei Starovoitov if (fn & 1)
144737521bffSAlexei Starovoitov test_hashmap_walk(fn, NULL);
14485aa5bd14SDaniel Borkmann for (i = fn; i < MAP_SIZE; i += TASKS) {
14495aa5bd14SDaniel Borkmann key = value = i;
14505aa5bd14SDaniel Borkmann
14515aa5bd14SDaniel Borkmann if (do_update) {
145211b844b0SAndrii Nakryiko err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES);
145311b844b0SAndrii Nakryiko if (err)
145411b844b0SAndrii Nakryiko printf("error %d %d\n", err, errno);
145511b844b0SAndrii Nakryiko assert(err == 0);
145611b844b0SAndrii Nakryiko err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES);
145711b844b0SAndrii Nakryiko if (err)
145811b844b0SAndrii Nakryiko printf("error %d %d\n", err, errno);
145911b844b0SAndrii Nakryiko assert(err == 0);
14605aa5bd14SDaniel Borkmann } else {
146111b844b0SAndrii Nakryiko err = map_delete_retriable(fd, &key, MAP_RETRIES);
146211b844b0SAndrii Nakryiko if (err)
146311b844b0SAndrii Nakryiko printf("error %d %d\n", err, errno);
146411b844b0SAndrii Nakryiko assert(err == 0);
14655aa5bd14SDaniel Borkmann }
14665aa5bd14SDaniel Borkmann }
14675aa5bd14SDaniel Borkmann }
14685aa5bd14SDaniel Borkmann
test_map_parallel(void)14695aa5bd14SDaniel Borkmann static void test_map_parallel(void)
14705aa5bd14SDaniel Borkmann {
147137521bffSAlexei Starovoitov int i, fd, key = 0, value = 0, j = 0;
14725aa5bd14SDaniel Borkmann int data[2];
14735aa5bd14SDaniel Borkmann
14742fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
14752fe256a4SAndrii Nakryiko MAP_SIZE, &map_opts);
14765aa5bd14SDaniel Borkmann if (fd < 0) {
14775aa5bd14SDaniel Borkmann printf("Failed to create map for parallel test '%s'!\n",
14785aa5bd14SDaniel Borkmann strerror(errno));
14795aa5bd14SDaniel Borkmann exit(1);
14805aa5bd14SDaniel Borkmann }
14815aa5bd14SDaniel Borkmann
148237521bffSAlexei Starovoitov again:
14835aa5bd14SDaniel Borkmann /* Use the same fd in children to add elements to this map:
14845aa5bd14SDaniel Borkmann * child_0 adds key=0, key=1024, key=2048, ...
14855aa5bd14SDaniel Borkmann * child_1 adds key=1, key=1025, key=2049, ...
14865aa5bd14SDaniel Borkmann * child_1023 adds key=1023, ...
14875aa5bd14SDaniel Borkmann */
14885aa5bd14SDaniel Borkmann data[0] = fd;
14895aa5bd14SDaniel Borkmann data[1] = DO_UPDATE;
14901a97cf1fSAlexei Starovoitov run_parallel(TASKS, test_update_delete, data);
14915aa5bd14SDaniel Borkmann
14925aa5bd14SDaniel Borkmann /* Check that key=0 is already there. */
1493bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
14945aa5bd14SDaniel Borkmann errno == EEXIST);
14955aa5bd14SDaniel Borkmann
14965aa5bd14SDaniel Borkmann /* Check that all elements were inserted. */
14978fe45924STeng Qin assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
14985aa5bd14SDaniel Borkmann key = -1;
14995aa5bd14SDaniel Borkmann for (i = 0; i < MAP_SIZE; i++)
15005f155c25SMickaël Salaün assert(bpf_map_get_next_key(fd, &key, &key) == 0);
1501bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
15025aa5bd14SDaniel Borkmann
15035aa5bd14SDaniel Borkmann /* Another check for all elements */
15045aa5bd14SDaniel Borkmann for (i = 0; i < MAP_SIZE; i++) {
15055aa5bd14SDaniel Borkmann key = MAP_SIZE - i - 1;
15065aa5bd14SDaniel Borkmann
1507e5ff7c40SMickaël Salaün assert(bpf_map_lookup_elem(fd, &key, &value) == 0 &&
15085aa5bd14SDaniel Borkmann value == key);
15095aa5bd14SDaniel Borkmann }
15105aa5bd14SDaniel Borkmann
15115aa5bd14SDaniel Borkmann /* Now let's delete all elemenets in parallel. */
15125aa5bd14SDaniel Borkmann data[1] = DO_DELETE;
15131a97cf1fSAlexei Starovoitov run_parallel(TASKS, test_update_delete, data);
15145aa5bd14SDaniel Borkmann
15155aa5bd14SDaniel Borkmann /* Nothing should be left. */
15165aa5bd14SDaniel Borkmann key = -1;
1517bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, NULL, &key) < 0 && errno == ENOENT);
1518bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
151937521bffSAlexei Starovoitov
152037521bffSAlexei Starovoitov key = 0;
152137521bffSAlexei Starovoitov bpf_map_delete_elem(fd, &key);
152237521bffSAlexei Starovoitov if (j++ < 5)
152337521bffSAlexei Starovoitov goto again;
152437521bffSAlexei Starovoitov close(fd);
15255aa5bd14SDaniel Borkmann }
15265aa5bd14SDaniel Borkmann
test_map_rdonly(void)1527e043325bSChenbo Feng static void test_map_rdonly(void)
1528e043325bSChenbo Feng {
1529e27afb84SAlexei Starovoitov int fd, key = 0, value = 0;
15302fe256a4SAndrii Nakryiko __u32 old_flags;
1531e043325bSChenbo Feng
15322fe256a4SAndrii Nakryiko old_flags = map_opts.map_flags;
15332fe256a4SAndrii Nakryiko map_opts.map_flags |= BPF_F_RDONLY;
15342fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
15352fe256a4SAndrii Nakryiko MAP_SIZE, &map_opts);
15362fe256a4SAndrii Nakryiko map_opts.map_flags = old_flags;
1537e043325bSChenbo Feng if (fd < 0) {
1538e043325bSChenbo Feng printf("Failed to create map for read only test '%s'!\n",
1539e043325bSChenbo Feng strerror(errno));
1540e043325bSChenbo Feng exit(1);
1541e043325bSChenbo Feng }
1542e043325bSChenbo Feng
1543e043325bSChenbo Feng key = 1;
1544e043325bSChenbo Feng value = 1234;
1545efbc3b8fSAnton Protopopov /* Try to insert key=1 element. */
1546bad2e478SAndrii Nakryiko assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) < 0 &&
1547e043325bSChenbo Feng errno == EPERM);
1548e043325bSChenbo Feng
1549efbc3b8fSAnton Protopopov /* Check that key=1 is not found. */
1550bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
1551bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &value) < 0 && errno == ENOENT);
155236ef9a2dSAnton Protopopov
155336ef9a2dSAnton Protopopov close(fd);
1554e043325bSChenbo Feng }
1555e043325bSChenbo Feng
test_map_wronly_hash(void)155643dd115bSAnton Protopopov static void test_map_wronly_hash(void)
1557e043325bSChenbo Feng {
1558e27afb84SAlexei Starovoitov int fd, key = 0, value = 0;
15592fe256a4SAndrii Nakryiko __u32 old_flags;
1560e043325bSChenbo Feng
15612fe256a4SAndrii Nakryiko old_flags = map_opts.map_flags;
15622fe256a4SAndrii Nakryiko map_opts.map_flags |= BPF_F_WRONLY;
15632fe256a4SAndrii Nakryiko fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
15642fe256a4SAndrii Nakryiko MAP_SIZE, &map_opts);
15652fe256a4SAndrii Nakryiko map_opts.map_flags = old_flags;
1566e043325bSChenbo Feng if (fd < 0) {
1567204fb041SAnton Protopopov printf("Failed to create map for write only test '%s'!\n",
1568e043325bSChenbo Feng strerror(errno));
1569e043325bSChenbo Feng exit(1);
1570e043325bSChenbo Feng }
1571e043325bSChenbo Feng
1572e043325bSChenbo Feng key = 1;
1573e043325bSChenbo Feng value = 1234;
1574e043325bSChenbo Feng /* Insert key=1 element. */
1575e27afb84SAlexei Starovoitov assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
1576e043325bSChenbo Feng
1577efbc3b8fSAnton Protopopov /* Check that reading elements and keys from the map is not allowed. */
1578bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == EPERM);
1579bad2e478SAndrii Nakryiko assert(bpf_map_get_next_key(fd, &key, &value) < 0 && errno == EPERM);
158036ef9a2dSAnton Protopopov
158136ef9a2dSAnton Protopopov close(fd);
1582e043325bSChenbo Feng }
1583e043325bSChenbo Feng
test_map_wronly_stack_or_queue(enum bpf_map_type map_type)158443dd115bSAnton Protopopov static void test_map_wronly_stack_or_queue(enum bpf_map_type map_type)
158543dd115bSAnton Protopopov {
158643dd115bSAnton Protopopov int fd, value = 0;
15872fe256a4SAndrii Nakryiko __u32 old_flags;
15882fe256a4SAndrii Nakryiko
158943dd115bSAnton Protopopov
159043dd115bSAnton Protopopov assert(map_type == BPF_MAP_TYPE_QUEUE ||
159143dd115bSAnton Protopopov map_type == BPF_MAP_TYPE_STACK);
15922fe256a4SAndrii Nakryiko old_flags = map_opts.map_flags;
15932fe256a4SAndrii Nakryiko map_opts.map_flags |= BPF_F_WRONLY;
15942fe256a4SAndrii Nakryiko fd = bpf_map_create(map_type, NULL, 0, sizeof(value), MAP_SIZE, &map_opts);
15952fe256a4SAndrii Nakryiko map_opts.map_flags = old_flags;
159643dd115bSAnton Protopopov /* Stack/Queue maps do not support BPF_F_NO_PREALLOC */
15972fe256a4SAndrii Nakryiko if (map_opts.map_flags & BPF_F_NO_PREALLOC) {
159843dd115bSAnton Protopopov assert(fd < 0 && errno == EINVAL);
159943dd115bSAnton Protopopov return;
160043dd115bSAnton Protopopov }
160143dd115bSAnton Protopopov if (fd < 0) {
160243dd115bSAnton Protopopov printf("Failed to create map '%s'!\n", strerror(errno));
160343dd115bSAnton Protopopov exit(1);
160443dd115bSAnton Protopopov }
160543dd115bSAnton Protopopov
160643dd115bSAnton Protopopov value = 1234;
160743dd115bSAnton Protopopov assert(bpf_map_update_elem(fd, NULL, &value, BPF_ANY) == 0);
160843dd115bSAnton Protopopov
160943dd115bSAnton Protopopov /* Peek element should fail */
1610bad2e478SAndrii Nakryiko assert(bpf_map_lookup_elem(fd, NULL, &value) < 0 && errno == EPERM);
161143dd115bSAnton Protopopov
161243dd115bSAnton Protopopov /* Pop element should fail */
1613bad2e478SAndrii Nakryiko assert(bpf_map_lookup_and_delete_elem(fd, NULL, &value) < 0 &&
161443dd115bSAnton Protopopov errno == EPERM);
161543dd115bSAnton Protopopov
161643dd115bSAnton Protopopov close(fd);
161743dd115bSAnton Protopopov }
161843dd115bSAnton Protopopov
test_map_wronly(void)161943dd115bSAnton Protopopov static void test_map_wronly(void)
162043dd115bSAnton Protopopov {
162143dd115bSAnton Protopopov test_map_wronly_hash();
162243dd115bSAnton Protopopov test_map_wronly_stack_or_queue(BPF_MAP_TYPE_STACK);
162343dd115bSAnton Protopopov test_map_wronly_stack_or_queue(BPF_MAP_TYPE_QUEUE);
162443dd115bSAnton Protopopov }
162543dd115bSAnton Protopopov
prepare_reuseport_grp(int type,int map_fd,size_t map_elem_size,__s64 * fds64,__u64 * sk_cookies,unsigned int n)1626bc2d8afeSIlya Leoshkevich static void prepare_reuseport_grp(int type, int map_fd, size_t map_elem_size,
16276bc8529cSMartin KaFai Lau __s64 *fds64, __u64 *sk_cookies,
16286bc8529cSMartin KaFai Lau unsigned int n)
16296bc8529cSMartin KaFai Lau {
16306bc8529cSMartin KaFai Lau socklen_t optlen, addrlen;
16316bc8529cSMartin KaFai Lau struct sockaddr_in6 s6;
16326bc8529cSMartin KaFai Lau const __u32 index0 = 0;
16336bc8529cSMartin KaFai Lau const int optval = 1;
16346bc8529cSMartin KaFai Lau unsigned int i;
16356bc8529cSMartin KaFai Lau u64 sk_cookie;
1636bc2d8afeSIlya Leoshkevich void *value;
1637bc2d8afeSIlya Leoshkevich __s32 fd32;
16386bc8529cSMartin KaFai Lau __s64 fd64;
16396bc8529cSMartin KaFai Lau int err;
16406bc8529cSMartin KaFai Lau
16416bc8529cSMartin KaFai Lau s6.sin6_family = AF_INET6;
16426bc8529cSMartin KaFai Lau s6.sin6_addr = in6addr_any;
16436bc8529cSMartin KaFai Lau s6.sin6_port = 0;
16446bc8529cSMartin KaFai Lau addrlen = sizeof(s6);
16456bc8529cSMartin KaFai Lau optlen = sizeof(sk_cookie);
16466bc8529cSMartin KaFai Lau
16476bc8529cSMartin KaFai Lau for (i = 0; i < n; i++) {
16486bc8529cSMartin KaFai Lau fd64 = socket(AF_INET6, type, 0);
16496bc8529cSMartin KaFai Lau CHECK(fd64 == -1, "socket()",
16506bc8529cSMartin KaFai Lau "sock_type:%d fd64:%lld errno:%d\n",
16516bc8529cSMartin KaFai Lau type, fd64, errno);
16526bc8529cSMartin KaFai Lau
16536bc8529cSMartin KaFai Lau err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT,
16546bc8529cSMartin KaFai Lau &optval, sizeof(optval));
165526a1ccc6SColin Ian King CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
16566bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
16576bc8529cSMartin KaFai Lau
16586bc8529cSMartin KaFai Lau /* reuseport_array does not allow unbound sk */
1659bc2d8afeSIlya Leoshkevich if (map_elem_size == sizeof(__u64))
1660bc2d8afeSIlya Leoshkevich value = &fd64;
1661bc2d8afeSIlya Leoshkevich else {
1662bc2d8afeSIlya Leoshkevich assert(map_elem_size == sizeof(__u32));
1663bc2d8afeSIlya Leoshkevich fd32 = (__s32)fd64;
1664bc2d8afeSIlya Leoshkevich value = &fd32;
1665bc2d8afeSIlya Leoshkevich }
1666bc2d8afeSIlya Leoshkevich err = bpf_map_update_elem(map_fd, &index0, value, BPF_ANY);
1667bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != EINVAL,
16686bc8529cSMartin KaFai Lau "reuseport array update unbound sk",
16696bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
16706bc8529cSMartin KaFai Lau type, err, errno);
16716bc8529cSMartin KaFai Lau
16726bc8529cSMartin KaFai Lau err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6));
16736bc8529cSMartin KaFai Lau CHECK(err == -1, "bind()",
16746bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n", type, err, errno);
16756bc8529cSMartin KaFai Lau
16766bc8529cSMartin KaFai Lau if (i == 0) {
16776bc8529cSMartin KaFai Lau err = getsockname(fd64, (struct sockaddr *)&s6,
16786bc8529cSMartin KaFai Lau &addrlen);
16796bc8529cSMartin KaFai Lau CHECK(err == -1, "getsockname()",
16806bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
16816bc8529cSMartin KaFai Lau type, err, errno);
16826bc8529cSMartin KaFai Lau }
16836bc8529cSMartin KaFai Lau
16846bc8529cSMartin KaFai Lau err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie,
16856bc8529cSMartin KaFai Lau &optlen);
16866bc8529cSMartin KaFai Lau CHECK(err == -1, "getsockopt(SO_COOKIE)",
16876bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n", type, err, errno);
16886bc8529cSMartin KaFai Lau
16896bc8529cSMartin KaFai Lau if (type == SOCK_STREAM) {
16906bc8529cSMartin KaFai Lau /*
16916bc8529cSMartin KaFai Lau * reuseport_array does not allow
16926bc8529cSMartin KaFai Lau * non-listening tcp sk.
16936bc8529cSMartin KaFai Lau */
1694bc2d8afeSIlya Leoshkevich err = bpf_map_update_elem(map_fd, &index0, value,
16956bc8529cSMartin KaFai Lau BPF_ANY);
1696bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != EINVAL,
16976bc8529cSMartin KaFai Lau "reuseport array update non-listening sk",
16986bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
16996bc8529cSMartin KaFai Lau type, err, errno);
17006bc8529cSMartin KaFai Lau err = listen(fd64, 0);
17016bc8529cSMartin KaFai Lau CHECK(err == -1, "listen()",
17026bc8529cSMartin KaFai Lau "sock_type:%d, err:%d errno:%d\n",
17036bc8529cSMartin KaFai Lau type, err, errno);
17046bc8529cSMartin KaFai Lau }
17056bc8529cSMartin KaFai Lau
17066bc8529cSMartin KaFai Lau fds64[i] = fd64;
17076bc8529cSMartin KaFai Lau sk_cookies[i] = sk_cookie;
17086bc8529cSMartin KaFai Lau }
17096bc8529cSMartin KaFai Lau }
17106bc8529cSMartin KaFai Lau
test_reuseport_array(void)17116bc8529cSMartin KaFai Lau static void test_reuseport_array(void)
17126bc8529cSMartin KaFai Lau {
17136bc8529cSMartin KaFai Lau #define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; })
17146bc8529cSMartin KaFai Lau
17156bc8529cSMartin KaFai Lau const __u32 array_size = 4, index0 = 0, index3 = 3;
17166bc8529cSMartin KaFai Lau int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type;
17176bc8529cSMartin KaFai Lau __u64 grpa_cookies[2], sk_cookie, map_cookie;
17186bc8529cSMartin KaFai Lau __s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1;
17196bc8529cSMartin KaFai Lau const __u32 bad_index = array_size;
17206bc8529cSMartin KaFai Lau int map_fd, err, t, f;
17216bc8529cSMartin KaFai Lau __u32 fds_idx = 0;
17226bc8529cSMartin KaFai Lau int fd;
17236bc8529cSMartin KaFai Lau
17242fe256a4SAndrii Nakryiko map_fd = bpf_map_create(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, NULL,
17252fe256a4SAndrii Nakryiko sizeof(__u32), sizeof(__u64), array_size, NULL);
1726bad2e478SAndrii Nakryiko CHECK(map_fd < 0, "reuseport array create",
17276bc8529cSMartin KaFai Lau "map_fd:%d, errno:%d\n", map_fd, errno);
17286bc8529cSMartin KaFai Lau
17296bc8529cSMartin KaFai Lau /* Test lookup/update/delete with invalid index */
17306bc8529cSMartin KaFai Lau err = bpf_map_delete_elem(map_fd, &bad_index);
1731bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != E2BIG, "reuseport array del >=max_entries",
17326bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
17336bc8529cSMartin KaFai Lau
17346bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY);
1735bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != E2BIG,
17366bc8529cSMartin KaFai Lau "reuseport array update >=max_entries",
17376bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
17386bc8529cSMartin KaFai Lau
17396bc8529cSMartin KaFai Lau err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie);
1740bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOENT,
17416bc8529cSMartin KaFai Lau "reuseport array update >=max_entries",
17426bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
17436bc8529cSMartin KaFai Lau
17446bc8529cSMartin KaFai Lau /* Test lookup/delete non existence elem */
17456bc8529cSMartin KaFai Lau err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1746bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOENT,
17476bc8529cSMartin KaFai Lau "reuseport array lookup not-exist elem",
17486bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
17496bc8529cSMartin KaFai Lau err = bpf_map_delete_elem(map_fd, &index3);
1750bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOENT,
17516bc8529cSMartin KaFai Lau "reuseport array del not-exist elem",
17526bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
17536bc8529cSMartin KaFai Lau
17546bc8529cSMartin KaFai Lau for (t = 0; t < ARRAY_SIZE(types); t++) {
17556bc8529cSMartin KaFai Lau type = types[t];
17566bc8529cSMartin KaFai Lau
1757bc2d8afeSIlya Leoshkevich prepare_reuseport_grp(type, map_fd, sizeof(__u64), grpa_fds64,
17586bc8529cSMartin KaFai Lau grpa_cookies, ARRAY_SIZE(grpa_fds64));
17596bc8529cSMartin KaFai Lau
17606bc8529cSMartin KaFai Lau /* Test BPF_* update flags */
17616bc8529cSMartin KaFai Lau /* BPF_EXIST failure case */
17626bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
17636bc8529cSMartin KaFai Lau BPF_EXIST);
1764bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOENT,
17656bc8529cSMartin KaFai Lau "reuseport array update empty elem BPF_EXIST",
17666bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
17676bc8529cSMartin KaFai Lau type, err, errno);
17686bc8529cSMartin KaFai Lau fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
17696bc8529cSMartin KaFai Lau
17706bc8529cSMartin KaFai Lau /* BPF_NOEXIST success case */
17716bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
17726bc8529cSMartin KaFai Lau BPF_NOEXIST);
1773bad2e478SAndrii Nakryiko CHECK(err < 0,
17746bc8529cSMartin KaFai Lau "reuseport array update empty elem BPF_NOEXIST",
17756bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
17766bc8529cSMartin KaFai Lau type, err, errno);
17776bc8529cSMartin KaFai Lau fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
17786bc8529cSMartin KaFai Lau
17796bc8529cSMartin KaFai Lau /* BPF_EXIST success case. */
17806bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
17816bc8529cSMartin KaFai Lau BPF_EXIST);
1782bad2e478SAndrii Nakryiko CHECK(err < 0,
17836bc8529cSMartin KaFai Lau "reuseport array update same elem BPF_EXIST",
17846bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n", type, err, errno);
17856bc8529cSMartin KaFai Lau fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
17866bc8529cSMartin KaFai Lau
17876bc8529cSMartin KaFai Lau /* BPF_NOEXIST failure case */
17886bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
17896bc8529cSMartin KaFai Lau BPF_NOEXIST);
1790bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != EEXIST,
17916bc8529cSMartin KaFai Lau "reuseport array update non-empty elem BPF_NOEXIST",
17926bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
17936bc8529cSMartin KaFai Lau type, err, errno);
17946bc8529cSMartin KaFai Lau fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
17956bc8529cSMartin KaFai Lau
17966bc8529cSMartin KaFai Lau /* BPF_ANY case (always succeed) */
17976bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
17986bc8529cSMartin KaFai Lau BPF_ANY);
1799bad2e478SAndrii Nakryiko CHECK(err < 0,
18006bc8529cSMartin KaFai Lau "reuseport array update same sk with BPF_ANY",
18016bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n", type, err, errno);
18026bc8529cSMartin KaFai Lau
18036bc8529cSMartin KaFai Lau fd64 = grpa_fds64[fds_idx];
18046bc8529cSMartin KaFai Lau sk_cookie = grpa_cookies[fds_idx];
18056bc8529cSMartin KaFai Lau
18066bc8529cSMartin KaFai Lau /* The same sk cannot be added to reuseport_array twice */
18076bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY);
1808bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != EBUSY,
18096bc8529cSMartin KaFai Lau "reuseport array update same sk with same index",
18106bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
18116bc8529cSMartin KaFai Lau type, err, errno);
18126bc8529cSMartin KaFai Lau
18136bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY);
1814bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != EBUSY,
18156bc8529cSMartin KaFai Lau "reuseport array update same sk with different index",
18166bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
18176bc8529cSMartin KaFai Lau type, err, errno);
18186bc8529cSMartin KaFai Lau
18196bc8529cSMartin KaFai Lau /* Test delete elem */
18206bc8529cSMartin KaFai Lau err = bpf_map_delete_elem(map_fd, &index3);
1821bad2e478SAndrii Nakryiko CHECK(err < 0, "reuseport array delete sk",
18226bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
18236bc8529cSMartin KaFai Lau type, err, errno);
18246bc8529cSMartin KaFai Lau
18256bc8529cSMartin KaFai Lau /* Add it back with BPF_NOEXIST */
18266bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1827bad2e478SAndrii Nakryiko CHECK(err < 0,
18286bc8529cSMartin KaFai Lau "reuseport array re-add with BPF_NOEXIST after del",
18296bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n", type, err, errno);
18306bc8529cSMartin KaFai Lau
18316bc8529cSMartin KaFai Lau /* Test cookie */
18326bc8529cSMartin KaFai Lau err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1833bad2e478SAndrii Nakryiko CHECK(err < 0 || sk_cookie != map_cookie,
18346bc8529cSMartin KaFai Lau "reuseport array lookup re-added sk",
18356bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn",
18366bc8529cSMartin KaFai Lau type, err, errno, sk_cookie, map_cookie);
18376bc8529cSMartin KaFai Lau
18386bc8529cSMartin KaFai Lau /* Test elem removed by close() */
18396bc8529cSMartin KaFai Lau for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++)
18406bc8529cSMartin KaFai Lau close(grpa_fds64[f]);
18416bc8529cSMartin KaFai Lau err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1842bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOENT,
18436bc8529cSMartin KaFai Lau "reuseport array lookup after close()",
18446bc8529cSMartin KaFai Lau "sock_type:%d err:%d errno:%d\n",
18456bc8529cSMartin KaFai Lau type, err, errno);
18466bc8529cSMartin KaFai Lau }
18476bc8529cSMartin KaFai Lau
18486bc8529cSMartin KaFai Lau /* Test SOCK_RAW */
18496bc8529cSMartin KaFai Lau fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
18506bc8529cSMartin KaFai Lau CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n",
18516bc8529cSMartin KaFai Lau err, errno);
18526bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1853bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOTSUPP, "reuseport array update SOCK_RAW",
18546bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
18556bc8529cSMartin KaFai Lau close(fd64);
18566bc8529cSMartin KaFai Lau
18576bc8529cSMartin KaFai Lau /* Close the 64 bit value map */
18586bc8529cSMartin KaFai Lau close(map_fd);
18596bc8529cSMartin KaFai Lau
18606bc8529cSMartin KaFai Lau /* Test 32 bit fd */
18612fe256a4SAndrii Nakryiko map_fd = bpf_map_create(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, NULL,
18622fe256a4SAndrii Nakryiko sizeof(__u32), sizeof(__u32), array_size, NULL);
1863bad2e478SAndrii Nakryiko CHECK(map_fd < 0, "reuseport array create",
18646bc8529cSMartin KaFai Lau "map_fd:%d, errno:%d\n", map_fd, errno);
1865bc2d8afeSIlya Leoshkevich prepare_reuseport_grp(SOCK_STREAM, map_fd, sizeof(__u32), &fd64,
1866bc2d8afeSIlya Leoshkevich &sk_cookie, 1);
18676bc8529cSMartin KaFai Lau fd = fd64;
18686bc8529cSMartin KaFai Lau err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST);
1869bad2e478SAndrii Nakryiko CHECK(err < 0, "reuseport array update 32 bit fd",
18706bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
18716bc8529cSMartin KaFai Lau err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1872bad2e478SAndrii Nakryiko CHECK(err >= 0 || errno != ENOSPC,
18736bc8529cSMartin KaFai Lau "reuseport array lookup 32 bit fd",
18746bc8529cSMartin KaFai Lau "err:%d errno:%d\n", err, errno);
18756bc8529cSMartin KaFai Lau close(fd);
18766bc8529cSMartin KaFai Lau close(map_fd);
18776bc8529cSMartin KaFai Lau }
18786bc8529cSMartin KaFai Lau
run_all_tests(void)18795aa5bd14SDaniel Borkmann static void run_all_tests(void)
18805aa5bd14SDaniel Borkmann {
18815aa5bd14SDaniel Borkmann test_hashmap(0, NULL);
18825aa5bd14SDaniel Borkmann test_hashmap_percpu(0, NULL);
18835ecf51fdSDaniel Borkmann test_hashmap_walk(0, NULL);
1884bf5d68c7SLorenz Bauer test_hashmap_zero_seed();
18855aa5bd14SDaniel Borkmann
18865aa5bd14SDaniel Borkmann test_arraymap(0, NULL);
18875aa5bd14SDaniel Borkmann test_arraymap_percpu(0, NULL);
18885aa5bd14SDaniel Borkmann
18895aa5bd14SDaniel Borkmann test_arraymap_percpu_many_keys();
18905aa5bd14SDaniel Borkmann
189181f6bf81SJohn Fastabend test_devmap(0, NULL);
18921375dc4aSToke Høiland-Jørgensen test_devmap_hash(0, NULL);
18936f6d33f3SJohn Fastabend test_sockmap(0, NULL);
189481f6bf81SJohn Fastabend
18955aa5bd14SDaniel Borkmann test_map_large();
18965aa5bd14SDaniel Borkmann test_map_parallel();
18975aa5bd14SDaniel Borkmann test_map_stress();
1898e043325bSChenbo Feng
1899e043325bSChenbo Feng test_map_rdonly();
1900e043325bSChenbo Feng test_map_wronly();
19016bc8529cSMartin KaFai Lau
19026bc8529cSMartin KaFai Lau test_reuseport_array();
190343b987d2SMauricio Vasquez B
190443b987d2SMauricio Vasquez B test_queuemap(0, NULL);
190543b987d2SMauricio Vasquez B test_stackmap(0, NULL);
1906b1957c92SNikita V. Shirokov
1907b1957c92SNikita V. Shirokov test_map_in_map();
19085aa5bd14SDaniel Borkmann }
19095aa5bd14SDaniel Borkmann
1910ee6c52e9SAndrii Nakryiko #define DEFINE_TEST(name) extern void test_##name(void);
191151a0e301SMartin KaFai Lau #include <map_tests/tests.h>
1912ee6c52e9SAndrii Nakryiko #undef DEFINE_TEST
191351a0e301SMartin KaFai Lau
main(void)19145aa5bd14SDaniel Borkmann int main(void)
19155aa5bd14SDaniel Borkmann {
191643b987d2SMauricio Vasquez B srand(time(NULL));
191743b987d2SMauricio Vasquez B
1918bad2e478SAndrii Nakryiko libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1919bad2e478SAndrii Nakryiko
19202fe256a4SAndrii Nakryiko map_opts.map_flags = 0;
19215aa5bd14SDaniel Borkmann run_all_tests();
19225aa5bd14SDaniel Borkmann
19232fe256a4SAndrii Nakryiko map_opts.map_flags = BPF_F_NO_PREALLOC;
19245aa5bd14SDaniel Borkmann run_all_tests();
19255aa5bd14SDaniel Borkmann
1926ee6c52e9SAndrii Nakryiko #define DEFINE_TEST(name) test_##name();
192751a0e301SMartin KaFai Lau #include <map_tests/tests.h>
1928ee6c52e9SAndrii Nakryiko #undef DEFINE_TEST
192951a0e301SMartin KaFai Lau
1930e8ddbfb4SStanislav Fomichev printf("test_maps: OK, %d SKIPPED\n", skips);
19315aa5bd14SDaniel Borkmann return 0;
19325aa5bd14SDaniel Borkmann }
1933