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