github.com/cilium/cilium@v1.16.2/bpf/lib/static_data.h (about) 1 /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 /* Copyright Authors of Cilium */ 3 4 #pragma once 5 6 #include <bpf/ctx/ctx.h> 7 #include <bpf/api.h> 8 9 #include "endian.h" 10 11 /* Declare a global configuration variable that can be modified at runtime, 12 * without needing to recompile the datapath. Access the variable using the 13 * CONFIG() macro. 14 */ 15 #define DECLARE_CONFIG(type, name, description) \ 16 /* Emit the variable to the .rodata.config section. The compiler will emit a 17 * BTF Datasec referring to all variables in this section, making them 18 * convenient to iterate through for generating config scaffolding in Go. 19 * ebpf-go will expose this section as a MapSpec when loading a 20 * CollectionSpec. 21 */ \ 22 __section(".rodata.config") \ 23 /* Assign the config variable a BTF decl tag containing its description. This 24 * allows including doc comments in code generated from BTF. 25 */ \ 26 __attribute__((btf_decl_tag(description))) \ 27 /* Declare a global variable of the given name and type. */ \ 28 static const type __config_##name; 29 30 /* Hardcode config values at compile time, e.g. from per-endpoint headers. 31 * Can be used only once per config variable within a single compilation unit. 32 */ 33 #define ASSIGN_CONFIG(type, name, value) \ 34 static const type __config_##name = value; 35 36 /* Access a global configuration variable declared using DECLARE_CONFIG(). All 37 * access must be done through this macro to ensure the loader can correctly 38 * find and update all instructions that refer to the variable. 39 */ 40 #define CONFIG(name) ({ \ 41 /* Variable used as output operand for the asm snippet. Type needs to match 42 * the width of the instruction in the snippet or some compilers will 43 * complain (notably arm64). 44 */ \ 45 __u64 out; \ 46 /* In BPF, referring to a global variable directly from C code will generally 47 * result in 2 instructions: 1) loading an array map pointer into a register, 48 * and 2) dereferencing the map pointer at the offset where the variable is 49 * located. The first instruction carries a relocation entry against the map, 50 * so the loader can update the instruction to carry the map's file 51 * descriptor after the map has been created, before loading the program. 52 * 53 * For security and efficiency purposes, we want to use global constants, 54 * populated by the agent before loading the program, remaining immutable 55 * thereafter. Native 'static const' are implemented by the compiler using the 56 * mechanism previously described, with variables emitted to the .rodata map, 57 * which gets frozen after being populated. This makes the verifier treat its 58 * values as constant, enabling dead code elimination and JIT optimizations. 59 * Unfortunately, this is only supported on kernels 5.2 and later, so we need 60 * a user space implementation in the meantime. 61 * 62 * This asm snippet emits a single dword load instruction with a symbol 63 * reference to .rodata.config, with the offset of the variable within the 64 * datasec stored in its instruction constant. This is no different from a 65 * regular static var access in bpf, with one difference: with a regular var, 66 * the compiler still takes the liberty of taking out a map pointer and using 67 * it multiple times, and/or pushing the register holding the variable to the 68 * stack, making it nearly impossible to correctly track and modify. 69 * 70 * To emulate the readonly map behaviour on older kernels, the ELF loader then 71 * rewrites all instructions referring to the map to simple ldimm64 with a 72 * constant provided by the agent at runtime. 73 */ \ 74 asm volatile("%[out] = __config_" #name " ll" : [out]"=r"(out)); \ 75 (typeof(__config_##name))out; \ 76 }) 77 78 /* Deprecated, use CONFIG instead. */ 79 #define fetch_u16(x) CONFIG(x) 80 #define fetch_u32(x) CONFIG(x) 81 #define fetch_ipv6(x) CONFIG(x ## _1), CONFIG(x ## _2) 82 #define fetch_mac(x) { { CONFIG(x ## _1), (__u16)CONFIG(x ## _2) } } 83 84 /* Deprecated, use DECLARE_CONFIG instead. */ 85 #define DEFINE_U16(name, value) \ 86 DECLARE_CONFIG(__u16, name, "Constant " #name " declared using DEFINE_U16") \ 87 ASSIGN_CONFIG(__u16, name, value) 88 #define DEFINE_U32(name, value) \ 89 DECLARE_CONFIG(__u32, name, "Constant " #name " declared using DEFINE_U32") \ 90 ASSIGN_CONFIG(__u32, name, value) 91 92 /* DEFINE_IPV6 and DEFINE_MAC are used to assign values to global constants from 93 * C headers generated at runtime before the datapath is compiled. This data 94 * ends up in .rodata.config in the ELF and is also inlined by the Go loader, 95 * even though it's not handled by ELF variable substitution. 96 * 97 * Variables relying on this are THIS_INTERFACE_MAC, LXC_IP, IPV6_MASQUERADE, ROUTER_IP 98 * and HOST_IP. 99 */ 100 #define DEFINE_IPV6(name, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) \ 101 DECLARE_CONFIG(__u64, name##_1, "First half of ipv6 address " #name) \ 102 DECLARE_CONFIG(__u64, name##_2, "Second half of ipv6 address " #name) \ 103 ASSIGN_CONFIG(__u64, name##_1, bpf_cpu_to_be64( \ 104 (__u64)(__u8)(a1) << 56 | (__u64)(__u8)(a2) << 48 | \ 105 (__u64)(__u8)(a3) << 40 | (__u64)(__u8)(a4) << 32 | \ 106 (__u64)(__u8)(a5) << 24 | (__u64)(__u8)(a6) << 16 | \ 107 (__u64)(__u8)(a7) << 8 | (__u64)(__u8)(a8))); \ 108 ASSIGN_CONFIG(__u64, name##_2, bpf_cpu_to_be64( \ 109 (__u64)(__u8)(a9) << 56 | (__u64)(__u8)(a10) << 48 | \ 110 (__u64)(__u8)(a11) << 40 | (__u64)(__u8)(a12) << 32 | \ 111 (__u64)(__u8)(a13) << 24 | (__u64)(__u8)(a14) << 16 | \ 112 (__u64)(__u8)(a15) << 8 | (__u64)(__u8)(a16))); 113 114 #define DEFINE_MAC(name, a1, a2, a3, a4, a5, a6) \ 115 DECLARE_CONFIG(__u32, name##_1, "First 32 bits of mac address " #name) \ 116 DECLARE_CONFIG(__u32, name##_2, "Remaining 16 bits of mac address " #name) \ 117 ASSIGN_CONFIG(__u32, name##_1, \ 118 (__u32)(__u8)(a1) << 24 | (__u32)(__u8)(a2) << 16 | \ 119 (__u32)(__u8)(a3) << 8 | (__u32)(__u8)(a4)) \ 120 ASSIGN_CONFIG(__u32, name##_2, (__u32)(__u8)(a5) << 8 | (__u32)(__u8)(a6))