209 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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}209