180 lines
3.7 KiB
Go
180 lines
3.7 KiB
Go
|
package internal
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
|
"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 = errNo
|
||
|
}
|
||
|
|
||
|
return r1, err
|
||
|
}
|
||
|
|
||
|
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) (*FD, error) {
|
||
|
attr := bpfObjAttr{
|
||
|
fileName: NewStringPointer(fileName),
|
||
|
}
|
||
|
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
|
||
|
}
|