162306a36Sopenharmony_ci#include <linux/unistd.h>
262306a36Sopenharmony_ci#include <linux/bpf.h>
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <stdio.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <stdint.h>
762306a36Sopenharmony_ci#include <unistd.h>
862306a36Sopenharmony_ci#include <string.h>
962306a36Sopenharmony_ci#include <assert.h>
1062306a36Sopenharmony_ci#include <errno.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <sys/types.h>
1362306a36Sopenharmony_ci#include <sys/socket.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <bpf/bpf.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <bpf/libbpf.h>
1862306a36Sopenharmony_ci#include "bpf_insn.h"
1962306a36Sopenharmony_ci#include "sock_example.h"
2062306a36Sopenharmony_ci#include "bpf_util.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define BPF_F_PIN	(1 << 0)
2362306a36Sopenharmony_ci#define BPF_F_GET	(1 << 1)
2462306a36Sopenharmony_ci#define BPF_F_PIN_GET	(BPF_F_PIN | BPF_F_GET)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define BPF_F_KEY	(1 << 2)
2762306a36Sopenharmony_ci#define BPF_F_VAL	(1 << 3)
2862306a36Sopenharmony_ci#define BPF_F_KEY_VAL	(BPF_F_KEY | BPF_F_VAL)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define BPF_M_UNSPEC	0
3162306a36Sopenharmony_ci#define BPF_M_MAP	1
3262306a36Sopenharmony_ci#define BPF_M_PROG	2
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cichar bpf_log_buf[BPF_LOG_BUF_SIZE];
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void usage(void)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	printf("Usage: fds_example [...]\n");
3962306a36Sopenharmony_ci	printf("       -F <file>   File to pin/get object\n");
4062306a36Sopenharmony_ci	printf("       -P          |- pin object\n");
4162306a36Sopenharmony_ci	printf("       -G          `- get object\n");
4262306a36Sopenharmony_ci	printf("       -m          eBPF map mode\n");
4362306a36Sopenharmony_ci	printf("       -k <key>    |- map key\n");
4462306a36Sopenharmony_ci	printf("       -v <value>  `- map value\n");
4562306a36Sopenharmony_ci	printf("       -p          eBPF prog mode\n");
4662306a36Sopenharmony_ci	printf("       -o <object> `- object file\n");
4762306a36Sopenharmony_ci	printf("       -h          Display this help.\n");
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic int bpf_prog_create(const char *object)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	static struct bpf_insn insns[] = {
5362306a36Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
5462306a36Sopenharmony_ci		BPF_EXIT_INSN(),
5562306a36Sopenharmony_ci	};
5662306a36Sopenharmony_ci	size_t insns_cnt = ARRAY_SIZE(insns);
5762306a36Sopenharmony_ci	struct bpf_object *obj;
5862306a36Sopenharmony_ci	int err;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (object) {
6162306a36Sopenharmony_ci		obj = bpf_object__open_file(object, NULL);
6262306a36Sopenharmony_ci		assert(!libbpf_get_error(obj));
6362306a36Sopenharmony_ci		err = bpf_object__load(obj);
6462306a36Sopenharmony_ci		assert(!err);
6562306a36Sopenharmony_ci		return bpf_program__fd(bpf_object__next_program(obj, NULL));
6662306a36Sopenharmony_ci	} else {
6762306a36Sopenharmony_ci		LIBBPF_OPTS(bpf_prog_load_opts, opts,
6862306a36Sopenharmony_ci			.log_buf = bpf_log_buf,
6962306a36Sopenharmony_ci			.log_size = BPF_LOG_BUF_SIZE,
7062306a36Sopenharmony_ci		);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		return bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
7362306a36Sopenharmony_ci				     insns, insns_cnt, &opts);
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int bpf_do_map(const char *file, uint32_t flags, uint32_t key,
7862306a36Sopenharmony_ci		      uint32_t value)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	int fd, ret;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (flags & BPF_F_PIN) {
8362306a36Sopenharmony_ci		fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(uint32_t),
8462306a36Sopenharmony_ci				    sizeof(uint32_t), 1024, NULL);
8562306a36Sopenharmony_ci		printf("bpf: map fd:%d (%s)\n", fd, strerror(errno));
8662306a36Sopenharmony_ci		assert(fd > 0);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		ret = bpf_obj_pin(fd, file);
8962306a36Sopenharmony_ci		printf("bpf: pin ret:(%d,%s)\n", ret, strerror(errno));
9062306a36Sopenharmony_ci		assert(ret == 0);
9162306a36Sopenharmony_ci	} else {
9262306a36Sopenharmony_ci		fd = bpf_obj_get(file);
9362306a36Sopenharmony_ci		printf("bpf: get fd:%d (%s)\n", fd, strerror(errno));
9462306a36Sopenharmony_ci		assert(fd > 0);
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if ((flags & BPF_F_KEY_VAL) == BPF_F_KEY_VAL) {
9862306a36Sopenharmony_ci		ret = bpf_map_update_elem(fd, &key, &value, 0);
9962306a36Sopenharmony_ci		printf("bpf: fd:%d u->(%u:%u) ret:(%d,%s)\n", fd, key, value,
10062306a36Sopenharmony_ci		       ret, strerror(errno));
10162306a36Sopenharmony_ci		assert(ret == 0);
10262306a36Sopenharmony_ci	} else if (flags & BPF_F_KEY) {
10362306a36Sopenharmony_ci		ret = bpf_map_lookup_elem(fd, &key, &value);
10462306a36Sopenharmony_ci		printf("bpf: fd:%d l->(%u):%u ret:(%d,%s)\n", fd, key, value,
10562306a36Sopenharmony_ci		       ret, strerror(errno));
10662306a36Sopenharmony_ci		assert(ret == 0);
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int bpf_do_prog(const char *file, uint32_t flags, const char *object)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int fd, sock, ret;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (flags & BPF_F_PIN) {
11762306a36Sopenharmony_ci		fd = bpf_prog_create(object);
11862306a36Sopenharmony_ci		printf("bpf: prog fd:%d (%s)\n", fd, strerror(errno));
11962306a36Sopenharmony_ci		assert(fd > 0);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		ret = bpf_obj_pin(fd, file);
12262306a36Sopenharmony_ci		printf("bpf: pin ret:(%d,%s)\n", ret, strerror(errno));
12362306a36Sopenharmony_ci		assert(ret == 0);
12462306a36Sopenharmony_ci	} else {
12562306a36Sopenharmony_ci		fd = bpf_obj_get(file);
12662306a36Sopenharmony_ci		printf("bpf: get fd:%d (%s)\n", fd, strerror(errno));
12762306a36Sopenharmony_ci		assert(fd > 0);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	sock = open_raw_sock("lo");
13162306a36Sopenharmony_ci	assert(sock > 0);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &fd, sizeof(fd));
13462306a36Sopenharmony_ci	printf("bpf: sock:%d <- fd:%d attached ret:(%d,%s)\n", sock, fd,
13562306a36Sopenharmony_ci	       ret, strerror(errno));
13662306a36Sopenharmony_ci	assert(ret == 0);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciint main(int argc, char **argv)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	const char *file = NULL, *object = NULL;
14462306a36Sopenharmony_ci	uint32_t key = 0, value = 0, flags = 0;
14562306a36Sopenharmony_ci	int opt, mode = BPF_M_UNSPEC;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	while ((opt = getopt(argc, argv, "F:PGmk:v:po:")) != -1) {
14862306a36Sopenharmony_ci		switch (opt) {
14962306a36Sopenharmony_ci		/* General args */
15062306a36Sopenharmony_ci		case 'F':
15162306a36Sopenharmony_ci			file = optarg;
15262306a36Sopenharmony_ci			break;
15362306a36Sopenharmony_ci		case 'P':
15462306a36Sopenharmony_ci			flags |= BPF_F_PIN;
15562306a36Sopenharmony_ci			break;
15662306a36Sopenharmony_ci		case 'G':
15762306a36Sopenharmony_ci			flags |= BPF_F_GET;
15862306a36Sopenharmony_ci			break;
15962306a36Sopenharmony_ci		/* Map-related args */
16062306a36Sopenharmony_ci		case 'm':
16162306a36Sopenharmony_ci			mode = BPF_M_MAP;
16262306a36Sopenharmony_ci			break;
16362306a36Sopenharmony_ci		case 'k':
16462306a36Sopenharmony_ci			key = strtoul(optarg, NULL, 0);
16562306a36Sopenharmony_ci			flags |= BPF_F_KEY;
16662306a36Sopenharmony_ci			break;
16762306a36Sopenharmony_ci		case 'v':
16862306a36Sopenharmony_ci			value = strtoul(optarg, NULL, 0);
16962306a36Sopenharmony_ci			flags |= BPF_F_VAL;
17062306a36Sopenharmony_ci			break;
17162306a36Sopenharmony_ci		/* Prog-related args */
17262306a36Sopenharmony_ci		case 'p':
17362306a36Sopenharmony_ci			mode = BPF_M_PROG;
17462306a36Sopenharmony_ci			break;
17562306a36Sopenharmony_ci		case 'o':
17662306a36Sopenharmony_ci			object = optarg;
17762306a36Sopenharmony_ci			break;
17862306a36Sopenharmony_ci		default:
17962306a36Sopenharmony_ci			goto out;
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (!(flags & BPF_F_PIN_GET) || !file)
18462306a36Sopenharmony_ci		goto out;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	switch (mode) {
18762306a36Sopenharmony_ci	case BPF_M_MAP:
18862306a36Sopenharmony_ci		return bpf_do_map(file, flags, key, value);
18962306a36Sopenharmony_ci	case BPF_M_PROG:
19062306a36Sopenharmony_ci		return bpf_do_prog(file, flags, object);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ciout:
19362306a36Sopenharmony_ci	usage();
19462306a36Sopenharmony_ci	return -1;
19562306a36Sopenharmony_ci}
196