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