| package sys |
| |
| import ( |
| "runtime" |
| "syscall" |
| "unsafe" |
| |
| "github.com/cilium/ebpf/internal/unix" |
| ) |
| |
| // ENOTSUPP is a Linux internal error code that has leaked into UAPI. |
| // |
| // It is not the same as ENOTSUP or EOPNOTSUPP. |
| const ENOTSUPP = syscall.Errno(524) |
| |
| // BPF wraps SYS_BPF. |
| // |
| // Any pointers contained in attr must use the Pointer type from this package. |
| func BPF(cmd Cmd, attr unsafe.Pointer, size uintptr) (uintptr, error) { |
| // Prevent the Go profiler from repeatedly interrupting the verifier, |
| // which could otherwise lead to a livelock due to receiving EAGAIN. |
| if cmd == BPF_PROG_LOAD || cmd == BPF_PROG_RUN { |
| maskProfilerSignal() |
| defer unmaskProfilerSignal() |
| } |
| |
| for { |
| r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size) |
| runtime.KeepAlive(attr) |
| |
| // As of ~4.20 the verifier can be interrupted by a signal, |
| // and returns EAGAIN in that case. |
| if errNo == unix.EAGAIN && cmd == BPF_PROG_LOAD { |
| continue |
| } |
| |
| var err error |
| if errNo != 0 { |
| err = wrappedErrno{errNo} |
| } |
| |
| return r1, err |
| } |
| } |
| |
| // Info is implemented by all structs that can be passed to the ObjInfo syscall. |
| // |
| // MapInfo |
| // ProgInfo |
| // LinkInfo |
| // BtfInfo |
| type Info interface { |
| info() (unsafe.Pointer, uint32) |
| } |
| |
| var _ Info = (*MapInfo)(nil) |
| |
| func (i *MapInfo) info() (unsafe.Pointer, uint32) { |
| return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i)) |
| } |
| |
| var _ Info = (*ProgInfo)(nil) |
| |
| func (i *ProgInfo) info() (unsafe.Pointer, uint32) { |
| return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i)) |
| } |
| |
| var _ Info = (*LinkInfo)(nil) |
| |
| func (i *LinkInfo) info() (unsafe.Pointer, uint32) { |
| return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i)) |
| } |
| |
| var _ Info = (*BtfInfo)(nil) |
| |
| func (i *BtfInfo) info() (unsafe.Pointer, uint32) { |
| return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i)) |
| } |
| |
| // ObjInfo retrieves information about a BPF Fd. |
| // |
| // info may be one of MapInfo, ProgInfo, LinkInfo and BtfInfo. |
| func ObjInfo(fd *FD, info Info) error { |
| ptr, len := info.info() |
| err := ObjGetInfoByFd(&ObjGetInfoByFdAttr{ |
| BpfFd: fd.Uint(), |
| InfoLen: len, |
| Info: NewPointer(ptr), |
| }) |
| runtime.KeepAlive(fd) |
| return err |
| } |
| |
| // BPFObjName is a null-terminated string made up of |
| // 'A-Za-z0-9_' characters. |
| type ObjName [unix.BPF_OBJ_NAME_LEN]byte |
| |
| // NewObjName truncates the result if it is too long. |
| func NewObjName(name string) ObjName { |
| var result ObjName |
| copy(result[:unix.BPF_OBJ_NAME_LEN-1], name) |
| return result |
| } |
| |
| // LogLevel controls the verbosity of the kernel's eBPF program verifier. |
| type LogLevel uint32 |
| |
| const ( |
| BPF_LOG_LEVEL1 LogLevel = 1 << iota |
| BPF_LOG_LEVEL2 |
| BPF_LOG_STATS |
| ) |
| |
| // LinkID uniquely identifies a bpf_link. |
| type LinkID uint32 |
| |
| // BTFID uniquely identifies a BTF blob loaded into the kernel. |
| type BTFID uint32 |
| |
| // TypeID identifies a type in a BTF blob. |
| type TypeID uint32 |
| |
| // MapFlags control map behaviour. |
| type MapFlags uint32 |
| |
| //go:generate go run golang.org/x/tools/cmd/stringer@latest -type MapFlags |
| |
| const ( |
| BPF_F_NO_PREALLOC MapFlags = 1 << iota |
| BPF_F_NO_COMMON_LRU |
| BPF_F_NUMA_NODE |
| BPF_F_RDONLY |
| BPF_F_WRONLY |
| BPF_F_STACK_BUILD_ID |
| BPF_F_ZERO_SEED |
| BPF_F_RDONLY_PROG |
| BPF_F_WRONLY_PROG |
| BPF_F_CLONE |
| BPF_F_MMAPABLE |
| BPF_F_PRESERVE_ELEMS |
| BPF_F_INNER_MAP |
| ) |
| |
| // wrappedErrno wraps syscall.Errno to prevent direct comparisons with |
| // syscall.E* or unix.E* constants. |
| // |
| // You should never export an error of this type. |
| type wrappedErrno struct { |
| syscall.Errno |
| } |
| |
| func (we wrappedErrno) Unwrap() error { |
| return we.Errno |
| } |
| |
| func (we wrappedErrno) Error() string { |
| if we.Errno == ENOTSUPP { |
| return "operation not supported" |
| } |
| return we.Errno.Error() |
| } |
| |
| type syscallError struct { |
| error |
| errno syscall.Errno |
| } |
| |
| func Error(err error, errno syscall.Errno) error { |
| return &syscallError{err, errno} |
| } |
| |
| func (se *syscallError) Is(target error) bool { |
| return target == se.error |
| } |
| |
| func (se *syscallError) Unwrap() error { |
| return se.errno |
| } |