100899e7eSAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0 200899e7eSAlexei Starovoitov /* Copyright (c) 2021 Facebook */ 300899e7eSAlexei Starovoitov #include <linux/stddef.h> 400899e7eSAlexei Starovoitov #include <linux/bpf.h> 500899e7eSAlexei Starovoitov #include <bpf/bpf_helpers.h> 600899e7eSAlexei Starovoitov #include <bpf/bpf_tracing.h> 700899e7eSAlexei Starovoitov #include <../../../tools/include/linux/filter.h> 8*2341d6bbSAlexei Starovoitov #include <linux/btf.h> 900899e7eSAlexei Starovoitov 1000899e7eSAlexei Starovoitov char _license[] SEC("license") = "GPL"; 1100899e7eSAlexei Starovoitov 1200899e7eSAlexei Starovoitov struct args { 1300899e7eSAlexei Starovoitov __u64 log_buf; 1400899e7eSAlexei Starovoitov __u32 log_size; 1500899e7eSAlexei Starovoitov int max_entries; 1600899e7eSAlexei Starovoitov int map_fd; 1700899e7eSAlexei Starovoitov int prog_fd; 18*2341d6bbSAlexei Starovoitov int btf_fd; 1900899e7eSAlexei Starovoitov }; 2000899e7eSAlexei Starovoitov 21*2341d6bbSAlexei Starovoitov #define BTF_INFO_ENC(kind, kind_flag, vlen) \ 22*2341d6bbSAlexei Starovoitov ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) 23*2341d6bbSAlexei Starovoitov #define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type) 24*2341d6bbSAlexei Starovoitov #define BTF_INT_ENC(encoding, bits_offset, nr_bits) \ 25*2341d6bbSAlexei Starovoitov ((encoding) << 24 | (bits_offset) << 16 | (nr_bits)) 26*2341d6bbSAlexei Starovoitov #define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \ 27*2341d6bbSAlexei Starovoitov BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ 28*2341d6bbSAlexei Starovoitov BTF_INT_ENC(encoding, bits_offset, bits) 29*2341d6bbSAlexei Starovoitov 30*2341d6bbSAlexei Starovoitov static int btf_load(void) 31*2341d6bbSAlexei Starovoitov { 32*2341d6bbSAlexei Starovoitov struct btf_blob { 33*2341d6bbSAlexei Starovoitov struct btf_header btf_hdr; 34*2341d6bbSAlexei Starovoitov __u32 types[8]; 35*2341d6bbSAlexei Starovoitov __u32 str; 36*2341d6bbSAlexei Starovoitov } raw_btf = { 37*2341d6bbSAlexei Starovoitov .btf_hdr = { 38*2341d6bbSAlexei Starovoitov .magic = BTF_MAGIC, 39*2341d6bbSAlexei Starovoitov .version = BTF_VERSION, 40*2341d6bbSAlexei Starovoitov .hdr_len = sizeof(struct btf_header), 41*2341d6bbSAlexei Starovoitov .type_len = sizeof(__u32) * 8, 42*2341d6bbSAlexei Starovoitov .str_off = sizeof(__u32) * 8, 43*2341d6bbSAlexei Starovoitov .str_len = sizeof(__u32), 44*2341d6bbSAlexei Starovoitov }, 45*2341d6bbSAlexei Starovoitov .types = { 46*2341d6bbSAlexei Starovoitov /* long */ 47*2341d6bbSAlexei Starovoitov BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 64, 8), /* [1] */ 48*2341d6bbSAlexei Starovoitov /* unsigned long */ 49*2341d6bbSAlexei Starovoitov BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */ 50*2341d6bbSAlexei Starovoitov }, 51*2341d6bbSAlexei Starovoitov }; 52*2341d6bbSAlexei Starovoitov static union bpf_attr btf_load_attr = { 53*2341d6bbSAlexei Starovoitov .btf_size = sizeof(raw_btf), 54*2341d6bbSAlexei Starovoitov }; 55*2341d6bbSAlexei Starovoitov 56*2341d6bbSAlexei Starovoitov btf_load_attr.btf = (long)&raw_btf; 57*2341d6bbSAlexei Starovoitov return bpf_sys_bpf(BPF_BTF_LOAD, &btf_load_attr, sizeof(btf_load_attr)); 58*2341d6bbSAlexei Starovoitov } 59*2341d6bbSAlexei Starovoitov 6000899e7eSAlexei Starovoitov SEC("syscall") 6100899e7eSAlexei Starovoitov int bpf_prog(struct args *ctx) 6200899e7eSAlexei Starovoitov { 6300899e7eSAlexei Starovoitov static char license[] = "GPL"; 6400899e7eSAlexei Starovoitov static struct bpf_insn insns[] = { 6500899e7eSAlexei Starovoitov BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 6600899e7eSAlexei Starovoitov BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 6700899e7eSAlexei Starovoitov BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 6800899e7eSAlexei Starovoitov BPF_LD_MAP_FD(BPF_REG_1, 0), 6900899e7eSAlexei Starovoitov BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 7000899e7eSAlexei Starovoitov BPF_MOV64_IMM(BPF_REG_0, 0), 7100899e7eSAlexei Starovoitov BPF_EXIT_INSN(), 7200899e7eSAlexei Starovoitov }; 7300899e7eSAlexei Starovoitov static union bpf_attr map_create_attr = { 7400899e7eSAlexei Starovoitov .map_type = BPF_MAP_TYPE_HASH, 7500899e7eSAlexei Starovoitov .key_size = 8, 7600899e7eSAlexei Starovoitov .value_size = 8, 77*2341d6bbSAlexei Starovoitov .btf_key_type_id = 1, 78*2341d6bbSAlexei Starovoitov .btf_value_type_id = 2, 7900899e7eSAlexei Starovoitov }; 8000899e7eSAlexei Starovoitov static union bpf_attr map_update_attr = { .map_fd = 1, }; 8100899e7eSAlexei Starovoitov static __u64 key = 12; 8200899e7eSAlexei Starovoitov static __u64 value = 34; 8300899e7eSAlexei Starovoitov static union bpf_attr prog_load_attr = { 8400899e7eSAlexei Starovoitov .prog_type = BPF_PROG_TYPE_XDP, 8500899e7eSAlexei Starovoitov .insn_cnt = sizeof(insns) / sizeof(insns[0]), 8600899e7eSAlexei Starovoitov }; 8700899e7eSAlexei Starovoitov int ret; 8800899e7eSAlexei Starovoitov 89*2341d6bbSAlexei Starovoitov ret = btf_load(); 90*2341d6bbSAlexei Starovoitov if (ret <= 0) 91*2341d6bbSAlexei Starovoitov return ret; 92*2341d6bbSAlexei Starovoitov 93*2341d6bbSAlexei Starovoitov ctx->btf_fd = ret; 9400899e7eSAlexei Starovoitov map_create_attr.max_entries = ctx->max_entries; 95*2341d6bbSAlexei Starovoitov map_create_attr.btf_fd = ret; 96*2341d6bbSAlexei Starovoitov 9700899e7eSAlexei Starovoitov prog_load_attr.license = (long) license; 9800899e7eSAlexei Starovoitov prog_load_attr.insns = (long) insns; 9900899e7eSAlexei Starovoitov prog_load_attr.log_buf = ctx->log_buf; 10000899e7eSAlexei Starovoitov prog_load_attr.log_size = ctx->log_size; 10100899e7eSAlexei Starovoitov prog_load_attr.log_level = 1; 10200899e7eSAlexei Starovoitov 10300899e7eSAlexei Starovoitov ret = bpf_sys_bpf(BPF_MAP_CREATE, &map_create_attr, sizeof(map_create_attr)); 10400899e7eSAlexei Starovoitov if (ret <= 0) 10500899e7eSAlexei Starovoitov return ret; 10600899e7eSAlexei Starovoitov ctx->map_fd = ret; 10700899e7eSAlexei Starovoitov insns[3].imm = ret; 10800899e7eSAlexei Starovoitov 10900899e7eSAlexei Starovoitov map_update_attr.map_fd = ret; 11000899e7eSAlexei Starovoitov map_update_attr.key = (long) &key; 11100899e7eSAlexei Starovoitov map_update_attr.value = (long) &value; 11200899e7eSAlexei Starovoitov ret = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, &map_update_attr, sizeof(map_update_attr)); 11300899e7eSAlexei Starovoitov if (ret < 0) 11400899e7eSAlexei Starovoitov return ret; 11500899e7eSAlexei Starovoitov 11600899e7eSAlexei Starovoitov ret = bpf_sys_bpf(BPF_PROG_LOAD, &prog_load_attr, sizeof(prog_load_attr)); 11700899e7eSAlexei Starovoitov if (ret <= 0) 11800899e7eSAlexei Starovoitov return ret; 11900899e7eSAlexei Starovoitov ctx->prog_fd = ret; 12000899e7eSAlexei Starovoitov return 1; 12100899e7eSAlexei Starovoitov } 122