Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2021 Facebook */
  3#include <linux/stddef.h>
  4#include <linux/bpf.h>
  5#include <bpf/bpf_helpers.h>
  6#include <bpf/bpf_tracing.h>
  7#include <../../../tools/include/linux/filter.h>
  8#include <linux/btf.h>
  9#include <string.h>
 10#include <errno.h>
 11#include "bpf_misc.h"
 12
 13char _license[] SEC("license") = "GPL";
 14
 15struct bpf_map {
 16	int id;
 17}  __attribute__((preserve_access_index));
 18
 19struct args {
 20	__u64 log_buf;
 21	__u32 log_size;
 22	int max_entries;
 23	int map_fd;
 24	int prog_fd;
 25	int btf_fd;
 26};
 27
 28#define BTF_INFO_ENC(kind, kind_flag, vlen) \
 29	((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
 30#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
 31#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \
 32	((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
 33#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \
 34	BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \
 35	BTF_INT_ENC(encoding, bits_offset, bits)
 36
 37struct {
 38	__uint(type, BPF_MAP_TYPE_ARRAY);
 39	__type(key, int);
 40	__type(value, union bpf_attr);
 41	__uint(max_entries, 1);
 42} bpf_attr_array SEC(".maps");
 43
 44struct inner_map_type {
 45	__uint(type, BPF_MAP_TYPE_ARRAY);
 46	__uint(key_size, 4);
 47	__uint(value_size, 4);
 48	__uint(max_entries, 1);
 49} inner_map SEC(".maps");
 50
 51struct {
 52	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
 53	__type(key, int);
 54	__type(value, int);
 55	__uint(max_entries, 1);
 56	__array(values, struct inner_map_type);
 57} outer_array_map SEC(".maps") = {
 58	.values = {
 59		[0] = &inner_map,
 60	},
 61};
 62
 63static inline __u64 ptr_to_u64(const void *ptr)
 64{
 65	return (__u64) (unsigned long) ptr;
 66}
 67
 68static int btf_load(void)
 69{
 70	struct btf_blob {
 71		struct btf_header btf_hdr;
 72		__u32 types[8];
 73		__u32 str;
 74	} raw_btf = {
 75		.btf_hdr = {
 76			.magic = BTF_MAGIC,
 77			.version = BTF_VERSION,
 78			.hdr_len = sizeof(struct btf_header),
 79			.type_len = sizeof(__u32) * 8,
 80			.str_off = sizeof(__u32) * 8,
 81			.str_len = sizeof(__u32),
 82		},
 83		.types = {
 84			/* long */
 85			BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 64, 8),  /* [1] */
 86			/* unsigned long */
 87			BTF_TYPE_INT_ENC(0, 0, 0, 64, 8),  /* [2] */
 88		},
 89	};
 90	static union bpf_attr btf_load_attr = {
 91		.btf_size = sizeof(raw_btf),
 92	};
 93
 94	btf_load_attr.btf = (long)&raw_btf;
 95	return bpf_sys_bpf(BPF_BTF_LOAD, &btf_load_attr, sizeof(btf_load_attr));
 96}
 97
 98SEC("syscall")
 99int load_prog(struct args *ctx)
100{
101	static char license[] = "GPL";
102	static struct bpf_insn insns[] = {
103		BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
104		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
105		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
106		BPF_LD_MAP_FD(BPF_REG_1, 0),
107		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
108		BPF_MOV64_IMM(BPF_REG_0, 0),
109		BPF_EXIT_INSN(),
110	};
111	static union bpf_attr map_create_attr = {
112		.map_type = BPF_MAP_TYPE_HASH,
113		.key_size = 8,
114		.value_size = 8,
115		.btf_key_type_id = 1,
116		.btf_value_type_id = 2,
117	};
118	static union bpf_attr map_update_attr = { .map_fd = 1, };
119	static __u64 key = 12;
120	static __u64 value = 34;
121	static union bpf_attr prog_load_attr = {
122		.prog_type = BPF_PROG_TYPE_XDP,
123		.insn_cnt = ARRAY_SIZE(insns),
124	};
125	int ret;
126
127	ret = btf_load();
128	if (ret <= 0)
129		return ret;
130
131	ctx->btf_fd = ret;
132	map_create_attr.max_entries = ctx->max_entries;
133	map_create_attr.btf_fd = ret;
134
135	prog_load_attr.license = ptr_to_u64(license);
136	prog_load_attr.insns = ptr_to_u64(insns);
137	prog_load_attr.log_buf = ctx->log_buf;
138	prog_load_attr.log_size = ctx->log_size;
139	prog_load_attr.log_level = 1;
140
141	ret = bpf_sys_bpf(BPF_MAP_CREATE, &map_create_attr, sizeof(map_create_attr));
142	if (ret <= 0)
143		return ret;
144	ctx->map_fd = ret;
145	insns[3].imm = ret;
146
147	map_update_attr.map_fd = ret;
148	map_update_attr.key = ptr_to_u64(&key);
149	map_update_attr.value = ptr_to_u64(&value);
150	ret = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, &map_update_attr, sizeof(map_update_attr));
151	if (ret < 0)
152		return ret;
153
154	ret = bpf_sys_bpf(BPF_PROG_LOAD, &prog_load_attr, sizeof(prog_load_attr));
155	if (ret <= 0)
156		return ret;
157	ctx->prog_fd = ret;
158	return 1;
159}
160
161SEC("syscall")
162int update_outer_map(void *ctx)
163{
164	int zero = 0, ret = 0, outer_fd = -1, inner_fd = -1, err;
165	const int attr_sz = sizeof(union bpf_attr);
166	union bpf_attr *attr;
167
168	attr = bpf_map_lookup_elem((struct bpf_map *)&bpf_attr_array, &zero);
169	if (!attr)
170		goto out;
171
172	memset(attr, 0, attr_sz);
173	attr->map_id = ((struct bpf_map *)&outer_array_map)->id;
174	outer_fd = bpf_sys_bpf(BPF_MAP_GET_FD_BY_ID, attr, attr_sz);
175	if (outer_fd < 0)
176		goto out;
177
178	memset(attr, 0, attr_sz);
179	attr->map_type = BPF_MAP_TYPE_ARRAY;
180	attr->key_size = 4;
181	attr->value_size = 4;
182	attr->max_entries = 1;
183	inner_fd = bpf_sys_bpf(BPF_MAP_CREATE, attr, attr_sz);
184	if (inner_fd < 0)
185		goto out;
186
187	memset(attr, 0, attr_sz);
188	attr->map_fd = outer_fd;
189	attr->key = ptr_to_u64(&zero);
190	attr->value = ptr_to_u64(&inner_fd);
191	err = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, attr, attr_sz);
192	if (err)
193		goto out;
194
195	memset(attr, 0, attr_sz);
196	attr->map_fd = outer_fd;
197	attr->key = ptr_to_u64(&zero);
198	err = bpf_sys_bpf(BPF_MAP_DELETE_ELEM, attr, attr_sz);
199	if (err)
200		goto out;
201	ret = 1;
202out:
203	if (inner_fd >= 0)
204		bpf_sys_close(inner_fd);
205	if (outer_fd >= 0)
206		bpf_sys_close(outer_fd);
207	return ret;
208}