18c2ecf20Sopenharmony_ci/* eBPF example program:
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * - Creates arraymap in kernel with 4 bytes keys and 8 byte values
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * - Loads eBPF program
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *   The eBPF program accesses the map passed in to store two pieces of
88c2ecf20Sopenharmony_ci *   information. The number of invocations of the program, which maps
98c2ecf20Sopenharmony_ci *   to the number of packets received, is stored to key 0. Key 1 is
108c2ecf20Sopenharmony_ci *   incremented on each iteration by the number of bytes stored in
118c2ecf20Sopenharmony_ci *   the skb.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * - Attaches the new program to a cgroup using BPF_PROG_ATTACH
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * - Every second, reads map[0] and map[1] to see how many bytes and
168c2ecf20Sopenharmony_ci *   packets were seen on any socket of tasks in the given cgroup.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define _GNU_SOURCE
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <stdio.h>
228c2ecf20Sopenharmony_ci#include <stdlib.h>
238c2ecf20Sopenharmony_ci#include <stddef.h>
248c2ecf20Sopenharmony_ci#include <string.h>
258c2ecf20Sopenharmony_ci#include <unistd.h>
268c2ecf20Sopenharmony_ci#include <assert.h>
278c2ecf20Sopenharmony_ci#include <errno.h>
288c2ecf20Sopenharmony_ci#include <fcntl.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/bpf.h>
318c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "bpf_insn.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cienum {
368c2ecf20Sopenharmony_ci	MAP_KEY_PACKETS,
378c2ecf20Sopenharmony_ci	MAP_KEY_BYTES,
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cichar bpf_log_buf[BPF_LOG_BUF_SIZE];
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int prog_load(int map_fd, int verdict)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct bpf_insn prog[] = {
458c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* save r6 so it's not clobbered by BPF_CALL */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci		/* Count packets */
488c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS), /* r0 = 0 */
498c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
508c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
518c2ecf20Sopenharmony_ci		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
528c2ecf20Sopenharmony_ci		BPF_LD_MAP_FD(BPF_REG_1, map_fd), /* load map fd to r1 */
538c2ecf20Sopenharmony_ci		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
548c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
558c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
568c2ecf20Sopenharmony_ci		BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		/* Count bytes */
598c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES), /* r0 = 1 */
608c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
618c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
628c2ecf20Sopenharmony_ci		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
638c2ecf20Sopenharmony_ci		BPF_LD_MAP_FD(BPF_REG_1, map_fd),
648c2ecf20Sopenharmony_ci		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
658c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
668c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)), /* r1 = skb->len */
678c2ecf20Sopenharmony_ci		BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
708c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
718c2ecf20Sopenharmony_ci	};
728c2ecf20Sopenharmony_ci	size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
758c2ecf20Sopenharmony_ci				prog, insns_cnt, "GPL", 0,
768c2ecf20Sopenharmony_ci				bpf_log_buf, BPF_LOG_BUF_SIZE);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int usage(const char *argv0)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	printf("Usage: %s [-d] [-D] <cg-path> <egress|ingress>\n", argv0);
828c2ecf20Sopenharmony_ci	printf("	-d	Drop Traffic\n");
838c2ecf20Sopenharmony_ci	printf("	-D	Detach filter, and exit\n");
848c2ecf20Sopenharmony_ci	return EXIT_FAILURE;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int attach_filter(int cg_fd, int type, int verdict)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	int prog_fd, map_fd, ret, key;
908c2ecf20Sopenharmony_ci	long long pkt_cnt, byte_cnt;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY,
938c2ecf20Sopenharmony_ci				sizeof(key), sizeof(byte_cnt),
948c2ecf20Sopenharmony_ci				256, 0);
958c2ecf20Sopenharmony_ci	if (map_fd < 0) {
968c2ecf20Sopenharmony_ci		printf("Failed to create map: '%s'\n", strerror(errno));
978c2ecf20Sopenharmony_ci		return EXIT_FAILURE;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	prog_fd = prog_load(map_fd, verdict);
1018c2ecf20Sopenharmony_ci	printf("Output from kernel verifier:\n%s\n-------\n", bpf_log_buf);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (prog_fd < 0) {
1048c2ecf20Sopenharmony_ci		printf("Failed to load prog: '%s'\n", strerror(errno));
1058c2ecf20Sopenharmony_ci		return EXIT_FAILURE;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	ret = bpf_prog_attach(prog_fd, cg_fd, type, 0);
1098c2ecf20Sopenharmony_ci	if (ret < 0) {
1108c2ecf20Sopenharmony_ci		printf("Failed to attach prog to cgroup: '%s'\n",
1118c2ecf20Sopenharmony_ci		       strerror(errno));
1128c2ecf20Sopenharmony_ci		return EXIT_FAILURE;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	while (1) {
1158c2ecf20Sopenharmony_ci		key = MAP_KEY_PACKETS;
1168c2ecf20Sopenharmony_ci		assert(bpf_map_lookup_elem(map_fd, &key, &pkt_cnt) == 0);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		key = MAP_KEY_BYTES;
1198c2ecf20Sopenharmony_ci		assert(bpf_map_lookup_elem(map_fd, &key, &byte_cnt) == 0);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		printf("cgroup received %lld packets, %lld bytes\n",
1228c2ecf20Sopenharmony_ci		       pkt_cnt, byte_cnt);
1238c2ecf20Sopenharmony_ci		sleep(1);
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return EXIT_SUCCESS;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ciint main(int argc, char **argv)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int detach_only = 0, verdict = 1;
1328c2ecf20Sopenharmony_ci	enum bpf_attach_type type;
1338c2ecf20Sopenharmony_ci	int opt, cg_fd, ret;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	while ((opt = getopt(argc, argv, "Dd")) != -1) {
1368c2ecf20Sopenharmony_ci		switch (opt) {
1378c2ecf20Sopenharmony_ci		case 'd':
1388c2ecf20Sopenharmony_ci			verdict = 0;
1398c2ecf20Sopenharmony_ci			break;
1408c2ecf20Sopenharmony_ci		case 'D':
1418c2ecf20Sopenharmony_ci			detach_only = 1;
1428c2ecf20Sopenharmony_ci			break;
1438c2ecf20Sopenharmony_ci		default:
1448c2ecf20Sopenharmony_ci			return usage(argv[0]);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (argc - optind < 2)
1498c2ecf20Sopenharmony_ci		return usage(argv[0]);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (strcmp(argv[optind + 1], "ingress") == 0)
1528c2ecf20Sopenharmony_ci		type = BPF_CGROUP_INET_INGRESS;
1538c2ecf20Sopenharmony_ci	else if (strcmp(argv[optind + 1], "egress") == 0)
1548c2ecf20Sopenharmony_ci		type = BPF_CGROUP_INET_EGRESS;
1558c2ecf20Sopenharmony_ci	else
1568c2ecf20Sopenharmony_ci		return usage(argv[0]);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	cg_fd = open(argv[optind], O_DIRECTORY | O_RDONLY);
1598c2ecf20Sopenharmony_ci	if (cg_fd < 0) {
1608c2ecf20Sopenharmony_ci		printf("Failed to open cgroup path: '%s'\n", strerror(errno));
1618c2ecf20Sopenharmony_ci		return EXIT_FAILURE;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (detach_only) {
1658c2ecf20Sopenharmony_ci		ret = bpf_prog_detach(cg_fd, type);
1668c2ecf20Sopenharmony_ci		printf("bpf_prog_detach() returned '%s' (%d)\n",
1678c2ecf20Sopenharmony_ci		       strerror(errno), errno);
1688c2ecf20Sopenharmony_ci	} else
1698c2ecf20Sopenharmony_ci		ret = attach_filter(cg_fd, type, verdict);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return ret;
1728c2ecf20Sopenharmony_ci}
173