123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- package internal
- import (
- "errors"
- "fmt"
- "path/filepath"
- "runtime"
- "syscall"
- "unsafe"
- "github.com/cilium/ebpf/internal/unix"
- )
- //go:generate stringer -output syscall_string.go -type=BPFCmd
- // BPFCmd identifies a subcommand of the bpf syscall.
- type BPFCmd int
- // Well known BPF commands.
- const (
- BPF_MAP_CREATE BPFCmd = iota
- BPF_MAP_LOOKUP_ELEM
- BPF_MAP_UPDATE_ELEM
- BPF_MAP_DELETE_ELEM
- BPF_MAP_GET_NEXT_KEY
- BPF_PROG_LOAD
- BPF_OBJ_PIN
- BPF_OBJ_GET
- BPF_PROG_ATTACH
- BPF_PROG_DETACH
- BPF_PROG_TEST_RUN
- BPF_PROG_GET_NEXT_ID
- BPF_MAP_GET_NEXT_ID
- BPF_PROG_GET_FD_BY_ID
- BPF_MAP_GET_FD_BY_ID
- BPF_OBJ_GET_INFO_BY_FD
- BPF_PROG_QUERY
- BPF_RAW_TRACEPOINT_OPEN
- BPF_BTF_LOAD
- BPF_BTF_GET_FD_BY_ID
- BPF_TASK_FD_QUERY
- BPF_MAP_LOOKUP_AND_DELETE_ELEM
- BPF_MAP_FREEZE
- BPF_BTF_GET_NEXT_ID
- BPF_MAP_LOOKUP_BATCH
- BPF_MAP_LOOKUP_AND_DELETE_BATCH
- BPF_MAP_UPDATE_BATCH
- BPF_MAP_DELETE_BATCH
- BPF_LINK_CREATE
- BPF_LINK_UPDATE
- BPF_LINK_GET_FD_BY_ID
- BPF_LINK_GET_NEXT_ID
- BPF_ENABLE_STATS
- BPF_ITER_CREATE
- )
- // BPF wraps SYS_BPF.
- //
- // Any pointers contained in attr must use the Pointer type from this package.
- func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
- r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size)
- runtime.KeepAlive(attr)
- var err error
- if errNo != 0 {
- err = wrappedErrno{errNo}
- }
- return r1, err
- }
- type BPFProgLoadAttr struct {
- ProgType uint32
- InsCount uint32
- Instructions Pointer
- License Pointer
- LogLevel uint32
- LogSize uint32
- LogBuf Pointer
- KernelVersion uint32 // since 4.1 2541517c32be
- ProgFlags uint32 // since 4.11 e07b98d9bffe
- ProgName BPFObjName // since 4.15 067cae47771c
- ProgIfIndex uint32 // since 4.15 1f6f4cb7ba21
- ExpectedAttachType uint32 // since 4.17 5e43f899b03a
- ProgBTFFd uint32
- FuncInfoRecSize uint32
- FuncInfo Pointer
- FuncInfoCnt uint32
- LineInfoRecSize uint32
- LineInfo Pointer
- LineInfoCnt uint32
- AttachBTFID uint32
- AttachProgFd uint32
- }
- // BPFProgLoad wraps BPF_PROG_LOAD.
- func BPFProgLoad(attr *BPFProgLoadAttr) (*FD, error) {
- for {
- fd, err := BPF(BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
- // As of ~4.20 the verifier can be interrupted by a signal,
- // and returns EAGAIN in that case.
- if errors.Is(err, unix.EAGAIN) {
- continue
- }
- if err != nil {
- return nil, err
- }
- return NewFD(uint32(fd)), nil
- }
- }
- type BPFProgAttachAttr struct {
- TargetFd uint32
- AttachBpfFd uint32
- AttachType uint32
- AttachFlags uint32
- ReplaceBpfFd uint32
- }
- func BPFProgAttach(attr *BPFProgAttachAttr) error {
- _, err := BPF(BPF_PROG_ATTACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
- return err
- }
- type BPFProgDetachAttr struct {
- TargetFd uint32
- AttachBpfFd uint32
- AttachType uint32
- }
- func BPFProgDetach(attr *BPFProgDetachAttr) error {
- _, err := BPF(BPF_PROG_DETACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
- return err
- }
- type BPFEnableStatsAttr struct {
- StatsType uint32
- }
- func BPFEnableStats(attr *BPFEnableStatsAttr) (*FD, error) {
- ptr, err := BPF(BPF_ENABLE_STATS, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
- if err != nil {
- return nil, fmt.Errorf("enable stats: %w", err)
- }
- return NewFD(uint32(ptr)), nil
- }
- type bpfObjAttr struct {
- fileName Pointer
- fd uint32
- fileFlags uint32
- }
- const bpfFSType = 0xcafe4a11
- // BPFObjPin wraps BPF_OBJ_PIN.
- func BPFObjPin(fileName string, fd *FD) error {
- dirName := filepath.Dir(fileName)
- var statfs unix.Statfs_t
- if err := unix.Statfs(dirName, &statfs); err != nil {
- return err
- }
- if uint64(statfs.Type) != bpfFSType {
- return fmt.Errorf("%s is not on a bpf filesystem", fileName)
- }
- value, err := fd.Value()
- if err != nil {
- return err
- }
- attr := bpfObjAttr{
- fileName: NewStringPointer(fileName),
- fd: value,
- }
- _, err = BPF(BPF_OBJ_PIN, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
- if err != nil {
- return fmt.Errorf("pin object %s: %w", fileName, err)
- }
- return nil
- }
- // BPFObjGet wraps BPF_OBJ_GET.
- func BPFObjGet(fileName string, flags uint32) (*FD, error) {
- attr := bpfObjAttr{
- fileName: NewStringPointer(fileName),
- fileFlags: flags,
- }
- ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
- if err != nil {
- return nil, fmt.Errorf("get object %s: %w", fileName, err)
- }
- return NewFD(uint32(ptr)), nil
- }
- type bpfObjGetInfoByFDAttr struct {
- fd uint32
- infoLen uint32
- info Pointer
- }
- // BPFObjGetInfoByFD wraps BPF_OBJ_GET_INFO_BY_FD.
- //
- // Available from 4.13.
- func BPFObjGetInfoByFD(fd *FD, info unsafe.Pointer, size uintptr) error {
- value, err := fd.Value()
- if err != nil {
- return err
- }
- attr := bpfObjGetInfoByFDAttr{
- fd: value,
- infoLen: uint32(size),
- info: NewPointer(info),
- }
- _, err = BPF(BPF_OBJ_GET_INFO_BY_FD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
- if err != nil {
- return fmt.Errorf("fd %v: %w", fd, err)
- }
- return nil
- }
- type bpfGetFDByIDAttr struct {
- id uint32
- next uint32
- }
- // BPFObjGetInfoByFD wraps BPF_*_GET_FD_BY_ID.
- //
- // Available from 4.13.
- func BPFObjGetFDByID(cmd BPFCmd, id uint32) (*FD, error) {
- attr := bpfGetFDByIDAttr{
- id: id,
- }
- ptr, err := BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
- return NewFD(uint32(ptr)), err
- }
- // BPFObjName is a null-terminated string made up of
- // 'A-Za-z0-9_' characters.
- type BPFObjName [unix.BPF_OBJ_NAME_LEN]byte
- // NewBPFObjName truncates the result if it is too long.
- func NewBPFObjName(name string) BPFObjName {
- var result BPFObjName
- copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
- return result
- }
- type BPFMapCreateAttr struct {
- MapType uint32
- KeySize uint32
- ValueSize uint32
- MaxEntries uint32
- Flags uint32
- InnerMapFd uint32 // since 4.12 56f668dfe00d
- NumaNode uint32 // since 4.14 96eabe7a40aa
- MapName BPFObjName // since 4.15 ad5b177bd73f
- MapIfIndex uint32
- BTFFd uint32
- BTFKeyTypeID uint32
- BTFValueTypeID uint32
- }
- func BPFMapCreate(attr *BPFMapCreateAttr) (*FD, error) {
- fd, err := BPF(BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
- if err != nil {
- return nil, err
- }
- return NewFD(uint32(fd)), nil
- }
- // 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
- }
- type syscallError struct {
- error
- errno syscall.Errno
- }
- func SyscallError(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
- }
|