forked from dropbox/goebpf
/
program_base.go
136 lines (117 loc) · 3.23 KB
/
program_base.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (c) 2019 Dropbox, Inc.
// Full license can be found in the LICENSE file.
package goebpf
/*
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include "bpf.h"
#include "bpf_helpers.h"
// Load eBPF program into kernel
static int ebpf_prog_load(const char *name, __u32 prog_type, const void *insns, __u32 insns_cnt,
const char *license, __u32 kern_version, void *log_buf, size_t log_size)
{
union bpf_attr attr = {};
// Try to load program without trace info - it takes too much memory
// for verifier to put all trace messages even for correct programs
// and may cause load error because of log buffer is too small.
attr.prog_type = prog_type;
attr.insn_cnt = insns_cnt;
attr.insns = ptr_to_u64(insns);
attr.license = ptr_to_u64(license);
attr.log_buf = ptr_to_u64(NULL);
attr.log_size = 0;
attr.log_level = 0;
attr.kern_version = kern_version;
// program name
strncpy((char*)&attr.prog_name, name, BPF_OBJ_NAME_LEN - 1);
#ifdef __linux__
int res = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
if (res == -1) {
// Try again with log
attr.log_buf = ptr_to_u64(log_buf);
attr.log_size = log_size;
attr.log_level = 1;
res = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}
return res;
#else
return 0;
#endif
}
*/
import "C"
import (
"errors"
"fmt"
"unsafe"
)
// Load loads program into linux kernel
func (prog *BaseProgram) Load() error {
// Sanity checks
if len(prog.name) >= C.BPF_OBJ_NAME_LEN {
return fmt.Errorf("Program name '%s' is too long", prog.name)
}
// Buffer for kernel's verified debug messages
var logBuf [logBufferSize]byte
// Program name / license
name := C.CString(prog.name)
defer C.free(unsafe.Pointer(name))
license := C.CString(prog.license)
defer C.free(unsafe.Pointer(license))
// Load eBPF program
res := int(C.ebpf_prog_load(
name,
C.__u32(prog.GetType()),
unsafe.Pointer(&prog.bytecode[0]),
C.__u32(prog.GetSize())/bpfInstructionLen,
license,
C.__u32(prog.kernelVersion),
unsafe.Pointer(&logBuf[0]),
C.size_t(unsafe.Sizeof(logBuf))))
if res == -1 {
return fmt.Errorf("ebpf_prog_load() failed: %s",
NullTerminatedStringToString(logBuf[:]))
}
prog.fd = res
return nil
}
// Close unloads program from kernel
func (prog *BaseProgram) Close() error {
if prog.fd == 0 {
return errors.New("Already closed / not created")
}
err := closeFd(prog.fd)
if err != nil {
return err
}
prog.fd = 0
return nil
}
// Pin saves ("pins") file description into special file on filesystem
// so it can be accessed from other processes.
// WARNING: destination filesystem must be mounted as "bpf" (mount -t bpf)
func (prog *BaseProgram) Pin(path string) error {
return ebpfObjPin(prog.fd, path)
}
// GetName returns program name as defined in C code
func (prog *BaseProgram) GetName() string {
return prog.name
}
// GetType returns program type
func (prog *BaseProgram) GetType() ProgramType {
return prog.programType
}
// GetFd returns program's file description
func (prog *BaseProgram) GetFd() int {
return prog.fd
}
// GetSize returns eBPF bytecode size in bytes
func (prog *BaseProgram) GetSize() int {
return len(prog.bytecode)
}
// GetLicense returns program's license
func (prog *BaseProgram) GetLicense() string {
return prog.license
}