internal: export BPFProgLoad syscall wrapper
Signed-off-by: Robin Gögge <r.goegge@gmail.com>
Robin Gögge authored 2 years ago
Timo Beckers committed 2 years ago
0 | 0 | package internal |
1 | 1 | |
2 | 2 | import ( |
3 | "errors" | |
3 | 4 | "fmt" |
4 | 5 | "path/filepath" |
5 | 6 | "runtime" |
67 | 68 | return r1, err |
68 | 69 | } |
69 | 70 | |
71 | type BPFProgLoadAttr struct { | |
72 | ProgType uint32 | |
73 | InsCount uint32 | |
74 | Instructions Pointer | |
75 | License Pointer | |
76 | LogLevel uint32 | |
77 | LogSize uint32 | |
78 | LogBuf Pointer | |
79 | KernelVersion uint32 // since 4.1 2541517c32be | |
80 | ProgFlags uint32 // since 4.11 e07b98d9bffe | |
81 | ProgName BPFObjName // since 4.15 067cae47771c | |
82 | ProgIfIndex uint32 // since 4.15 1f6f4cb7ba21 | |
83 | ExpectedAttachType uint32 // since 4.17 5e43f899b03a | |
84 | ProgBTFFd uint32 | |
85 | FuncInfoRecSize uint32 | |
86 | FuncInfo Pointer | |
87 | FuncInfoCnt uint32 | |
88 | LineInfoRecSize uint32 | |
89 | LineInfo Pointer | |
90 | LineInfoCnt uint32 | |
91 | AttachBTFID uint32 | |
92 | AttachProgFd uint32 | |
93 | } | |
94 | ||
95 | // BPFProgLoad wraps BPF_PROG_LOAD. | |
96 | func BPFProgLoad(attr *BPFProgLoadAttr) (*FD, error) { | |
97 | for { | |
98 | fd, err := BPF(BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | |
99 | // As of ~4.20 the verifier can be interrupted by a signal, | |
100 | // and returns EAGAIN in that case. | |
101 | if errors.Is(err, unix.EAGAIN) { | |
102 | continue | |
103 | } | |
104 | ||
105 | if err != nil { | |
106 | return nil, err | |
107 | } | |
108 | ||
109 | return NewFD(uint32(fd)), nil | |
110 | } | |
111 | } | |
112 | ||
70 | 113 | type BPFProgAttachAttr struct { |
71 | 114 | TargetFd uint32 |
72 | 115 | AttachBpfFd uint32 |
170 | 170 | kv = v.Kernel() |
171 | 171 | } |
172 | 172 | |
173 | attr := &bpfProgLoadAttr{ | |
174 | progType: spec.Type, | |
175 | progFlags: spec.Flags, | |
176 | expectedAttachType: spec.AttachType, | |
177 | license: internal.NewStringPointer(spec.License), | |
178 | kernelVersion: kv, | |
173 | attr := &internal.BPFProgLoadAttr{ | |
174 | ProgType: uint32(spec.Type), | |
175 | ProgFlags: spec.Flags, | |
176 | ExpectedAttachType: uint32(spec.AttachType), | |
177 | License: internal.NewStringPointer(spec.License), | |
178 | KernelVersion: kv, | |
179 | 179 | } |
180 | 180 | |
181 | 181 | if haveObjName() == nil { |
182 | attr.progName = internal.NewBPFObjName(spec.Name) | |
182 | attr.ProgName = internal.NewBPFObjName(spec.Name) | |
183 | 183 | } |
184 | 184 | |
185 | 185 | var err error |
206 | 206 | } |
207 | 207 | |
208 | 208 | if handle != nil { |
209 | attr.progBTFFd = uint32(handle.FD()) | |
209 | attr.ProgBTFFd = uint32(handle.FD()) | |
210 | 210 | |
211 | 211 | recSize, bytes, err := btf.ProgramLineInfos(spec.BTF) |
212 | 212 | if err != nil { |
213 | 213 | return nil, fmt.Errorf("get BTF line infos: %w", err) |
214 | 214 | } |
215 | attr.lineInfoRecSize = recSize | |
216 | attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) | |
217 | attr.lineInfo = internal.NewSlicePointer(bytes) | |
215 | attr.LineInfoRecSize = recSize | |
216 | attr.LineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) | |
217 | attr.LineInfo = internal.NewSlicePointer(bytes) | |
218 | 218 | |
219 | 219 | recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF) |
220 | 220 | if err != nil { |
221 | 221 | return nil, fmt.Errorf("get BTF function infos: %w", err) |
222 | 222 | } |
223 | attr.funcInfoRecSize = recSize | |
224 | attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) | |
225 | attr.funcInfo = internal.NewSlicePointer(bytes) | |
223 | attr.FuncInfoRecSize = recSize | |
224 | attr.FuncInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) | |
225 | attr.FuncInfo = internal.NewSlicePointer(bytes) | |
226 | 226 | } |
227 | 227 | } |
228 | 228 | |
242 | 242 | } |
243 | 243 | |
244 | 244 | bytecode := buf.Bytes() |
245 | attr.instructions = internal.NewSlicePointer(bytecode) | |
246 | attr.insCount = uint32(len(bytecode) / asm.InstructionSize) | |
245 | attr.Instructions = internal.NewSlicePointer(bytecode) | |
246 | attr.InsCount = uint32(len(bytecode) / asm.InstructionSize) | |
247 | 247 | |
248 | 248 | if spec.AttachTo != "" { |
249 | 249 | if spec.AttachTarget != nil { |
272 | 272 | return nil, err |
273 | 273 | } |
274 | 274 | if target != nil { |
275 | attr.attachBTFID = target.ID() | |
275 | attr.AttachBTFID = uint32(target.ID()) | |
276 | 276 | } |
277 | 277 | if spec.AttachTarget != nil { |
278 | attr.attachProgFd = uint32(spec.AttachTarget.FD()) | |
278 | attr.AttachProgFd = uint32(spec.AttachTarget.FD()) | |
279 | 279 | } |
280 | 280 | } |
281 | 281 | |
287 | 287 | var logBuf []byte |
288 | 288 | if opts.LogLevel > 0 { |
289 | 289 | logBuf = make([]byte, logSize) |
290 | attr.logLevel = opts.LogLevel | |
291 | attr.logSize = uint32(len(logBuf)) | |
292 | attr.logBuf = internal.NewSlicePointer(logBuf) | |
293 | } | |
294 | ||
295 | fd, err := bpfProgLoad(attr) | |
290 | attr.LogLevel = opts.LogLevel | |
291 | attr.LogSize = uint32(len(logBuf)) | |
292 | attr.LogBuf = internal.NewSlicePointer(logBuf) | |
293 | } | |
294 | ||
295 | fd, err := internal.BPFProgLoad(attr) | |
296 | 296 | if err == nil { |
297 | 297 | return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil |
298 | 298 | } |
301 | 301 | if opts.LogLevel == 0 && opts.LogSize >= 0 { |
302 | 302 | // Re-run with the verifier enabled to get better error messages. |
303 | 303 | logBuf = make([]byte, logSize) |
304 | attr.logLevel = 1 | |
305 | attr.logSize = uint32(len(logBuf)) | |
306 | attr.logBuf = internal.NewSlicePointer(logBuf) | |
307 | ||
308 | _, logErr = bpfProgLoad(attr) | |
304 | attr.LogLevel = 1 | |
305 | attr.LogSize = uint32(len(logBuf)) | |
306 | attr.LogBuf = internal.NewSlicePointer(logBuf) | |
307 | ||
308 | _, logErr = internal.BPFProgLoad(attr) | |
309 | 309 | } |
310 | 310 | |
311 | 311 | if errors.Is(logErr, unix.EPERM) && logBuf[0] == 0 { |
6 | 6 | "unsafe" |
7 | 7 | |
8 | 8 | "github.com/cilium/ebpf/internal" |
9 | "github.com/cilium/ebpf/internal/btf" | |
10 | 9 | "github.com/cilium/ebpf/internal/unix" |
11 | 10 | ) |
12 | 11 | |
70 | 69 | btf_id uint32 // since 4.18 78958fca7ead |
71 | 70 | btf_key_type_id uint32 // since 4.18 9b2cf328b2ec |
72 | 71 | btf_value_type_id uint32 |
73 | } | |
74 | ||
75 | type bpfProgLoadAttr struct { | |
76 | progType ProgramType | |
77 | insCount uint32 | |
78 | instructions internal.Pointer | |
79 | license internal.Pointer | |
80 | logLevel uint32 | |
81 | logSize uint32 | |
82 | logBuf internal.Pointer | |
83 | kernelVersion uint32 // since 4.1 2541517c32be | |
84 | progFlags uint32 // since 4.11 e07b98d9bffe | |
85 | progName internal.BPFObjName // since 4.15 067cae47771c | |
86 | progIfIndex uint32 // since 4.15 1f6f4cb7ba21 | |
87 | expectedAttachType AttachType // since 4.17 5e43f899b03a | |
88 | progBTFFd uint32 | |
89 | funcInfoRecSize uint32 | |
90 | funcInfo internal.Pointer | |
91 | funcInfoCnt uint32 | |
92 | lineInfoRecSize uint32 | |
93 | lineInfo internal.Pointer | |
94 | lineInfoCnt uint32 | |
95 | attachBTFID btf.TypeID | |
96 | attachProgFd uint32 | |
97 | 72 | } |
98 | 73 | |
99 | 74 | type bpfProgInfo struct { |
154 | 129 | openFlags uint32 |
155 | 130 | } |
156 | 131 | |
157 | func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) { | |
158 | for { | |
159 | fd, err := internal.BPF(internal.BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | |
160 | // As of ~4.20 the verifier can be interrupted by a signal, | |
161 | // and returns EAGAIN in that case. | |
162 | if errors.Is(err, unix.EAGAIN) { | |
163 | continue | |
164 | } | |
165 | ||
166 | if err != nil { | |
167 | return nil, err | |
168 | } | |
169 | ||
170 | return internal.NewFD(uint32(fd)), nil | |
171 | } | |
172 | } | |
173 | ||
174 | 132 | func bpfProgTestRun(attr *bpfProgTestRunAttr) error { |
175 | 133 | _, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) |
176 | 134 | return err |