18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2017 Facebook
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <sys/resource.h>
68c2ecf20Sopenharmony_ci#include <sys/socket.h>
78c2ecf20Sopenharmony_ci#include <arpa/inet.h>
88c2ecf20Sopenharmony_ci#include <stdint.h>
98c2ecf20Sopenharmony_ci#include <assert.h>
108c2ecf20Sopenharmony_ci#include <errno.h>
118c2ecf20Sopenharmony_ci#include <stdlib.h>
128c2ecf20Sopenharmony_ci#include <stdio.h>
138c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
148c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int map_fd[7];
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define PORT_A		(map_fd[0])
198c2ecf20Sopenharmony_ci#define PORT_H		(map_fd[1])
208c2ecf20Sopenharmony_ci#define REG_RESULT_H	(map_fd[2])
218c2ecf20Sopenharmony_ci#define INLINE_RESULT_H	(map_fd[3])
228c2ecf20Sopenharmony_ci#define A_OF_PORT_A	(map_fd[4]) /* Test case #0 */
238c2ecf20Sopenharmony_ci#define H_OF_PORT_A	(map_fd[5]) /* Test case #1 */
248c2ecf20Sopenharmony_ci#define H_OF_PORT_H	(map_fd[6]) /* Test case #2 */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic const char * const test_names[] = {
278c2ecf20Sopenharmony_ci	"Array of Array",
288c2ecf20Sopenharmony_ci	"Hash of Array",
298c2ecf20Sopenharmony_ci	"Hash of Hash",
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define NR_TESTS (sizeof(test_names) / sizeof(*test_names))
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void check_map_id(int inner_map_fd, int map_in_map_fd, uint32_t key)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct bpf_map_info info = {};
378c2ecf20Sopenharmony_ci	uint32_t info_len = sizeof(info);
388c2ecf20Sopenharmony_ci	int ret, id;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	ret = bpf_obj_get_info_by_fd(inner_map_fd, &info, &info_len);
418c2ecf20Sopenharmony_ci	assert(!ret);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	ret = bpf_map_lookup_elem(map_in_map_fd, &key, &id);
448c2ecf20Sopenharmony_ci	assert(!ret);
458c2ecf20Sopenharmony_ci	assert(id == info.id);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void populate_map(uint32_t port_key, int magic_result)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	int ret;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	ret = bpf_map_update_elem(PORT_A, &port_key, &magic_result, BPF_ANY);
538c2ecf20Sopenharmony_ci	assert(!ret);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	ret = bpf_map_update_elem(PORT_H, &port_key, &magic_result,
568c2ecf20Sopenharmony_ci				  BPF_NOEXIST);
578c2ecf20Sopenharmony_ci	assert(!ret);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	ret = bpf_map_update_elem(A_OF_PORT_A, &port_key, &PORT_A, BPF_ANY);
608c2ecf20Sopenharmony_ci	assert(!ret);
618c2ecf20Sopenharmony_ci	check_map_id(PORT_A, A_OF_PORT_A, port_key);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	ret = bpf_map_update_elem(H_OF_PORT_A, &port_key, &PORT_A, BPF_NOEXIST);
648c2ecf20Sopenharmony_ci	assert(!ret);
658c2ecf20Sopenharmony_ci	check_map_id(PORT_A, H_OF_PORT_A, port_key);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	ret = bpf_map_update_elem(H_OF_PORT_H, &port_key, &PORT_H, BPF_NOEXIST);
688c2ecf20Sopenharmony_ci	assert(!ret);
698c2ecf20Sopenharmony_ci	check_map_id(PORT_H, H_OF_PORT_H, port_key);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void test_map_in_map(void)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct sockaddr_in6 in6 = { .sin6_family = AF_INET6 };
758c2ecf20Sopenharmony_ci	uint32_t result_key = 0, port_key;
768c2ecf20Sopenharmony_ci	int result, inline_result;
778c2ecf20Sopenharmony_ci	int magic_result = 0xfaceb00c;
788c2ecf20Sopenharmony_ci	int ret;
798c2ecf20Sopenharmony_ci	int i;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	port_key = rand() & 0x00FF;
828c2ecf20Sopenharmony_ci	populate_map(port_key, magic_result);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	in6.sin6_addr.s6_addr16[0] = 0xdead;
858c2ecf20Sopenharmony_ci	in6.sin6_addr.s6_addr16[1] = 0xbeef;
868c2ecf20Sopenharmony_ci	in6.sin6_port = port_key;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	for (i = 0; i < NR_TESTS; i++) {
898c2ecf20Sopenharmony_ci		printf("%s: ", test_names[i]);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		in6.sin6_addr.s6_addr16[7] = i;
928c2ecf20Sopenharmony_ci		ret = connect(-1, (struct sockaddr *)&in6, sizeof(in6));
938c2ecf20Sopenharmony_ci		assert(ret == -1 && errno == EBADF);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		ret = bpf_map_lookup_elem(REG_RESULT_H, &result_key, &result);
968c2ecf20Sopenharmony_ci		assert(!ret);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		ret = bpf_map_lookup_elem(INLINE_RESULT_H, &result_key,
998c2ecf20Sopenharmony_ci					  &inline_result);
1008c2ecf20Sopenharmony_ci		assert(!ret);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		if (result != magic_result || inline_result != magic_result) {
1038c2ecf20Sopenharmony_ci			printf("Error. result:%d inline_result:%d\n",
1048c2ecf20Sopenharmony_ci			       result, inline_result);
1058c2ecf20Sopenharmony_ci			exit(1);
1068c2ecf20Sopenharmony_ci		}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		bpf_map_delete_elem(REG_RESULT_H, &result_key);
1098c2ecf20Sopenharmony_ci		bpf_map_delete_elem(INLINE_RESULT_H, &result_key);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		printf("Pass\n");
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint main(int argc, char **argv)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
1188c2ecf20Sopenharmony_ci	struct bpf_link *link = NULL;
1198c2ecf20Sopenharmony_ci	struct bpf_program *prog;
1208c2ecf20Sopenharmony_ci	struct bpf_object *obj;
1218c2ecf20Sopenharmony_ci	char filename[256];
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (setrlimit(RLIMIT_MEMLOCK, &r)) {
1248c2ecf20Sopenharmony_ci		perror("setrlimit(RLIMIT_MEMLOCK)");
1258c2ecf20Sopenharmony_ci		return 1;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
1298c2ecf20Sopenharmony_ci	obj = bpf_object__open_file(filename, NULL);
1308c2ecf20Sopenharmony_ci	if (libbpf_get_error(obj)) {
1318c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: opening BPF object file failed\n");
1328c2ecf20Sopenharmony_ci		return 0;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	prog = bpf_object__find_program_by_name(obj, "trace_sys_connect");
1368c2ecf20Sopenharmony_ci	if (!prog) {
1378c2ecf20Sopenharmony_ci		printf("finding a prog in obj file failed\n");
1388c2ecf20Sopenharmony_ci		goto cleanup;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* load BPF program */
1428c2ecf20Sopenharmony_ci	if (bpf_object__load(obj)) {
1438c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: loading BPF object file failed\n");
1448c2ecf20Sopenharmony_ci		goto cleanup;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	map_fd[0] = bpf_object__find_map_fd_by_name(obj, "port_a");
1488c2ecf20Sopenharmony_ci	map_fd[1] = bpf_object__find_map_fd_by_name(obj, "port_h");
1498c2ecf20Sopenharmony_ci	map_fd[2] = bpf_object__find_map_fd_by_name(obj, "reg_result_h");
1508c2ecf20Sopenharmony_ci	map_fd[3] = bpf_object__find_map_fd_by_name(obj, "inline_result_h");
1518c2ecf20Sopenharmony_ci	map_fd[4] = bpf_object__find_map_fd_by_name(obj, "a_of_port_a");
1528c2ecf20Sopenharmony_ci	map_fd[5] = bpf_object__find_map_fd_by_name(obj, "h_of_port_a");
1538c2ecf20Sopenharmony_ci	map_fd[6] = bpf_object__find_map_fd_by_name(obj, "h_of_port_h");
1548c2ecf20Sopenharmony_ci	if (map_fd[0] < 0 || map_fd[1] < 0 || map_fd[2] < 0 ||
1558c2ecf20Sopenharmony_ci	    map_fd[3] < 0 || map_fd[4] < 0 || map_fd[5] < 0 || map_fd[6] < 0) {
1568c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
1578c2ecf20Sopenharmony_ci		goto cleanup;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	link = bpf_program__attach(prog);
1618c2ecf20Sopenharmony_ci	if (libbpf_get_error(link)) {
1628c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: bpf_program__attach failed\n");
1638c2ecf20Sopenharmony_ci		link = NULL;
1648c2ecf20Sopenharmony_ci		goto cleanup;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	test_map_in_map();
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cicleanup:
1708c2ecf20Sopenharmony_ci	bpf_link__destroy(link);
1718c2ecf20Sopenharmony_ci	bpf_object__close(obj);
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
174