github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/ebpf/ebpf.go (about) 1 package ebpf 2 3 import ( 4 "fmt" 5 "unsafe" 6 ) 7 8 // Instruction is any struct that can be turned into a list of raw instruction. 9 // It returns a list since the LD IMM 64bit consists of 2 actual eBPF "instructions" 10 type Instruction interface { 11 fmt.Stringer 12 Raw() ([]RawInstruction, error) 13 } 14 15 // Jumper is any instruction that can jump to another piece of code using an 16-bit address 16 type Jumper interface { 17 SetJumpTarget(relAddr int16) 18 } 19 20 // Valuer is any instruction for which a constant value can be set 21 type Valuer interface { 22 SetValue(value int32) 23 } 24 25 // Nop does not exist in the eBPF definition, it is a filler instruction this package 26 // adds to decoded programs so the index numbers of the slice stay the same as 27 // the index numbers of the raw instructions, even when the LoadConstant64bit op is used. 28 // This is to avoid confusion when looking at jump commands or calculating offsets for 29 // FD relocation. 30 type Nop struct{} 31 32 func (n *Nop) String() string { 33 return "nop" 34 } 35 36 func (n *Nop) Raw() ([]RawInstruction, error) { 37 return nil, nil 38 } 39 40 const ( 41 // BPFInstSize is the size of a BPF VM instruction 42 BPFInstSize = int(unsafe.Sizeof(RawInstruction{})) 43 ) 44 45 // A RawInstruction is a BPF virtual machine instruction. 46 type RawInstruction struct { 47 // Operation to execute. 48 Op uint8 49 // The operation register, split into source and destination register 50 // The upper 4 bits are the destination register, the lower 4 bits the source 51 Reg uint8 52 // 53 Off int16 54 // Constant parameter. The meaning depends on the Op. 55 Imm int32 56 } 57 58 func (i *RawInstruction) SetDestReg(v Register) { 59 i.Reg = (i.Reg & 0xF0) | (uint8(v) & 0x0F) 60 } 61 62 func (i *RawInstruction) GetDestReg() Register { 63 return Register(i.Reg & 0x0F) 64 } 65 66 func (i *RawInstruction) SetSourceReg(v Register) { 67 i.Reg = (i.Reg & 0x0F) | (uint8(v) << 4 & 0xF0) 68 } 69 70 func (i *RawInstruction) GetSourceReg() Register { 71 return Register((i.Reg & 0xF0) >> 4) 72 } 73 74 func NewReg(src Register, dest Register) uint8 { 75 return (uint8(src) << 4 & 0xF0) | (uint8(dest) & 0x0F) 76 } 77 78 // MustEncode does the same as Encode but rather than returning an error it will panic 79 func MustEncode(raw []Instruction) []RawInstruction { 80 inst, err := Encode(raw) 81 if err != nil { 82 panic(err) 83 } 84 85 return inst 86 } 87 88 // Encode turns a slice of instructions into raw instructions 89 func Encode(ins []Instruction) ([]RawInstruction, error) { 90 // The output will be at least as big as the input 91 instructions := make([]RawInstruction, 0, len(ins)) 92 for _, instruction := range ins { 93 rawInstructions, err := instruction.Raw() 94 if err != nil { 95 return nil, err 96 } 97 98 instructions = append(instructions, rawInstructions...) 99 } 100 101 return instructions, nil 102 } 103 104 type Size uint8 105 106 const ( 107 // BPF_W Word - 4 bytes 108 BPF_W Size = 0x00 109 // BPF_H Half-Word - 2 bytes 110 BPF_H Size = 0x08 111 // BPF_B Byte - 1 byte 112 BPF_B Size = 0x10 113 // BPF_DW Double-Word - 8 bytes 114 BPF_DW Size = 0x18 115 ) 116 117 func (s Size) String() string { 118 switch s { 119 case BPF_W: 120 return "u32" 121 case BPF_H: 122 return "u16" 123 case BPF_B: 124 return "u8" 125 case BPF_DW: 126 return "u64" 127 } 128 129 return "invalid" 130 } 131 132 func (s Size) Bytes() int { 133 switch s { 134 case BPF_W: 135 return 4 136 case BPF_H: 137 return 2 138 case BPF_B: 139 return 1 140 case BPF_DW: 141 return 8 142 } 143 144 return 0 145 } 146 147 // Register is a value used to indicate a source or destination register. 148 // Registers are used to pass arguments to variables and as scrach room for. 149 // See section 'BPF kernel internals' of https://www.kernel.org/doc/Documentation/networking/filter.rst 150 type Register uint8 151 152 const ( 153 // BPF_REG_0 aka R0 is the return value of the eBPF program, it is also used by helper functions and BPF to BPF 154 // calls for return values. 155 BPF_REG_0 Register = iota 156 // BPF_REG_1 aka R1 is the first argument of a helper function or BPF to BPF call, it is set at the start of 157 // a eBPF program to different values depending on the program type (typically a pointer to a struct). 158 // After calling a helper function or BPF function one should assume the constents will be changed. 159 BPF_REG_1 160 // BPF_REG_2 aka R2 is the second argument of a helper function or BPF to BPF call, it can be set at the start 161 // of the program depending on the program type but is typically not used. 162 // After calling a helper function or BPF function one should assume the constents will be changed. 163 BPF_REG_2 164 // BPF_REG_3 aka R3 is the third argument of a helper function or BPF to BPF call, it can be set at the start 165 // of the program depending on the program type but is typically not used. 166 // After calling a helper function or BPF function one should assume the constents will be changed. 167 BPF_REG_3 168 // BPF_REG_4 aka R4 is the forth argument of a helper function or BPF to BPF call, it can be set at the start 169 // of the program depending on the program type but is typically not used. 170 // After calling a helper function or BPF function one should assume the constents will be changed. 171 BPF_REG_4 172 // BPF_REG_5 aka R5 is the fifth argument of a helper function or BPF to BPF call, it can be set at the start 173 // of the program depending on the program type but is typically not used. 174 // After calling a helper function or BPF function one should assume the constents will be changed. 175 BPF_REG_5 176 // BPF_REG_6 aka R6 is a callee saved register for helper functions, meaning the contents will not be changed 177 // by the helper function. 178 BPF_REG_6 179 // BPF_REG_7 aka R7 is a callee saved register for helper functions, meaning the contents will not be changed 180 // by the helper function. 181 BPF_REG_7 182 // BPF_REG_8 aka R8 is a callee saved register for helper functions, meaning the contents will not be changed 183 // by the helper function. 184 BPF_REG_8 185 // BPF_REG_9 aka R9 is a callee saved register for helper functions, meaning the contents will not be changed 186 // by the helper function. 187 BPF_REG_9 188 // BPF_REG_10 aka R10 is a read-only register containing the frame pointer. It is a pointer to the start of 189 // the stack data reserved for this program. Each program/bpf to bpf function has its own stack. 190 BPF_REG_10 191 // BPF_REG_MAX is an invalid register, it is used for enumeration over registers. 192 BPF_REG_MAX 193 ) 194 195 // PSEUDO_CALL If the source register is 1, it is not a call to a helper function 196 // but to another bpf function(bpf to bpf call). 197 const PSEUDO_CALL Register = 0x01 198 199 func (r Register) String() string { 200 if r < BPF_REG_MAX { 201 return fmt.Sprintf("%d", r) 202 } 203 204 return "invalid" 205 } 206 207 const ( 208 // BPF_IMM Load intermediate values into registers 209 BPF_IMM uint8 = 0x00 210 // BPF_ABS Load values at intermediate offsets from the socketbuffer into memory 211 BPF_ABS uint8 = 0x20 212 // BPF_IND Load values at variable offsets from the socketbuffer into memory 213 BPF_IND uint8 = 0x40 214 // BPF_MEM Load values from memory into registers visa versa. 215 BPF_MEM uint8 = 0x60 216 // BPF_LEN not used in eBPF, reserved 217 BPF_LEN uint8 = 0x80 218 // BPF_MSH not used in eBPF, reserved 219 BPF_MSH uint8 = 0xa0 220 // BPF_ATOMIC atomic operators (for multi processor synchronization) 221 BPF_ATOMIC uint8 = 0xc0 222 ) 223 224 const ( 225 // BPF_LD is used for specialized load operations 226 BPF_LD uint8 = iota 227 // BPF_LDX is used for generic load operations 228 BPF_LDX 229 // BPF_ST is used for specialized store operations 230 BPF_ST 231 // BPF_STX is used for generic store operations 232 BPF_STX 233 // BPF_ALU is used for 32bit arithmatic operations 234 BPF_ALU 235 // BPF_JMP is used for 64bit branching operations 236 BPF_JMP 237 // BPF_JMP32 is used for 32bit branching operations 238 BPF_JMP32 239 // BPF_ALU64 is used for 64bit arithmatic operations 240 BPF_ALU64 241 ) 242 243 const ( 244 // BPF_K indicates that the source argument of an operation is an immediate value 245 BPF_K uint8 = 0x00 246 // BPF_X indicates that the source argument of an operation is a register 247 BPF_X uint8 = 0x08 248 ) 249 250 const ( 251 // BPF_ADD add two numbers 252 BPF_ADD uint8 = 0x00 253 // BPF_SUB subtract two numbers 254 BPF_SUB uint8 = 0x10 255 // BPF_MUL multiply two numbers 256 BPF_MUL uint8 = 0x20 257 // BPF_DIV divide two numbers 258 BPF_DIV uint8 = 0x30 259 // BPF_OR binary or two numbers 260 BPF_OR uint8 = 0x40 261 // BPF_AND binary and two numbers 262 BPF_AND uint8 = 0x50 263 // BPF_LSH left shift a number 264 BPF_LSH uint8 = 0x60 265 // BPF_RSH right shift a number 266 BPF_RSH uint8 = 0x70 267 // BPF_NEG negate/invert a number 268 BPF_NEG uint8 = 0x80 269 // BPF_MOD get the modulo of two numbers 270 BPF_MOD uint8 = 0x90 271 // BPF_XOR binary XOR two numbers 272 BPF_XOR uint8 = 0xa0 273 // BPF_MOV move register into another register 274 BPF_MOV uint8 = 0xb0 275 // BPF_ARSH Signed shift right 276 BPF_ARSH uint8 = 0xc0 277 // BPF_END endianness conversion 278 BPF_END uint8 = 0xd0 279 ) 280 281 const ( 282 // BPF_JA jump always 283 BPF_JA uint8 = 0x00 284 // BPF_JEQ jump equal 285 BPF_JEQ uint8 = 0x10 286 // BPF_JGT jump greater than 287 BPF_JGT uint8 = 0x20 288 // BPF_JGE jump greater than or equal 289 BPF_JGE uint8 = 0x30 290 // BPF_JSET jump if A & B == 0 291 BPF_JSET uint8 = 0x40 292 // BPF_JNE jump not equal 293 BPF_JNE uint8 = 0x50 294 // BPF_JSGT jump signed greater than 295 BPF_JSGT uint8 = 0x60 296 // BPF_JSGE jump signed greater than or equal 297 BPF_JSGE uint8 = 0x70 298 // BPF_CALL call a helper function or BPF to BPF call 299 BPF_CALL uint8 = 0x80 300 // BPF_CALLX call a helper function(indirect call), the ID of the helper is placed in a regisister indicated by 301 // imm. This call is illegal in the linux kernel, but can be emitted by clang when optimizations are disabled. 302 BPF_CALLX uint8 = 0x88 303 // BPF_EXIT exit the program 304 BPF_EXIT uint8 = 0x90 305 // BPF_JLT jump less than 306 BPF_JLT uint8 = 0xa0 307 // BPF_JLE jump less than equal 308 BPF_JLE uint8 = 0xb0 309 // BPF_JSLT jump signed less than 310 BPF_JSLT uint8 = 0xc0 311 // BPF_JSLE jump signed less then equal 312 BPF_JSLE uint8 = 0xd0 313 ) 314 315 const ( 316 // BPF_FETCH not an opcode on its own, used to build others 317 BPF_FETCH uint8 = 0x01 318 // BPF_XCHG atomic exchange 319 BPF_XCHG uint8 = (0xe0 | BPF_FETCH) 320 // BPF_CMPXCHG atomic compare-and-write 321 BPF_CMPXCHG uint8 = (0xf0 | BPF_FETCH) 322 ) 323 324 const ( 325 // BPF_TO_LE convert to little-endian 326 BPF_TO_LE uint8 = 0x00 327 // BPF_TO_BE convert to big-endian 328 BPF_TO_BE uint8 = 0x08 329 ) 330 331 const ( 332 // XDP_ABORTED exit program with an error 333 XDP_ABORTED = 0 334 // XDP_DROP drop the packet 335 XDP_DROP = 1 336 // XDP_PASS send packet to OS 337 XDP_PASS = 2 338 // XDP_TX send packet to egress on same port 339 XDP_TX = 3 340 // XDP_REDIRECT redirect to a different port, CPU or userspace 341 XDP_REDIRECT = 4 342 ) 343 344 // TODO add other return consts like for TC