Pin dependency github.com/cilium/ebpf
Use same as opencontainers/runc
This commit is contained in:
parent
088ee920e0
commit
5ba2a8da09
4
go.mod
4
go.mod
@ -28,7 +28,7 @@ require (
|
|||||||
github.com/caddyserver/caddy v1.0.3
|
github.com/caddyserver/caddy v1.0.3
|
||||||
github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c
|
github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c
|
||||||
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 // indirect
|
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 // indirect
|
||||||
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3 // indirect
|
github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed // indirect
|
||||||
github.com/client9/misspell v0.3.4
|
github.com/client9/misspell v0.3.4
|
||||||
github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313
|
github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313
|
||||||
github.com/codegangsta/negroni v1.0.0 // indirect
|
github.com/codegangsta/negroni v1.0.0 // indirect
|
||||||
@ -222,7 +222,7 @@ replace (
|
|||||||
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
|
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
|
||||||
github.com/checkpoint-restore/go-criu => github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 // 17b0214f6c48 is the SHA for git tag 3.11
|
github.com/checkpoint-restore/go-criu => github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 // 17b0214f6c48 is the SHA for git tag 3.11
|
||||||
github.com/cheekybits/genny => github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9
|
github.com/cheekybits/genny => github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9
|
||||||
github.com/cilium/ebpf => github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3
|
github.com/cilium/ebpf => github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed
|
||||||
github.com/client9/misspell => github.com/client9/misspell v0.3.4
|
github.com/client9/misspell => github.com/client9/misspell v0.3.4
|
||||||
github.com/clusterhq/flocker-go => github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313
|
github.com/clusterhq/flocker-go => github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313
|
||||||
github.com/cockroachdb/datadriven => github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa
|
github.com/cockroachdb/datadriven => github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa
|
||||||
|
4
go.sum
4
go.sum
@ -86,8 +86,8 @@ github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1
|
|||||||
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 h1:AQMF0Xixllgf29MKlx/TGEhRk7bEDX5kxz8Ui8lOvEs=
|
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 h1:AQMF0Xixllgf29MKlx/TGEhRk7bEDX5kxz8Ui8lOvEs=
|
||||||
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
|
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
|
||||||
github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3 h1:i8+1fuPLjSgAYXUyBlHNhFwjcfAsP4ufiuH1+PWkyDU=
|
github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed h1:/UgmF+cZTm9kp4uJ122y/9cVhczNJCgAgAeH2FfzPeg=
|
||||||
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
|
github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
|
||||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313 h1:eIHD9GNM3Hp7kcRW5mvcz7WTR3ETeoYYKwpgA04kaXE=
|
github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313 h1:eIHD9GNM3Hp7kcRW5mvcz7WTR3ETeoYYKwpgA04kaXE=
|
||||||
|
5
vendor/github.com/cilium/ebpf/BUILD
generated
vendored
5
vendor/github.com/cilium/ebpf/BUILD
generated
vendored
@ -7,10 +7,14 @@ go_library(
|
|||||||
"collection.go",
|
"collection.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"elf_reader.go",
|
"elf_reader.go",
|
||||||
|
"feature.go",
|
||||||
"linker.go",
|
"linker.go",
|
||||||
"map.go",
|
"map.go",
|
||||||
"marshalers.go",
|
"marshalers.go",
|
||||||
"prog.go",
|
"prog.go",
|
||||||
|
"ptr_32_be.go",
|
||||||
|
"ptr_32_le.go",
|
||||||
|
"ptr_64.go",
|
||||||
"syscalls.go",
|
"syscalls.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
"types_string.go",
|
"types_string.go",
|
||||||
@ -21,7 +25,6 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/cilium/ebpf/asm:go_default_library",
|
"//vendor/github.com/cilium/ebpf/asm:go_default_library",
|
||||||
"//vendor/github.com/cilium/ebpf/internal:go_default_library",
|
"//vendor/github.com/cilium/ebpf/internal:go_default_library",
|
||||||
"//vendor/github.com/cilium/ebpf/internal/btf:go_default_library",
|
|
||||||
"//vendor/github.com/cilium/ebpf/internal/unix:go_default_library",
|
"//vendor/github.com/cilium/ebpf/internal/unix:go_default_library",
|
||||||
"//vendor/github.com/pkg/errors:go_default_library",
|
"//vendor/github.com/pkg/errors:go_default_library",
|
||||||
],
|
],
|
||||||
|
277
vendor/github.com/cilium/ebpf/abi.go
generated
vendored
277
vendor/github.com/cilium/ebpf/abi.go
generated
vendored
@ -1,90 +1,143 @@
|
|||||||
package ebpf
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MapABI are the attributes of a Map which are available across all supported kernels.
|
// CollectionABI describes the interface of an eBPF collection.
|
||||||
|
type CollectionABI struct {
|
||||||
|
Maps map[string]*MapABI
|
||||||
|
Programs map[string]*ProgramABI
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckSpec verifies that all maps and programs mentioned
|
||||||
|
// in the ABI are present in the spec.
|
||||||
|
func (abi *CollectionABI) CheckSpec(cs *CollectionSpec) error {
|
||||||
|
for name := range abi.Maps {
|
||||||
|
if cs.Maps[name] == nil {
|
||||||
|
return errors.Errorf("missing map %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for name := range abi.Programs {
|
||||||
|
if cs.Programs[name] == nil {
|
||||||
|
return errors.Errorf("missing program %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check verifies that all items in a collection conform to this ABI.
|
||||||
|
func (abi *CollectionABI) Check(coll *Collection) error {
|
||||||
|
for name, mapABI := range abi.Maps {
|
||||||
|
m := coll.Maps[name]
|
||||||
|
if m == nil {
|
||||||
|
return errors.Errorf("missing map %s", name)
|
||||||
|
}
|
||||||
|
if err := mapABI.Check(m); err != nil {
|
||||||
|
return errors.Wrapf(err, "map %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, progABI := range abi.Programs {
|
||||||
|
p := coll.Programs[name]
|
||||||
|
if p == nil {
|
||||||
|
return errors.Errorf("missing program %s", name)
|
||||||
|
}
|
||||||
|
if err := progABI.Check(p); err != nil {
|
||||||
|
return errors.Wrapf(err, "program %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapABI describes a Map.
|
||||||
|
//
|
||||||
|
// Use it to assert that a Map matches what your code expects.
|
||||||
type MapABI struct {
|
type MapABI struct {
|
||||||
Type MapType
|
Type MapType
|
||||||
KeySize uint32
|
KeySize uint32
|
||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
Flags uint32
|
InnerMap *MapABI
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMapABIFromSpec(spec *MapSpec) *MapABI {
|
func newMapABIFromSpec(spec *MapSpec) *MapABI {
|
||||||
|
var inner *MapABI
|
||||||
|
if spec.InnerMap != nil {
|
||||||
|
inner = newMapABIFromSpec(spec.InnerMap)
|
||||||
|
}
|
||||||
|
|
||||||
return &MapABI{
|
return &MapABI{
|
||||||
spec.Type,
|
spec.Type,
|
||||||
spec.KeySize,
|
spec.KeySize,
|
||||||
spec.ValueSize,
|
spec.ValueSize,
|
||||||
spec.MaxEntries,
|
spec.MaxEntries,
|
||||||
spec.Flags,
|
inner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMapABIFromFd(fd *internal.FD) (string, *MapABI, error) {
|
func newMapABIFromFd(fd *bpfFD) (*MapABI, error) {
|
||||||
info, err := bpfGetMapInfoByFD(fd)
|
info, err := bpfGetMapInfoByFD(fd)
|
||||||
if err != nil {
|
|
||||||
if errors.Cause(err) == syscall.EINVAL {
|
|
||||||
abi, err := newMapABIFromProc(fd)
|
|
||||||
return "", abi, err
|
|
||||||
}
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", &MapABI{
|
|
||||||
MapType(info.mapType),
|
|
||||||
info.keySize,
|
|
||||||
info.valueSize,
|
|
||||||
info.maxEntries,
|
|
||||||
info.flags,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapABIFromProc(fd *internal.FD) (*MapABI, error) {
|
|
||||||
var abi MapABI
|
|
||||||
err := scanFdInfo(fd, map[string]interface{}{
|
|
||||||
"map_type": &abi.Type,
|
|
||||||
"key_size": &abi.KeySize,
|
|
||||||
"value_size": &abi.ValueSize,
|
|
||||||
"max_entries": &abi.MaxEntries,
|
|
||||||
"map_flags": &abi.Flags,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &abi, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal returns true if two ABIs have the same values.
|
mapType := MapType(info.mapType)
|
||||||
func (abi *MapABI) Equal(other *MapABI) bool {
|
if mapType == ArrayOfMaps || mapType == HashOfMaps {
|
||||||
switch {
|
return nil, errors.New("can't get map info for nested maps")
|
||||||
case abi.Type != other.Type:
|
|
||||||
return false
|
|
||||||
case abi.KeySize != other.KeySize:
|
|
||||||
return false
|
|
||||||
case abi.ValueSize != other.ValueSize:
|
|
||||||
return false
|
|
||||||
case abi.MaxEntries != other.MaxEntries:
|
|
||||||
return false
|
|
||||||
case abi.Flags != other.Flags:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return &MapABI{
|
||||||
|
mapType,
|
||||||
|
info.keySize,
|
||||||
|
info.valueSize,
|
||||||
|
info.maxEntries,
|
||||||
|
nil,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProgramABI are the attributes of a Program which are available across all supported kernels.
|
// Check verifies that a Map conforms to the ABI.
|
||||||
|
//
|
||||||
|
// Members of ABI which have the zero value of their type are not checked.
|
||||||
|
func (abi *MapABI) Check(m *Map) error {
|
||||||
|
return abi.check(&m.abi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (abi *MapABI) check(other *MapABI) error {
|
||||||
|
if abi.Type != UnspecifiedMap && other.Type != abi.Type {
|
||||||
|
return errors.Errorf("expected map type %s, have %s", abi.Type, other.Type)
|
||||||
|
}
|
||||||
|
if err := checkUint32("key size", abi.KeySize, other.KeySize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkUint32("value size", abi.ValueSize, other.ValueSize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkUint32("max entries", abi.MaxEntries, other.MaxEntries); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if abi.InnerMap == nil {
|
||||||
|
if abi.Type == ArrayOfMaps || abi.Type == HashOfMaps {
|
||||||
|
return errors.New("missing inner map ABI")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.InnerMap == nil {
|
||||||
|
return errors.New("missing inner map")
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Wrap(abi.InnerMap.check(other.InnerMap), "inner map")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProgramABI describes a Program.
|
||||||
|
//
|
||||||
|
// Use it to assert that a Program matches what your code expects.
|
||||||
type ProgramABI struct {
|
type ProgramABI struct {
|
||||||
Type ProgramType
|
Type ProgramType
|
||||||
}
|
}
|
||||||
@ -95,110 +148,36 @@ func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProgramABIFromFd(fd *internal.FD) (string, *ProgramABI, error) {
|
func newProgramABIFromFd(fd *bpfFD) (*ProgramABI, error) {
|
||||||
info, err := bpfGetProgInfoByFD(fd)
|
info, err := bpfGetProgInfoByFD(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) == syscall.EINVAL {
|
return nil, err
|
||||||
return newProgramABIFromProc(fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var name string
|
return newProgramABIFromInfo(info), nil
|
||||||
if bpfName := internal.CString(info.name[:]); bpfName != "" {
|
}
|
||||||
name = bpfName
|
|
||||||
} else {
|
|
||||||
name = internal.CString(info.tag[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
return name, &ProgramABI{
|
func newProgramABIFromInfo(info *bpfProgInfo) *ProgramABI {
|
||||||
|
return &ProgramABI{
|
||||||
Type: ProgramType(info.progType),
|
Type: ProgramType(info.progType),
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProgramABIFromProc(fd *internal.FD) (string, *ProgramABI, error) {
|
// Check verifies that a Program conforms to the ABI.
|
||||||
var (
|
//
|
||||||
abi ProgramABI
|
// Members which have the zero value of their type
|
||||||
name string
|
// are not checked.
|
||||||
)
|
func (abi *ProgramABI) Check(prog *Program) error {
|
||||||
|
if abi.Type != UnspecifiedProgram && prog.abi.Type != abi.Type {
|
||||||
err := scanFdInfo(fd, map[string]interface{}{
|
return errors.Errorf("expected program type %s, have %s", abi.Type, prog.abi.Type)
|
||||||
"prog_type": &abi.Type,
|
|
||||||
"prog_tag": &name,
|
|
||||||
})
|
|
||||||
if errors.Cause(err) == errMissingFields {
|
|
||||||
return "", nil, &internal.UnsupportedFeatureError{
|
|
||||||
Name: "reading ABI from /proc/self/fdinfo",
|
|
||||||
MinimumVersion: internal.Version{4, 11, 0},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return name, &abi, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
|
|
||||||
raw, err := fd.Value()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", raw))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer fh.Close()
|
|
||||||
|
|
||||||
return errors.Wrap(scanFdInfoReader(fh, fields), fh.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
var errMissingFields = errors.New("missing fields")
|
|
||||||
|
|
||||||
func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
|
|
||||||
var (
|
|
||||||
scanner = bufio.NewScanner(r)
|
|
||||||
scanned int
|
|
||||||
)
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
|
||||||
parts := bytes.SplitN(scanner.Bytes(), []byte("\t"), 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
name := bytes.TrimSuffix(parts[0], []byte(":"))
|
|
||||||
field, ok := fields[string(name)]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := fmt.Fscanln(bytes.NewReader(parts[1]), field); err != nil || n != 1 {
|
|
||||||
return errors.Wrapf(err, "can't parse field %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
scanned++
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if scanned != len(fields) {
|
|
||||||
return errMissingFields
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal returns true if two ABIs have the same values.
|
func checkUint32(name string, want, have uint32) error {
|
||||||
func (abi *ProgramABI) Equal(other *ProgramABI) bool {
|
if want != 0 && have != want {
|
||||||
switch {
|
return errors.Errorf("expected %s to be %d, have %d", name, want, have)
|
||||||
case abi.Type != other.Type:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
63
vendor/github.com/cilium/ebpf/collection.go
generated
vendored
63
vendor/github.com/cilium/ebpf/collection.go
generated
vendored
@ -2,7 +2,6 @@ package ebpf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/internal/btf"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,61 +55,17 @@ func NewCollection(spec *CollectionSpec) (*Collection, error) {
|
|||||||
// NewCollectionWithOptions creates a Collection from a specification.
|
// NewCollectionWithOptions creates a Collection from a specification.
|
||||||
//
|
//
|
||||||
// Only maps referenced by at least one of the programs are initialized.
|
// Only maps referenced by at least one of the programs are initialized.
|
||||||
func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (coll *Collection, err error) {
|
func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) {
|
||||||
var (
|
maps := make(map[string]*Map)
|
||||||
maps = make(map[string]*Map)
|
|
||||||
progs = make(map[string]*Program)
|
|
||||||
btfs = make(map[*btf.Spec]*btf.Handle)
|
|
||||||
)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
for _, btf := range btfs {
|
|
||||||
btf.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range maps {
|
|
||||||
m.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range progs {
|
|
||||||
p.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
loadBTF := func(spec *btf.Spec) (*btf.Handle, error) {
|
|
||||||
if btfs[spec] != nil {
|
|
||||||
return btfs[spec], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
handle, err := btf.NewHandle(spec)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
btfs[spec] = handle
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for mapName, mapSpec := range spec.Maps {
|
for mapName, mapSpec := range spec.Maps {
|
||||||
var handle *btf.Handle
|
m, err := NewMap(mapSpec)
|
||||||
if mapSpec.BTF != nil {
|
|
||||||
handle, err = loadBTF(btf.MapSpec(mapSpec.BTF))
|
|
||||||
if err != nil && !btf.IsNotSupported(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m, err := newMapWithBTF(mapSpec, handle)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "map %s", mapName)
|
return nil, errors.Wrapf(err, "map %s", mapName)
|
||||||
}
|
}
|
||||||
maps[mapName] = m
|
maps[mapName] = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progs := make(map[string]*Program)
|
||||||
for progName, origProgSpec := range spec.Programs {
|
for progName, origProgSpec := range spec.Programs {
|
||||||
progSpec := origProgSpec.Copy()
|
progSpec := origProgSpec.Copy()
|
||||||
|
|
||||||
@ -136,15 +91,7 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var handle *btf.Handle
|
prog, err := NewProgramWithOptions(progSpec, opts.Programs)
|
||||||
if progSpec.BTF != nil {
|
|
||||||
handle, err = loadBTF(btf.ProgramSpec(progSpec.BTF))
|
|
||||||
if err != nil && !btf.IsNotSupported(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prog, err := newProgramWithBTF(progSpec, handle, opts.Programs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "program %s", progName)
|
return nil, errors.Wrapf(err, "program %s", progName)
|
||||||
}
|
}
|
||||||
|
297
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
297
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
@ -4,13 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/internal"
|
|
||||||
"github.com/cilium/ebpf/internal/btf"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -19,8 +18,6 @@ type elfCode struct {
|
|||||||
*elf.File
|
*elf.File
|
||||||
symbols []elf.Symbol
|
symbols []elf.Symbol
|
||||||
symbolsPerSection map[elf.SectionIndex]map[uint64]string
|
symbolsPerSection map[elf.SectionIndex]map[uint64]string
|
||||||
license string
|
|
||||||
version uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadCollectionSpec parses an ELF file into a CollectionSpec.
|
// LoadCollectionSpec parses an ELF file into a CollectionSpec.
|
||||||
@ -36,8 +33,8 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec.
|
// LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec.
|
||||||
func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
|
||||||
f, err := elf.NewFile(rd)
|
f, err := elf.NewFile(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -48,17 +45,12 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
return nil, errors.Wrap(err, "load symbols")
|
return nil, errors.Wrap(err, "load symbols")
|
||||||
}
|
}
|
||||||
|
|
||||||
ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0}
|
ec := &elfCode{f, symbols, symbolsPerSection(symbols)}
|
||||||
|
|
||||||
var (
|
|
||||||
licenseSection *elf.Section
|
|
||||||
versionSection *elf.Section
|
|
||||||
btfMaps = make(map[elf.SectionIndex]*elf.Section)
|
|
||||||
progSections = make(map[elf.SectionIndex]*elf.Section)
|
|
||||||
relSections = make(map[elf.SectionIndex]*elf.Section)
|
|
||||||
mapSections = make(map[elf.SectionIndex]*elf.Section)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
var licenseSection, versionSection *elf.Section
|
||||||
|
progSections := make(map[elf.SectionIndex]*elf.Section)
|
||||||
|
relSections := make(map[elf.SectionIndex]*elf.Section)
|
||||||
|
mapSections := make(map[elf.SectionIndex]*elf.Section)
|
||||||
for i, sec := range ec.Sections {
|
for i, sec := range ec.Sections {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(sec.Name, "license"):
|
case strings.HasPrefix(sec.Name, "license"):
|
||||||
@ -67,8 +59,6 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
versionSection = sec
|
versionSection = sec
|
||||||
case strings.HasPrefix(sec.Name, "maps"):
|
case strings.HasPrefix(sec.Name, "maps"):
|
||||||
mapSections[elf.SectionIndex(i)] = sec
|
mapSections[elf.SectionIndex(i)] = sec
|
||||||
case sec.Name == ".maps":
|
|
||||||
btfMaps[elf.SectionIndex(i)] = sec
|
|
||||||
case sec.Type == elf.SHT_REL:
|
case sec.Type == elf.SHT_REL:
|
||||||
if int(sec.Info) >= len(ec.Sections) {
|
if int(sec.Info) >= len(ec.Sections) {
|
||||||
return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
|
return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
|
||||||
@ -77,7 +67,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
// Store relocations under the section index of the target
|
// Store relocations under the section index of the target
|
||||||
idx := elf.SectionIndex(sec.Info)
|
idx := elf.SectionIndex(sec.Info)
|
||||||
if relSections[idx] != nil {
|
if relSections[idx] != nil {
|
||||||
return nil, errors.Errorf("section %d has multiple relocation sections", sec.Info)
|
return nil, errors.Errorf("section %d has multiple relocation sections", idx)
|
||||||
}
|
}
|
||||||
relSections[idx] = sec
|
relSections[idx] = sec
|
||||||
case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
|
case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
|
||||||
@ -85,38 +75,35 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ec.license, err = loadLicense(licenseSection)
|
license, err := loadLicense(licenseSection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "load license")
|
return nil, errors.Wrap(err, "load license")
|
||||||
}
|
}
|
||||||
|
|
||||||
ec.version, err = loadVersion(versionSection, ec.ByteOrder)
|
version, err := loadVersion(versionSection, ec.ByteOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "load version")
|
return nil, errors.Wrap(err, "load version")
|
||||||
}
|
}
|
||||||
|
|
||||||
btf, err := btf.LoadSpecFromReader(rd)
|
maps, err := ec.loadMaps(mapSections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "load BTF")
|
|
||||||
}
|
|
||||||
|
|
||||||
maps := make(map[string]*MapSpec)
|
|
||||||
|
|
||||||
if err := ec.loadMaps(maps, mapSections); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "load maps")
|
return nil, errors.Wrap(err, "load maps")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(btfMaps) > 0 {
|
progs, libs, err := ec.loadPrograms(progSections, relSections, license, version)
|
||||||
if err := ec.loadBTFMaps(maps, btfMaps, btf); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "load BTF maps")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
progs, err := ec.loadPrograms(progSections, relSections, btf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "load programs")
|
return nil, errors.Wrap(err, "load programs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(libs) > 0 {
|
||||||
|
for name, prog := range progs {
|
||||||
|
prog.Instructions, err = link(prog.Instructions, libs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "program %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &CollectionSpec{maps, progs}, nil
|
return &CollectionSpec{maps, progs}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,74 +128,52 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
|
|||||||
return version, errors.Wrapf(err, "section %s", sec.Name)
|
return version, errors.Wrapf(err, "section %s", sec.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*elf.Section, btf *btf.Spec) (map[string]*ProgramSpec, error) {
|
func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*elf.Section, license string, version uint32) (map[string]*ProgramSpec, []asm.Instructions, error) {
|
||||||
var (
|
var (
|
||||||
progs []*ProgramSpec
|
progs = make(map[string]*ProgramSpec)
|
||||||
libs []*ProgramSpec
|
libs []asm.Instructions
|
||||||
)
|
)
|
||||||
|
|
||||||
for idx, prog := range progSections {
|
for idx, prog := range progSections {
|
||||||
syms := ec.symbolsPerSection[idx]
|
syms := ec.symbolsPerSection[idx]
|
||||||
if len(syms) == 0 {
|
if len(syms) == 0 {
|
||||||
return nil, errors.Errorf("section %v: missing symbols", prog.Name)
|
return nil, nil, errors.Errorf("section %v: missing symbols", prog.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
funcSym := syms[0]
|
funcSym := syms[0]
|
||||||
if funcSym == "" {
|
if funcSym == "" {
|
||||||
return nil, errors.Errorf("section %v: no label at start", prog.Name)
|
return nil, nil, errors.Errorf("section %v: no label at start", prog.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
rels, err := ec.loadRelocations(relSections[idx])
|
rels, err := ec.loadRelocations(relSections[idx])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "program %s: can't load relocations", funcSym)
|
return nil, nil, errors.Wrapf(err, "program %s: can't load relocations", funcSym)
|
||||||
}
|
}
|
||||||
|
|
||||||
insns, length, err := ec.loadInstructions(prog, syms, rels)
|
insns, err := ec.loadInstructions(prog, syms, rels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "program %s: can't unmarshal instructions", funcSym)
|
return nil, nil, errors.Wrapf(err, "program %s: can't unmarshal instructions", funcSym)
|
||||||
}
|
}
|
||||||
|
|
||||||
progType, attachType := getProgType(prog.Name)
|
if progType, attachType := getProgType(prog.Name); progType == UnspecifiedProgram {
|
||||||
|
|
||||||
spec := &ProgramSpec{
|
|
||||||
Name: funcSym,
|
|
||||||
Type: progType,
|
|
||||||
AttachType: attachType,
|
|
||||||
License: ec.license,
|
|
||||||
KernelVersion: ec.version,
|
|
||||||
Instructions: insns,
|
|
||||||
}
|
|
||||||
|
|
||||||
if btf != nil {
|
|
||||||
spec.BTF, err = btf.Program(prog.Name, length)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "BTF for section %s (program %s)", prog.Name, funcSym)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if spec.Type == UnspecifiedProgram {
|
|
||||||
// There is no single name we can use for "library" sections,
|
// There is no single name we can use for "library" sections,
|
||||||
// since they may contain multiple functions. We'll decode the
|
// since they may contain multiple functions. We'll decode the
|
||||||
// labels they contain later on, and then link sections that way.
|
// labels they contain later on, and then link sections that way.
|
||||||
libs = append(libs, spec)
|
libs = append(libs, insns)
|
||||||
} else {
|
} else {
|
||||||
progs = append(progs, spec)
|
progs[funcSym] = &ProgramSpec{
|
||||||
|
Name: funcSym,
|
||||||
|
Type: progType,
|
||||||
|
AttachType: attachType,
|
||||||
|
License: license,
|
||||||
|
KernelVersion: version,
|
||||||
|
Instructions: insns,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return progs, libs, nil
|
||||||
res := make(map[string]*ProgramSpec, len(progs))
|
|
||||||
for _, prog := range progs {
|
|
||||||
err := link(prog, libs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "program %s", prog.Name)
|
|
||||||
}
|
|
||||||
res[prog.Name] = prog
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]string) (asm.Instructions, uint64, error) {
|
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]string) (asm.Instructions, error) {
|
||||||
var (
|
var (
|
||||||
r = section.Open()
|
r = section.Open()
|
||||||
insns asm.Instructions
|
insns asm.Instructions
|
||||||
@ -218,10 +183,10 @@ func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations m
|
|||||||
for {
|
for {
|
||||||
n, err := ins.Unmarshal(r, ec.ByteOrder)
|
n, err := ins.Unmarshal(r, ec.ByteOrder)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return insns, offset, nil
|
return insns, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, errors.Wrapf(err, "offset %d", offset)
|
return nil, errors.Wrapf(err, "offset %d", offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
ins.Symbol = symbols[offset]
|
ins.Symbol = symbols[offset]
|
||||||
@ -232,15 +197,19 @@ func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section) error {
|
func (ec *elfCode) loadMaps(mapSections map[elf.SectionIndex]*elf.Section) (map[string]*MapSpec, error) {
|
||||||
|
var (
|
||||||
|
maps = make(map[string]*MapSpec)
|
||||||
|
b = make([]byte, 1)
|
||||||
|
)
|
||||||
for idx, sec := range mapSections {
|
for idx, sec := range mapSections {
|
||||||
syms := ec.symbolsPerSection[idx]
|
syms := ec.symbolsPerSection[idx]
|
||||||
if len(syms) == 0 {
|
if len(syms) == 0 {
|
||||||
return errors.Errorf("section %v: no symbols", sec.Name)
|
return nil, errors.Errorf("section %v: no symbols", sec.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sec.Size%uint64(len(syms)) != 0 {
|
if sec.Size%uint64(len(syms)) != 0 {
|
||||||
return errors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
|
return nil, errors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -250,11 +219,12 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
|
|||||||
for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
|
for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
|
||||||
mapSym := syms[offset]
|
mapSym := syms[offset]
|
||||||
if mapSym == "" {
|
if mapSym == "" {
|
||||||
return errors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
|
fmt.Println(syms)
|
||||||
|
return nil, errors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if maps[mapSym] != nil {
|
if maps[mapSym] != nil {
|
||||||
return errors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
|
return nil, errors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
|
||||||
}
|
}
|
||||||
|
|
||||||
lr := io.LimitReader(r, int64(size))
|
lr := io.LimitReader(r, int64(size))
|
||||||
@ -262,152 +232,51 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
|
|||||||
var spec MapSpec
|
var spec MapSpec
|
||||||
switch {
|
switch {
|
||||||
case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
|
case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
|
||||||
return errors.Errorf("map %v: missing type", mapSym)
|
return nil, errors.Errorf("map %v: missing type", mapSym)
|
||||||
case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
|
case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
|
||||||
return errors.Errorf("map %v: missing key size", mapSym)
|
return nil, errors.Errorf("map %v: missing key size", mapSym)
|
||||||
case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
|
case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
|
||||||
return errors.Errorf("map %v: missing value size", mapSym)
|
return nil, errors.Errorf("map %v: missing value size", mapSym)
|
||||||
case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
|
case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
|
||||||
return errors.Errorf("map %v: missing max entries", mapSym)
|
return nil, errors.Errorf("map %v: missing max entries", mapSym)
|
||||||
case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
|
case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
|
||||||
return errors.Errorf("map %v: missing flags", mapSym)
|
return nil, errors.Errorf("map %v: missing flags", mapSym)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
|
for {
|
||||||
return errors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
|
_, err := lr.Read(b)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if b[0] != 0 {
|
||||||
|
return nil, errors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maps[mapSym] = &spec
|
maps[mapSym] = &spec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return maps, nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
|
|
||||||
|
|
||||||
if spec == nil {
|
|
||||||
return errors.Errorf("missing BTF")
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx, sec := range mapSections {
|
|
||||||
syms := ec.symbolsPerSection[idx]
|
|
||||||
if len(syms) == 0 {
|
|
||||||
return errors.Errorf("section %v: no symbols", sec.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sym := range syms {
|
|
||||||
if maps[sym] != nil {
|
|
||||||
return errors.Errorf("section %v: map %v already exists", sec.Name, sym)
|
|
||||||
}
|
|
||||||
|
|
||||||
btfMap, err := spec.Map(sym)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "map %v: can't get BTF", sym)
|
|
||||||
}
|
|
||||||
|
|
||||||
spec, err := mapSpecFromBTF(btfMap)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "map %v", sym)
|
|
||||||
}
|
|
||||||
|
|
||||||
maps[sym] = spec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapSpecFromBTF(btfMap *btf.Map) (*MapSpec, error) {
|
|
||||||
var (
|
|
||||||
mapType, flags, maxEntries uint32
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
for _, member := range btf.MapType(btfMap).Members {
|
|
||||||
switch member.Name {
|
|
||||||
case "type":
|
|
||||||
mapType, err = uintFromBTF(member.Type)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get type")
|
|
||||||
}
|
|
||||||
|
|
||||||
case "map_flags":
|
|
||||||
flags, err = uintFromBTF(member.Type)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get BTF map flags")
|
|
||||||
}
|
|
||||||
|
|
||||||
case "max_entries":
|
|
||||||
maxEntries, err = uintFromBTF(member.Type)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get BTF map max entries")
|
|
||||||
}
|
|
||||||
|
|
||||||
case "key":
|
|
||||||
case "value":
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("unrecognized field %s in BTF map definition", member.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
keySize, err := btf.Sizeof(btf.MapKey(btfMap))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get size of BTF key")
|
|
||||||
}
|
|
||||||
|
|
||||||
valueSize, err := btf.Sizeof(btf.MapValue(btfMap))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get size of BTF value")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MapSpec{
|
|
||||||
Type: MapType(mapType),
|
|
||||||
KeySize: uint32(keySize),
|
|
||||||
ValueSize: uint32(valueSize),
|
|
||||||
MaxEntries: maxEntries,
|
|
||||||
Flags: flags,
|
|
||||||
BTF: btfMap,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// uintFromBTF resolves the __uint macro, which is a pointer to a sized
|
|
||||||
// array, e.g. for int (*foo)[10], this function will return 10.
|
|
||||||
func uintFromBTF(typ btf.Type) (uint32, error) {
|
|
||||||
ptr, ok := typ.(*btf.Pointer)
|
|
||||||
if !ok {
|
|
||||||
return 0, errors.Errorf("not a pointer: %v", typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
arr, ok := ptr.Target.(*btf.Array)
|
|
||||||
if !ok {
|
|
||||||
return 0, errors.Errorf("not a pointer to array: %v", typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr.Nelems, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProgType(v string) (ProgramType, AttachType) {
|
func getProgType(v string) (ProgramType, AttachType) {
|
||||||
types := map[string]ProgramType{
|
types := map[string]ProgramType{
|
||||||
// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c#n3568
|
// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c#n3568
|
||||||
"socket": SocketFilter,
|
"socket": SocketFilter,
|
||||||
"seccomp": SocketFilter,
|
"seccomp": SocketFilter,
|
||||||
"kprobe/": Kprobe,
|
"kprobe/": Kprobe,
|
||||||
"uprobe/": Kprobe,
|
"kretprobe/": Kprobe,
|
||||||
"kretprobe/": Kprobe,
|
"tracepoint/": TracePoint,
|
||||||
"uretprobe/": Kprobe,
|
"xdp": XDP,
|
||||||
"tracepoint/": TracePoint,
|
"perf_event": PerfEvent,
|
||||||
"raw_tracepoint/": RawTracepoint,
|
"sockops": SockOps,
|
||||||
"xdp": XDP,
|
"sk_skb": SkSKB,
|
||||||
"perf_event": PerfEvent,
|
"sk_msg": SkMsg,
|
||||||
"lwt_in": LWTIn,
|
"lirc_mode2": LircMode2,
|
||||||
"lwt_out": LWTOut,
|
"flow_dissector": FlowDissector,
|
||||||
"lwt_xmit": LWTXmit,
|
|
||||||
"lwt_seg6local": LWTSeg6Local,
|
|
||||||
"sockops": SockOps,
|
|
||||||
"sk_skb": SkSKB,
|
|
||||||
"sk_msg": SkMsg,
|
|
||||||
"lirc_mode2": LircMode2,
|
|
||||||
"flow_dissector": FlowDissector,
|
|
||||||
|
|
||||||
"cgroup_skb/": CGroupSKB,
|
"cgroup_skb/": CGroupSKB,
|
||||||
"cgroup/dev": CGroupDevice,
|
"cgroup/dev": CGroupDevice,
|
||||||
|
19
vendor/github.com/cilium/ebpf/feature.go
generated
vendored
Normal file
19
vendor/github.com/cilium/ebpf/feature.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package ebpf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type featureTest struct {
|
||||||
|
Fn func() bool
|
||||||
|
|
||||||
|
once sync.Once
|
||||||
|
result bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ft *featureTest) Result() bool {
|
||||||
|
ft.once.Do(func() {
|
||||||
|
ft.result = ft.Fn()
|
||||||
|
})
|
||||||
|
return ft.result
|
||||||
|
}
|
15
vendor/github.com/cilium/ebpf/internal/BUILD
generated
vendored
15
vendor/github.com/cilium/ebpf/internal/BUILD
generated
vendored
@ -5,23 +5,11 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"cpu.go",
|
"cpu.go",
|
||||||
"endian.go",
|
"endian.go",
|
||||||
"errors.go",
|
|
||||||
"fd.go",
|
|
||||||
"feature.go",
|
|
||||||
"io.go",
|
|
||||||
"ptr.go",
|
|
||||||
"ptr_32_be.go",
|
|
||||||
"ptr_32_le.go",
|
|
||||||
"ptr_64.go",
|
|
||||||
"syscall.go",
|
|
||||||
],
|
],
|
||||||
importmap = "k8s.io/kubernetes/vendor/github.com/cilium/ebpf/internal",
|
importmap = "k8s.io/kubernetes/vendor/github.com/cilium/ebpf/internal",
|
||||||
importpath = "github.com/cilium/ebpf/internal",
|
importpath = "github.com/cilium/ebpf/internal",
|
||||||
visibility = ["//vendor/github.com/cilium/ebpf:__subpackages__"],
|
visibility = ["//vendor/github.com/cilium/ebpf:__subpackages__"],
|
||||||
deps = [
|
deps = ["//vendor/github.com/pkg/errors:go_default_library"],
|
||||||
"//vendor/github.com/cilium/ebpf/internal/unix:go_default_library",
|
|
||||||
"//vendor/github.com/pkg/errors:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
@ -35,7 +23,6 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//vendor/github.com/cilium/ebpf/internal/btf:all-srcs",
|
|
||||||
"//vendor/github.com/cilium/ebpf/internal/unix:all-srcs",
|
"//vendor/github.com/cilium/ebpf/internal/unix:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
36
vendor/github.com/cilium/ebpf/internal/btf/BUILD
generated
vendored
36
vendor/github.com/cilium/ebpf/internal/btf/BUILD
generated
vendored
@ -1,36 +0,0 @@
|
|||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"btf.go",
|
|
||||||
"btf_types.go",
|
|
||||||
"doc.go",
|
|
||||||
"ext_info.go",
|
|
||||||
"strings.go",
|
|
||||||
"types.go",
|
|
||||||
],
|
|
||||||
importmap = "k8s.io/kubernetes/vendor/github.com/cilium/ebpf/internal/btf",
|
|
||||||
importpath = "github.com/cilium/ebpf/internal/btf",
|
|
||||||
visibility = ["//vendor/github.com/cilium/ebpf:__subpackages__"],
|
|
||||||
deps = [
|
|
||||||
"//vendor/github.com/cilium/ebpf/asm:go_default_library",
|
|
||||||
"//vendor/github.com/cilium/ebpf/internal:go_default_library",
|
|
||||||
"//vendor/github.com/cilium/ebpf/internal/unix:go_default_library",
|
|
||||||
"//vendor/github.com/pkg/errors:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
530
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
530
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
@ -1,530 +0,0 @@
|
|||||||
package btf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"debug/elf"
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal"
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const btfMagic = 0xeB9F
|
|
||||||
|
|
||||||
// Spec represents decoded BTF.
|
|
||||||
type Spec struct {
|
|
||||||
rawTypes []rawType
|
|
||||||
strings stringTable
|
|
||||||
types map[string][]Type
|
|
||||||
funcInfos map[string]extInfo
|
|
||||||
lineInfos map[string]extInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type btfHeader struct {
|
|
||||||
Magic uint16
|
|
||||||
Version uint8
|
|
||||||
Flags uint8
|
|
||||||
HdrLen uint32
|
|
||||||
|
|
||||||
TypeOff uint32
|
|
||||||
TypeLen uint32
|
|
||||||
StringOff uint32
|
|
||||||
StringLen uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadSpecFromReader reads BTF sections from an ELF.
|
|
||||||
//
|
|
||||||
// Returns a nil Spec and no error if no BTF was present.
|
|
||||||
func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
|
||||||
file, err := elf.NewFile(rd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
var (
|
|
||||||
btfSection *elf.Section
|
|
||||||
btfExtSection *elf.Section
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, sec := range file.Sections {
|
|
||||||
switch sec.Name {
|
|
||||||
case ".BTF":
|
|
||||||
btfSection = sec
|
|
||||||
case ".BTF.ext":
|
|
||||||
btfExtSection = sec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if btfSection == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
spec, err := parseBTF(btfSection.Open(), file.ByteOrder)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if btfExtSection != nil {
|
|
||||||
spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read ext info")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return spec, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) (*Spec, error) {
|
|
||||||
rawBTF, err := ioutil.ReadAll(btf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read BTF")
|
|
||||||
}
|
|
||||||
|
|
||||||
rd := bytes.NewReader(rawBTF)
|
|
||||||
|
|
||||||
var header btfHeader
|
|
||||||
if err := binary.Read(rd, bo, &header); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read header")
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Magic != btfMagic {
|
|
||||||
return nil, errors.Errorf("incorrect magic value %v", header.Magic)
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Version != 1 {
|
|
||||||
return nil, errors.Errorf("unexpected version %v", header.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Flags != 0 {
|
|
||||||
return nil, errors.Errorf("unsupported flags %v", header.Flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
remainder := int64(header.HdrLen) - int64(binary.Size(&header))
|
|
||||||
if remainder < 0 {
|
|
||||||
return nil, errors.New("header is too short")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "header padding")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't seek to start of string section")
|
|
||||||
}
|
|
||||||
|
|
||||||
strings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen)))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read type names")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't seek to start of type section")
|
|
||||||
}
|
|
||||||
|
|
||||||
rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read types")
|
|
||||||
}
|
|
||||||
|
|
||||||
types, err := inflateRawTypes(rawTypes, strings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Spec{
|
|
||||||
rawTypes: rawTypes,
|
|
||||||
types: types,
|
|
||||||
strings: strings,
|
|
||||||
funcInfos: make(map[string]extInfo),
|
|
||||||
lineInfos: make(map[string]extInfo),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
|
|
||||||
var (
|
|
||||||
buf bytes.Buffer
|
|
||||||
header = new(btfHeader)
|
|
||||||
headerLen = binary.Size(header)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reserve space for the header. We have to write it last since
|
|
||||||
// we don't know the size of the type section yet.
|
|
||||||
_, _ = buf.Write(make([]byte, headerLen))
|
|
||||||
|
|
||||||
// Write type section, just after the header.
|
|
||||||
for _, typ := range s.rawTypes {
|
|
||||||
if typ.Kind() == kindDatasec {
|
|
||||||
// Datasec requires patching with information from the ELF
|
|
||||||
// file. We don't support this at the moment, so patch
|
|
||||||
// out any Datasec by turning it into a void*.
|
|
||||||
typ = rawType{}
|
|
||||||
typ.SetKind(kindPointer)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := typ.Marshal(&buf, bo); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't marshal BTF")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typeLen := uint32(buf.Len() - headerLen)
|
|
||||||
|
|
||||||
// Write string section after type section.
|
|
||||||
_, _ = buf.Write(s.strings)
|
|
||||||
|
|
||||||
// Fill out the header, and write it out.
|
|
||||||
header = &btfHeader{
|
|
||||||
Magic: btfMagic,
|
|
||||||
Version: 1,
|
|
||||||
Flags: 0,
|
|
||||||
HdrLen: uint32(headerLen),
|
|
||||||
TypeOff: 0,
|
|
||||||
TypeLen: typeLen,
|
|
||||||
StringOff: typeLen,
|
|
||||||
StringLen: uint32(len(s.strings)),
|
|
||||||
}
|
|
||||||
|
|
||||||
raw := buf.Bytes()
|
|
||||||
err := binary.Write(sliceWriter(raw[:headerLen]), bo, header)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't write header")
|
|
||||||
}
|
|
||||||
|
|
||||||
return raw, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type sliceWriter []byte
|
|
||||||
|
|
||||||
func (sw sliceWriter) Write(p []byte) (int, error) {
|
|
||||||
if len(p) != len(sw) {
|
|
||||||
return 0, errors.New("size doesn't match")
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy(sw, p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Program finds the BTF for a specific section.
|
|
||||||
//
|
|
||||||
// Length is the number of bytes in the raw BPF instruction stream.
|
|
||||||
//
|
|
||||||
// Returns an error if there is no BTF.
|
|
||||||
func (s *Spec) Program(name string, length uint64) (*Program, error) {
|
|
||||||
if length == 0 {
|
|
||||||
return nil, errors.New("length musn't be zero")
|
|
||||||
}
|
|
||||||
|
|
||||||
funcInfos, funcOK := s.funcInfos[name]
|
|
||||||
lineInfos, lineOK := s.lineInfos[name]
|
|
||||||
|
|
||||||
if !funcOK && !lineOK {
|
|
||||||
return nil, errors.Errorf("no BTF for program %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Program{s, length, funcInfos, lineInfos}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map finds the BTF for a map.
|
|
||||||
//
|
|
||||||
// Returns an error if there is no BTF for the given name.
|
|
||||||
func (s *Spec) Map(name string) (*Map, error) {
|
|
||||||
var mapVar Var
|
|
||||||
if err := s.FindType(name, &mapVar); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mapStruct, ok := mapVar.Type.(*Struct)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.Errorf("expected struct, have %s", mapVar.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
var key, value Type
|
|
||||||
for _, member := range mapStruct.Members {
|
|
||||||
switch member.Name {
|
|
||||||
case "key":
|
|
||||||
key = member.Type
|
|
||||||
|
|
||||||
case "value":
|
|
||||||
value = member.Type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if key == nil {
|
|
||||||
return nil, errors.Errorf("map %s: missing 'key' in type", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if value == nil {
|
|
||||||
return nil, errors.Errorf("map %s: missing 'value' in type", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Map{mapStruct, s, key, value}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errNotFound = errors.New("not found")
|
|
||||||
|
|
||||||
// FindType searches for a type with a specific name.
|
|
||||||
//
|
|
||||||
// hint determines the type of the returned Type.
|
|
||||||
//
|
|
||||||
// Returns an error if there is no or multiple matches.
|
|
||||||
func (s *Spec) FindType(name string, typ Type) error {
|
|
||||||
var (
|
|
||||||
wanted = reflect.TypeOf(typ)
|
|
||||||
candidate Type
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, typ := range s.types[name] {
|
|
||||||
if reflect.TypeOf(typ) != wanted {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidate != nil {
|
|
||||||
return errors.Errorf("type %s: multiple candidates for %T", name, typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
candidate = typ
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidate == nil {
|
|
||||||
return errors.WithMessagef(errNotFound, "type %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
value := reflect.Indirect(reflect.ValueOf(copyType(candidate)))
|
|
||||||
reflect.Indirect(reflect.ValueOf(typ)).Set(value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle is a reference to BTF loaded into the kernel.
|
|
||||||
type Handle struct {
|
|
||||||
fd *internal.FD
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHandle loads BTF into the kernel.
|
|
||||||
//
|
|
||||||
// Returns an error if BTF is not supported, which can
|
|
||||||
// be checked by IsNotSupported.
|
|
||||||
func NewHandle(spec *Spec) (*Handle, error) {
|
|
||||||
if err := haveBTF(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
btf, err := spec.marshal(internal.NativeEndian)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't marshal BTF")
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(len(btf)) > math.MaxUint32 {
|
|
||||||
return nil, errors.New("BTF exceeds the maximum size")
|
|
||||||
}
|
|
||||||
|
|
||||||
attr := &bpfLoadBTFAttr{
|
|
||||||
btf: internal.NewSlicePointer(btf),
|
|
||||||
btfSize: uint32(len(btf)),
|
|
||||||
}
|
|
||||||
|
|
||||||
fd, err := bpfLoadBTF(attr)
|
|
||||||
if err != nil {
|
|
||||||
logBuf := make([]byte, 64*1024)
|
|
||||||
attr.logBuf = internal.NewSlicePointer(logBuf)
|
|
||||||
attr.btfLogSize = uint32(len(logBuf))
|
|
||||||
attr.btfLogLevel = 1
|
|
||||||
_, logErr := bpfLoadBTF(attr)
|
|
||||||
return nil, internal.ErrorWithLog(err, logBuf, logErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Handle{fd}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close destroys the handle.
|
|
||||||
//
|
|
||||||
// Subsequent calls to FD will return an invalid value.
|
|
||||||
func (h *Handle) Close() error {
|
|
||||||
return h.fd.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FD returns the file descriptor for the handle.
|
|
||||||
func (h *Handle) FD() int {
|
|
||||||
value, err := h.fd.Value()
|
|
||||||
if err != nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map is the BTF for a map.
|
|
||||||
type Map struct {
|
|
||||||
definition *Struct
|
|
||||||
spec *Spec
|
|
||||||
key, value Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapSpec should be a method on Map, but is a free function
|
|
||||||
// to hide it from users of the ebpf package.
|
|
||||||
func MapSpec(m *Map) *Spec {
|
|
||||||
return m.spec
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapType should be a method on Map, but is a free function
|
|
||||||
// to hide it from users of the ebpf package.
|
|
||||||
func MapType(m *Map) *Struct {
|
|
||||||
return m.definition
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapKey should be a method on Map, but is a free function
|
|
||||||
// to hide it from users of the ebpf package.
|
|
||||||
func MapKey(m *Map) Type {
|
|
||||||
return m.key
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapValue should be a method on Map, but is a free function
|
|
||||||
// to hide it from users of the ebpf package.
|
|
||||||
func MapValue(m *Map) Type {
|
|
||||||
return m.value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Program is the BTF information for a stream of instructions.
|
|
||||||
type Program struct {
|
|
||||||
spec *Spec
|
|
||||||
length uint64
|
|
||||||
funcInfos, lineInfos extInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProgramSpec returns the Spec needed for loading function and line infos into the kernel.
|
|
||||||
//
|
|
||||||
// This is a free function instead of a method to hide it from users
|
|
||||||
// of package ebpf.
|
|
||||||
func ProgramSpec(s *Program) *Spec {
|
|
||||||
return s.spec
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProgramAppend the information from other to the Program.
|
|
||||||
//
|
|
||||||
// This is a free function instead of a method to hide it from users
|
|
||||||
// of package ebpf.
|
|
||||||
func ProgramAppend(s, other *Program) error {
|
|
||||||
funcInfos, err := s.funcInfos.append(other.funcInfos, s.length)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "func infos")
|
|
||||||
}
|
|
||||||
|
|
||||||
lineInfos, err := s.lineInfos.append(other.lineInfos, s.length)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "line infos")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.length += other.length
|
|
||||||
s.funcInfos = funcInfos
|
|
||||||
s.lineInfos = lineInfos
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProgramFuncInfos returns the binary form of BTF function infos.
|
|
||||||
//
|
|
||||||
// This is a free function instead of a method to hide it from users
|
|
||||||
// of package ebpf.
|
|
||||||
func ProgramFuncInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
|
||||||
bytes, err = s.funcInfos.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.funcInfos.recordSize, bytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProgramLineInfos returns the binary form of BTF line infos.
|
|
||||||
//
|
|
||||||
// This is a free function instead of a method to hide it from users
|
|
||||||
// of package ebpf.
|
|
||||||
func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
|
||||||
bytes, err = s.lineInfos.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.lineInfos.recordSize, bytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotSupported returns true if the error indicates that the kernel
|
|
||||||
// doesn't support BTF.
|
|
||||||
func IsNotSupported(err error) bool {
|
|
||||||
ufe, ok := errors.Cause(err).(*internal.UnsupportedFeatureError)
|
|
||||||
return ok && ufe.Name == "BTF"
|
|
||||||
}
|
|
||||||
|
|
||||||
type bpfLoadBTFAttr struct {
|
|
||||||
btf internal.Pointer
|
|
||||||
logBuf internal.Pointer
|
|
||||||
btfSize uint32
|
|
||||||
btfLogSize uint32
|
|
||||||
btfLogLevel uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) {
|
|
||||||
const _BTFLoad = 18
|
|
||||||
|
|
||||||
fd, err := internal.BPF(_BTFLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return internal.NewFD(uint32(fd)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func minimalBTF(bo binary.ByteOrder) []byte {
|
|
||||||
const minHeaderLength = 24
|
|
||||||
|
|
||||||
var (
|
|
||||||
types struct {
|
|
||||||
Integer btfType
|
|
||||||
Var btfType
|
|
||||||
btfVar struct{ Linkage uint32 }
|
|
||||||
}
|
|
||||||
typLen = uint32(binary.Size(&types))
|
|
||||||
strings = []byte{0, 'a', 0}
|
|
||||||
header = btfHeader{
|
|
||||||
Magic: btfMagic,
|
|
||||||
Version: 1,
|
|
||||||
HdrLen: minHeaderLength,
|
|
||||||
TypeOff: 0,
|
|
||||||
TypeLen: typLen,
|
|
||||||
StringOff: typLen,
|
|
||||||
StringLen: uint32(len(strings)),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// We use a BTF_KIND_VAR here, to make sure that
|
|
||||||
// the kernel understands BTF at least as well as we
|
|
||||||
// do. BTF_KIND_VAR was introduced ~5.1.
|
|
||||||
types.Integer.SetKind(kindPointer)
|
|
||||||
types.Var.NameOff = 1
|
|
||||||
types.Var.SetKind(kindVar)
|
|
||||||
types.Var.SizeType = 1
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
_ = binary.Write(buf, bo, &header)
|
|
||||||
_ = binary.Write(buf, bo, &types)
|
|
||||||
buf.Write(strings)
|
|
||||||
|
|
||||||
return buf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
var haveBTF = internal.FeatureTest("BTF", "5.1", func() bool {
|
|
||||||
btf := minimalBTF(internal.NativeEndian)
|
|
||||||
fd, err := bpfLoadBTF(&bpfLoadBTFAttr{
|
|
||||||
btf: internal.NewSlicePointer(btf),
|
|
||||||
btfSize: uint32(len(btf)),
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
fd.Close()
|
|
||||||
}
|
|
||||||
// Check for EINVAL specifically, rather than err != nil since we
|
|
||||||
// otherwise misdetect due to insufficient permissions.
|
|
||||||
return errors.Cause(err) != unix.EINVAL
|
|
||||||
})
|
|
190
vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
190
vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
@ -1,190 +0,0 @@
|
|||||||
package btf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// btfKind describes a Type.
|
|
||||||
type btfKind uint8
|
|
||||||
|
|
||||||
// Equivalents of the BTF_KIND_* constants.
|
|
||||||
const (
|
|
||||||
kindUnknown btfKind = iota
|
|
||||||
kindInt
|
|
||||||
kindPointer
|
|
||||||
kindArray
|
|
||||||
kindStruct
|
|
||||||
kindUnion
|
|
||||||
kindEnum
|
|
||||||
kindForward
|
|
||||||
kindTypedef
|
|
||||||
kindVolatile
|
|
||||||
kindConst
|
|
||||||
kindRestrict
|
|
||||||
// Added ~4.20
|
|
||||||
kindFunc
|
|
||||||
kindFuncProto
|
|
||||||
// Added ~5.1
|
|
||||||
kindVar
|
|
||||||
kindDatasec
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
btfTypeKindShift = 24
|
|
||||||
btfTypeKindLen = 4
|
|
||||||
btfTypeVlenShift = 0
|
|
||||||
btfTypeVlenMask = 16
|
|
||||||
)
|
|
||||||
|
|
||||||
// btfType is equivalent to struct btf_type in Documentation/bpf/btf.rst.
|
|
||||||
type btfType struct {
|
|
||||||
NameOff uint32
|
|
||||||
/* "info" bits arrangement
|
|
||||||
* bits 0-15: vlen (e.g. # of struct's members)
|
|
||||||
* bits 16-23: unused
|
|
||||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
|
||||||
* bits 28-30: unused
|
|
||||||
* bit 31: kind_flag, currently used by
|
|
||||||
* struct, union and fwd
|
|
||||||
*/
|
|
||||||
Info uint32
|
|
||||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
|
||||||
* "size" tells the size of the type it is describing.
|
|
||||||
*
|
|
||||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
|
||||||
* FUNC and FUNC_PROTO.
|
|
||||||
* "type" is a type_id referring to another type.
|
|
||||||
*/
|
|
||||||
SizeType uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func mask(len uint32) uint32 {
|
|
||||||
return (1 << len) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) info(len, shift uint32) uint32 {
|
|
||||||
return (bt.Info >> shift) & mask(len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) setInfo(value, len, shift uint32) {
|
|
||||||
bt.Info &^= mask(len) << shift
|
|
||||||
bt.Info |= (value & mask(len)) << shift
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) Kind() btfKind {
|
|
||||||
return btfKind(bt.info(btfTypeKindLen, btfTypeKindShift))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) SetKind(kind btfKind) {
|
|
||||||
bt.setInfo(uint32(kind), btfTypeKindLen, btfTypeKindShift)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) Vlen() int {
|
|
||||||
return int(bt.info(btfTypeVlenMask, btfTypeVlenShift))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) SetVlen(vlen int) {
|
|
||||||
bt.setInfo(uint32(vlen), btfTypeVlenMask, btfTypeVlenShift)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) Type() TypeID {
|
|
||||||
// TODO: Panic here if wrong kind?
|
|
||||||
return TypeID(bt.SizeType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *btfType) Size() uint32 {
|
|
||||||
// TODO: Panic here if wrong kind?
|
|
||||||
return bt.SizeType
|
|
||||||
}
|
|
||||||
|
|
||||||
type rawType struct {
|
|
||||||
btfType
|
|
||||||
data interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *rawType) Marshal(w io.Writer, bo binary.ByteOrder) error {
|
|
||||||
if err := binary.Write(w, bo, &rt.btfType); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rt.data == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return binary.Write(w, bo, rt.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
type btfArray struct {
|
|
||||||
Type TypeID
|
|
||||||
IndexType TypeID
|
|
||||||
Nelems uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type btfMember struct {
|
|
||||||
NameOff uint32
|
|
||||||
Type TypeID
|
|
||||||
Offset uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
|
||||||
var (
|
|
||||||
header btfType
|
|
||||||
types []rawType
|
|
||||||
)
|
|
||||||
|
|
||||||
for id := TypeID(1); ; id++ {
|
|
||||||
if err := binary.Read(r, bo, &header); err == io.EOF {
|
|
||||||
return types, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "can't read type info for id %v", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
var data interface{}
|
|
||||||
switch header.Kind() {
|
|
||||||
case kindInt:
|
|
||||||
// sizeof(uint32)
|
|
||||||
data = make([]byte, 4)
|
|
||||||
case kindPointer:
|
|
||||||
case kindArray:
|
|
||||||
data = new(btfArray)
|
|
||||||
case kindStruct:
|
|
||||||
fallthrough
|
|
||||||
case kindUnion:
|
|
||||||
data = make([]btfMember, header.Vlen())
|
|
||||||
case kindEnum:
|
|
||||||
// sizeof(struct btf_enum)
|
|
||||||
data = make([]byte, header.Vlen()*4*2)
|
|
||||||
case kindForward:
|
|
||||||
case kindTypedef:
|
|
||||||
case kindVolatile:
|
|
||||||
case kindConst:
|
|
||||||
case kindRestrict:
|
|
||||||
case kindFunc:
|
|
||||||
case kindFuncProto:
|
|
||||||
// sizeof(struct btf_param)
|
|
||||||
data = make([]byte, header.Vlen()*4*2)
|
|
||||||
case kindVar:
|
|
||||||
// sizeof(struct btf_variable)
|
|
||||||
data = make([]byte, 4)
|
|
||||||
case kindDatasec:
|
|
||||||
// sizeof(struct btf_var_secinfo)
|
|
||||||
data = make([]byte, header.Vlen()*4*3)
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("type id %v: unknown kind: %v", id, header.Kind())
|
|
||||||
}
|
|
||||||
|
|
||||||
if data == nil {
|
|
||||||
types = append(types, rawType{header, nil})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(r, bo, data); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "type id %d: kind %v: can't read %T", id, header.Kind(), data)
|
|
||||||
}
|
|
||||||
|
|
||||||
types = append(types, rawType{header, data})
|
|
||||||
}
|
|
||||||
}
|
|
8
vendor/github.com/cilium/ebpf/internal/btf/doc.go
generated
vendored
8
vendor/github.com/cilium/ebpf/internal/btf/doc.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// Package btf handles data encoded according to the BPF Type Format.
|
|
||||||
//
|
|
||||||
// The canonical documentation lives in the Linux kernel repository and is
|
|
||||||
// available at https://www.kernel.org/doc/html/latest/bpf/btf.html
|
|
||||||
//
|
|
||||||
// The API is very much unstable. You should only use this via the main
|
|
||||||
// ebpf library.
|
|
||||||
package btf
|
|
184
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
184
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
@ -1,184 +0,0 @@
|
|||||||
package btf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
|
||||||
"github.com/cilium/ebpf/internal"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type btfExtHeader struct {
|
|
||||||
Magic uint16
|
|
||||||
Version uint8
|
|
||||||
Flags uint8
|
|
||||||
HdrLen uint32
|
|
||||||
|
|
||||||
FuncInfoOff uint32
|
|
||||||
FuncInfoLen uint32
|
|
||||||
LineInfoOff uint32
|
|
||||||
LineInfoLen uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, err error) {
|
|
||||||
const expectedMagic = 0xeB9F
|
|
||||||
|
|
||||||
var header btfExtHeader
|
|
||||||
if err := binary.Read(r, bo, &header); err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "can't read header")
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Magic != expectedMagic {
|
|
||||||
return nil, nil, errors.Errorf("incorrect magic value %v", header.Magic)
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Version != 1 {
|
|
||||||
return nil, nil, errors.Errorf("unexpected version %v", header.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Flags != 0 {
|
|
||||||
return nil, nil, errors.Errorf("unsupported flags %v", header.Flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
remainder := int64(header.HdrLen) - int64(binary.Size(&header))
|
|
||||||
if remainder < 0 {
|
|
||||||
return nil, nil, errors.New("header is too short")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Of course, the .BTF.ext header has different semantics than the
|
|
||||||
// .BTF ext header. We need to ignore non-null values.
|
|
||||||
_, err = io.CopyN(ioutil.Discard, r, remainder)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "header padding")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "can't seek to function info section")
|
|
||||||
}
|
|
||||||
|
|
||||||
funcInfo, err = parseExtInfo(io.LimitReader(r, int64(header.FuncInfoLen)), bo, strings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "function info")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "can't seek to line info section")
|
|
||||||
}
|
|
||||||
|
|
||||||
lineInfo, err = parseExtInfo(io.LimitReader(r, int64(header.LineInfoLen)), bo, strings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "line info")
|
|
||||||
}
|
|
||||||
|
|
||||||
return funcInfo, lineInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type btfExtInfoSec struct {
|
|
||||||
SecNameOff uint32
|
|
||||||
NumInfo uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type extInfoRecord struct {
|
|
||||||
InsnOff uint64
|
|
||||||
Opaque []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type extInfo struct {
|
|
||||||
recordSize uint32
|
|
||||||
records []extInfoRecord
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) {
|
|
||||||
if other.recordSize != ei.recordSize {
|
|
||||||
return extInfo{}, errors.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
records := make([]extInfoRecord, 0, len(ei.records)+len(other.records))
|
|
||||||
records = append(records, ei.records...)
|
|
||||||
for _, info := range other.records {
|
|
||||||
records = append(records, extInfoRecord{
|
|
||||||
InsnOff: info.InsnOff + offset,
|
|
||||||
Opaque: info.Opaque,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return extInfo{ei.recordSize, records}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ei extInfo) MarshalBinary() ([]byte, error) {
|
|
||||||
if len(ei.records) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, int(ei.recordSize)*len(ei.records)))
|
|
||||||
for _, info := range ei.records {
|
|
||||||
// The kernel expects offsets in number of raw bpf instructions,
|
|
||||||
// while the ELF tracks it in bytes.
|
|
||||||
insnOff := uint32(info.InsnOff / asm.InstructionSize)
|
|
||||||
if err := binary.Write(buf, internal.NativeEndian, insnOff); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't write instruction offset")
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.Write(info.Opaque)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]extInfo, error) {
|
|
||||||
var recordSize uint32
|
|
||||||
if err := binary.Read(r, bo, &recordSize); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read record size")
|
|
||||||
}
|
|
||||||
|
|
||||||
if recordSize < 4 {
|
|
||||||
// Need at least insnOff
|
|
||||||
return nil, errors.New("record size too short")
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make(map[string]extInfo)
|
|
||||||
for {
|
|
||||||
var infoHeader btfExtInfoSec
|
|
||||||
if err := binary.Read(r, bo, &infoHeader); err == io.EOF {
|
|
||||||
return result, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read ext info header")
|
|
||||||
}
|
|
||||||
|
|
||||||
secName, err := strings.Lookup(infoHeader.SecNameOff)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get section name")
|
|
||||||
}
|
|
||||||
|
|
||||||
if infoHeader.NumInfo == 0 {
|
|
||||||
return nil, errors.Errorf("section %s has invalid number of records", secName)
|
|
||||||
}
|
|
||||||
|
|
||||||
var records []extInfoRecord
|
|
||||||
for i := uint32(0); i < infoHeader.NumInfo; i++ {
|
|
||||||
var byteOff uint32
|
|
||||||
if err := binary.Read(r, bo, &byteOff); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "section %v: can't read extended info offset", secName)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, int(recordSize-4))
|
|
||||||
if _, err := io.ReadFull(r, buf); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "section %v: can't read record", secName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if byteOff%asm.InstructionSize != 0 {
|
|
||||||
return nil, errors.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
|
|
||||||
}
|
|
||||||
|
|
||||||
records = append(records, extInfoRecord{uint64(byteOff), buf})
|
|
||||||
}
|
|
||||||
|
|
||||||
result[secName] = extInfo{
|
|
||||||
recordSize,
|
|
||||||
records,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
60
vendor/github.com/cilium/ebpf/internal/btf/strings.go
generated
vendored
60
vendor/github.com/cilium/ebpf/internal/btf/strings.go
generated
vendored
@ -1,60 +0,0 @@
|
|||||||
package btf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type stringTable []byte
|
|
||||||
|
|
||||||
func readStringTable(r io.Reader) (stringTable, error) {
|
|
||||||
contents, err := ioutil.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't read string table")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(contents) < 1 {
|
|
||||||
return nil, errors.New("string table is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
if contents[0] != '\x00' {
|
|
||||||
return nil, errors.New("first item in string table is non-empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
if contents[len(contents)-1] != '\x00' {
|
|
||||||
return nil, errors.New("string table isn't null terminated")
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringTable(contents), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st stringTable) Lookup(offset uint32) (string, error) {
|
|
||||||
if int64(offset) > int64(^uint(0)>>1) {
|
|
||||||
return "", errors.Errorf("offset %d overflows int", offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
pos := int(offset)
|
|
||||||
if pos >= len(st) {
|
|
||||||
return "", errors.Errorf("offset %d is out of bounds", offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pos > 0 && st[pos-1] != '\x00' {
|
|
||||||
return "", errors.Errorf("offset %d isn't start of a string", offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
str := st[pos:]
|
|
||||||
end := bytes.IndexByte(str, '\x00')
|
|
||||||
if end == -1 {
|
|
||||||
return "", errors.Errorf("offset %d isn't null terminated", offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(str[:end]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st stringTable) LookupName(offset uint32) (Name, error) {
|
|
||||||
str, err := st.Lookup(offset)
|
|
||||||
return Name(str), err
|
|
||||||
}
|
|
550
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
550
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
@ -1,550 +0,0 @@
|
|||||||
package btf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const maxTypeDepth = 32
|
|
||||||
|
|
||||||
// TypeID identifies a type in a BTF section.
|
|
||||||
type TypeID uint32
|
|
||||||
|
|
||||||
// ID implements part of the Type interface.
|
|
||||||
func (tid TypeID) ID() TypeID {
|
|
||||||
return tid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type represents a type described by BTF.
|
|
||||||
type Type interface {
|
|
||||||
ID() TypeID
|
|
||||||
|
|
||||||
// Make a copy of the type, without copying Type members.
|
|
||||||
copy() Type
|
|
||||||
|
|
||||||
walk(*copyStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name identifies a type.
|
|
||||||
//
|
|
||||||
// Anonymous types have an empty name.
|
|
||||||
type Name string
|
|
||||||
|
|
||||||
func (n Name) name() string {
|
|
||||||
return string(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Void is the unit type of BTF.
|
|
||||||
type Void struct{}
|
|
||||||
|
|
||||||
func (v Void) ID() TypeID { return 0 }
|
|
||||||
func (v Void) copy() Type { return Void{} }
|
|
||||||
func (v Void) walk(*copyStack) {}
|
|
||||||
|
|
||||||
// Int is an integer of a given length.
|
|
||||||
type Int struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
|
|
||||||
// The size of the integer in bytes.
|
|
||||||
Size uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Int) size() uint32 { return i.Size }
|
|
||||||
func (i *Int) walk(*copyStack) {}
|
|
||||||
func (i *Int) copy() Type {
|
|
||||||
cpy := *i
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer is a pointer to another type.
|
|
||||||
type Pointer struct {
|
|
||||||
TypeID
|
|
||||||
Target Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pointer) size() uint32 { return 8 }
|
|
||||||
func (p *Pointer) walk(cs *copyStack) { cs.push(&p.Target) }
|
|
||||||
func (p *Pointer) copy() Type {
|
|
||||||
cpy := *p
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array is an array with a fixed number of elements.
|
|
||||||
type Array struct {
|
|
||||||
TypeID
|
|
||||||
Type Type
|
|
||||||
Nelems uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (arr *Array) walk(cs *copyStack) { cs.push(&arr.Type) }
|
|
||||||
func (arr *Array) copy() Type {
|
|
||||||
cpy := *arr
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Struct is a compound type of consecutive members.
|
|
||||||
type Struct struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
// The size of the struct including padding, in bytes
|
|
||||||
Size uint32
|
|
||||||
Members []Member
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Struct) size() uint32 { return s.Size }
|
|
||||||
|
|
||||||
func (s *Struct) walk(cs *copyStack) {
|
|
||||||
for i := range s.Members {
|
|
||||||
cs.push(&s.Members[i].Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Struct) copy() Type {
|
|
||||||
cpy := *s
|
|
||||||
cpy.Members = copyMembers(cpy.Members)
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Union is a compound type where members occupy the same memory.
|
|
||||||
type Union struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
// The size of the union including padding, in bytes.
|
|
||||||
Size uint32
|
|
||||||
Members []Member
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Union) size() uint32 { return u.Size }
|
|
||||||
|
|
||||||
func (u *Union) walk(cs *copyStack) {
|
|
||||||
for i := range u.Members {
|
|
||||||
cs.push(&u.Members[i].Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Union) copy() Type {
|
|
||||||
cpy := *u
|
|
||||||
cpy.Members = copyMembers(cpy.Members)
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Member is part of a Struct or Union.
|
|
||||||
//
|
|
||||||
// It is not a valid Type.
|
|
||||||
type Member struct {
|
|
||||||
Name
|
|
||||||
Type Type
|
|
||||||
Offset uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyMembers(in []Member) []Member {
|
|
||||||
cpy := make([]Member, 0, len(in))
|
|
||||||
for _, member := range in {
|
|
||||||
cpy = append(cpy, member)
|
|
||||||
}
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum lists possible values.
|
|
||||||
type Enum struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Enum) size() uint32 { return 4 }
|
|
||||||
func (e *Enum) walk(*copyStack) {}
|
|
||||||
func (e *Enum) copy() Type {
|
|
||||||
cpy := *e
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fwd is a forward declaration of a Type.
|
|
||||||
type Fwd struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fwd) walk(*copyStack) {}
|
|
||||||
func (f *Fwd) copy() Type {
|
|
||||||
cpy := *f
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Typedef is an alias of a Type.
|
|
||||||
type Typedef struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (td *Typedef) walk(cs *copyStack) { cs.push(&td.Type) }
|
|
||||||
func (td *Typedef) copy() Type {
|
|
||||||
cpy := *td
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Volatile is a modifier.
|
|
||||||
type Volatile struct {
|
|
||||||
TypeID
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Volatile) walk(cs *copyStack) { cs.push(&v.Type) }
|
|
||||||
func (v *Volatile) copy() Type {
|
|
||||||
cpy := *v
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Const is a modifier.
|
|
||||||
type Const struct {
|
|
||||||
TypeID
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Const) walk(cs *copyStack) { cs.push(&c.Type) }
|
|
||||||
func (c *Const) copy() Type {
|
|
||||||
cpy := *c
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict is a modifier.
|
|
||||||
type Restrict struct {
|
|
||||||
TypeID
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Restrict) walk(cs *copyStack) { cs.push(&r.Type) }
|
|
||||||
func (r *Restrict) copy() Type {
|
|
||||||
cpy := *r
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Func is a function definition.
|
|
||||||
type Func struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Func) walk(cs *copyStack) { cs.push(&f.Type) }
|
|
||||||
func (f *Func) copy() Type {
|
|
||||||
cpy := *f
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// FuncProto is a function declaration.
|
|
||||||
type FuncProto struct {
|
|
||||||
TypeID
|
|
||||||
Return Type
|
|
||||||
// Parameters not supported yet
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fp *FuncProto) walk(cs *copyStack) { cs.push(&fp.Return) }
|
|
||||||
func (fp *FuncProto) copy() Type {
|
|
||||||
cpy := *fp
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Var is a global variable.
|
|
||||||
type Var struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Var) walk(cs *copyStack) { cs.push(&v.Type) }
|
|
||||||
func (v *Var) copy() Type {
|
|
||||||
cpy := *v
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Datasec is a global program section containing data.
|
|
||||||
type Datasec struct {
|
|
||||||
TypeID
|
|
||||||
Name
|
|
||||||
Size uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *Datasec) size() uint32 { return ds.Size }
|
|
||||||
func (ds *Datasec) walk(*copyStack) {}
|
|
||||||
func (ds *Datasec) copy() Type {
|
|
||||||
cpy := *ds
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
type sizer interface {
|
|
||||||
size() uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ sizer = (*Int)(nil)
|
|
||||||
_ sizer = (*Pointer)(nil)
|
|
||||||
_ sizer = (*Struct)(nil)
|
|
||||||
_ sizer = (*Union)(nil)
|
|
||||||
_ sizer = (*Enum)(nil)
|
|
||||||
_ sizer = (*Datasec)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Sizeof returns the size of a type in bytes.
|
|
||||||
//
|
|
||||||
// Returns an error if the size can't be computed.
|
|
||||||
func Sizeof(typ Type) (int, error) {
|
|
||||||
var (
|
|
||||||
n = int64(1)
|
|
||||||
elem int64
|
|
||||||
)
|
|
||||||
|
|
||||||
for i := 0; i < maxTypeDepth; i++ {
|
|
||||||
switch v := typ.(type) {
|
|
||||||
case *Array:
|
|
||||||
if n > 0 && int64(v.Nelems) > math.MaxInt64/n {
|
|
||||||
return 0, errors.New("overflow")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Arrays may be of zero length, which allows
|
|
||||||
// n to be zero as well.
|
|
||||||
n *= int64(v.Nelems)
|
|
||||||
typ = v.Type
|
|
||||||
continue
|
|
||||||
|
|
||||||
case sizer:
|
|
||||||
elem = int64(v.size())
|
|
||||||
|
|
||||||
case *Typedef:
|
|
||||||
typ = v.Type
|
|
||||||
continue
|
|
||||||
case *Volatile:
|
|
||||||
typ = v.Type
|
|
||||||
continue
|
|
||||||
case *Const:
|
|
||||||
typ = v.Type
|
|
||||||
continue
|
|
||||||
case *Restrict:
|
|
||||||
typ = v.Type
|
|
||||||
continue
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0, errors.Errorf("unrecognized type %T", typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > 0 && elem > math.MaxInt64/n {
|
|
||||||
return 0, errors.New("overflow")
|
|
||||||
}
|
|
||||||
|
|
||||||
size := n * elem
|
|
||||||
if int64(int(size)) != size {
|
|
||||||
return 0, errors.New("overflow")
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(size), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, errors.New("exceeded type depth")
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy a Type recursively.
|
|
||||||
//
|
|
||||||
// typ may form a cycle.
|
|
||||||
func copyType(typ Type) Type {
|
|
||||||
var (
|
|
||||||
copies = make(map[Type]Type)
|
|
||||||
work copyStack
|
|
||||||
)
|
|
||||||
|
|
||||||
for t := &typ; t != nil; t = work.pop() {
|
|
||||||
// *t is the identity of the type.
|
|
||||||
if cpy := copies[*t]; cpy != nil {
|
|
||||||
*t = cpy
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
cpy := (*t).copy()
|
|
||||||
copies[*t] = cpy
|
|
||||||
*t = cpy
|
|
||||||
|
|
||||||
// Mark any nested types for copying.
|
|
||||||
cpy.walk(&work)
|
|
||||||
}
|
|
||||||
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyStack keeps track of pointers to types which still
|
|
||||||
// need to be copied.
|
|
||||||
type copyStack []*Type
|
|
||||||
|
|
||||||
// push adds a type to the stack.
|
|
||||||
func (cs *copyStack) push(t *Type) {
|
|
||||||
*cs = append(*cs, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pop returns the topmost Type, or nil.
|
|
||||||
func (cs *copyStack) pop() *Type {
|
|
||||||
n := len(*cs)
|
|
||||||
if n == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
t := (*cs)[n-1]
|
|
||||||
*cs = (*cs)[:n-1]
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
type namer interface {
|
|
||||||
name() string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ namer = Name("")
|
|
||||||
|
|
||||||
// inflateRawTypes takes a list of raw btf types linked via type IDs, and turns
|
|
||||||
// it into a graph of Types connected via pointers.
|
|
||||||
//
|
|
||||||
// Returns a map of named types (so, where NameOff is non-zero). Since BTF ignores
|
|
||||||
// compilation units, multiple types may share the same name. A Type may form a
|
|
||||||
// cyclic graph by pointing at itself.
|
|
||||||
func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map[string][]Type, err error) {
|
|
||||||
type fixup struct {
|
|
||||||
id TypeID
|
|
||||||
typ *Type
|
|
||||||
}
|
|
||||||
|
|
||||||
var fixups []fixup
|
|
||||||
convertMembers := func(raw []btfMember) ([]Member, error) {
|
|
||||||
// NB: The fixup below relies on pre-allocating this array to
|
|
||||||
// work, since otherwise append might re-allocate members.
|
|
||||||
members := make([]Member, 0, len(raw))
|
|
||||||
for i, btfMember := range raw {
|
|
||||||
name, err := rawStrings.LookupName(btfMember.NameOff)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "can't get name for member %d", i)
|
|
||||||
}
|
|
||||||
members = append(members, Member{
|
|
||||||
Name: name,
|
|
||||||
Offset: btfMember.Offset,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for i := range members {
|
|
||||||
fixups = append(fixups, fixup{raw[i].Type, &members[i].Type})
|
|
||||||
}
|
|
||||||
return members, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
types := make([]Type, 0, len(rawTypes))
|
|
||||||
types = append(types, Void{})
|
|
||||||
namedTypes = make(map[string][]Type)
|
|
||||||
|
|
||||||
for i, raw := range rawTypes {
|
|
||||||
var (
|
|
||||||
// Void is defined to always be type ID 0, and is thus
|
|
||||||
// omitted from BTF.
|
|
||||||
id = TypeID(i + 1)
|
|
||||||
typ Type
|
|
||||||
)
|
|
||||||
|
|
||||||
name, err := rawStrings.LookupName(raw.NameOff)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "can't get name for type id %d", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch raw.Kind() {
|
|
||||||
case kindInt:
|
|
||||||
typ = &Int{id, name, raw.Size()}
|
|
||||||
|
|
||||||
case kindPointer:
|
|
||||||
ptr := &Pointer{id, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &ptr.Target})
|
|
||||||
typ = ptr
|
|
||||||
|
|
||||||
case kindArray:
|
|
||||||
btfArr := raw.data.(*btfArray)
|
|
||||||
|
|
||||||
// IndexType is unused according to btf.rst.
|
|
||||||
// Don't make it available right now.
|
|
||||||
arr := &Array{id, nil, btfArr.Nelems}
|
|
||||||
fixups = append(fixups, fixup{btfArr.Type, &arr.Type})
|
|
||||||
typ = arr
|
|
||||||
|
|
||||||
case kindStruct:
|
|
||||||
members, err := convertMembers(raw.data.([]btfMember))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "struct %s (id %d)", name, id)
|
|
||||||
}
|
|
||||||
typ = &Struct{id, name, raw.Size(), members}
|
|
||||||
|
|
||||||
case kindUnion:
|
|
||||||
members, err := convertMembers(raw.data.([]btfMember))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "union %s (id %d)", name, id)
|
|
||||||
}
|
|
||||||
typ = &Union{id, name, raw.Size(), members}
|
|
||||||
|
|
||||||
case kindEnum:
|
|
||||||
typ = &Enum{id, name}
|
|
||||||
|
|
||||||
case kindForward:
|
|
||||||
typ = &Fwd{id, name}
|
|
||||||
|
|
||||||
case kindTypedef:
|
|
||||||
typedef := &Typedef{id, name, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &typedef.Type})
|
|
||||||
typ = typedef
|
|
||||||
|
|
||||||
case kindVolatile:
|
|
||||||
volatile := &Volatile{id, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &volatile.Type})
|
|
||||||
typ = volatile
|
|
||||||
|
|
||||||
case kindConst:
|
|
||||||
cnst := &Const{id, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &cnst.Type})
|
|
||||||
typ = cnst
|
|
||||||
|
|
||||||
case kindRestrict:
|
|
||||||
restrict := &Restrict{id, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &restrict.Type})
|
|
||||||
typ = restrict
|
|
||||||
|
|
||||||
case kindFunc:
|
|
||||||
fn := &Func{id, name, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &fn.Type})
|
|
||||||
typ = fn
|
|
||||||
|
|
||||||
case kindFuncProto:
|
|
||||||
fp := &FuncProto{id, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &fp.Return})
|
|
||||||
typ = fp
|
|
||||||
|
|
||||||
case kindVar:
|
|
||||||
v := &Var{id, name, nil}
|
|
||||||
fixups = append(fixups, fixup{raw.Type(), &v.Type})
|
|
||||||
typ = v
|
|
||||||
|
|
||||||
case kindDatasec:
|
|
||||||
typ = &Datasec{id, name, raw.SizeType}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
|
||||||
}
|
|
||||||
|
|
||||||
types = append(types, typ)
|
|
||||||
|
|
||||||
if namer, ok := typ.(namer); ok {
|
|
||||||
if name := namer.name(); name != "" {
|
|
||||||
namedTypes[name] = append(namedTypes[name], typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fixup := range fixups {
|
|
||||||
i := int(fixup.id)
|
|
||||||
if i >= len(types) {
|
|
||||||
return nil, errors.Errorf("reference to invalid type id: %d", fixup.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
*fixup.typ = types[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return namedTypes, nil
|
|
||||||
}
|
|
50
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
50
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
@ -1,50 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrorWithLog returns an error that includes logs from the
|
|
||||||
// kernel verifier.
|
|
||||||
//
|
|
||||||
// logErr should be the error returned by the syscall that generated
|
|
||||||
// the log. It is used to check for truncation of the output.
|
|
||||||
func ErrorWithLog(err error, log []byte, logErr error) error {
|
|
||||||
logStr := strings.Trim(CString(log), "\t\r\n ")
|
|
||||||
if errors.Cause(logErr) == unix.ENOSPC {
|
|
||||||
logStr += " (truncated...)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return &loadError{err, logStr}
|
|
||||||
}
|
|
||||||
|
|
||||||
type loadError struct {
|
|
||||||
cause error
|
|
||||||
log string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (le *loadError) Error() string {
|
|
||||||
if le.log == "" {
|
|
||||||
return le.cause.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s: %s", le.cause, le.log)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (le *loadError) Cause() error {
|
|
||||||
return le.cause
|
|
||||||
}
|
|
||||||
|
|
||||||
// CString turns a NUL / zero terminated byte buffer into a string.
|
|
||||||
func CString(in []byte) string {
|
|
||||||
inLen := bytes.IndexByte(in, 0)
|
|
||||||
if inLen == -1 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string(in[:inLen])
|
|
||||||
}
|
|
63
vendor/github.com/cilium/ebpf/internal/fd.go
generated
vendored
63
vendor/github.com/cilium/ebpf/internal/fd.go
generated
vendored
@ -1,63 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrClosedFd = errors.New("use of closed file descriptor")
|
|
||||||
|
|
||||||
type FD struct {
|
|
||||||
raw int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFD(value uint32) *FD {
|
|
||||||
fd := &FD{int64(value)}
|
|
||||||
runtime.SetFinalizer(fd, (*FD).Close)
|
|
||||||
return fd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fd *FD) String() string {
|
|
||||||
return strconv.FormatInt(fd.raw, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fd *FD) Value() (uint32, error) {
|
|
||||||
if fd.raw < 0 {
|
|
||||||
return 0, ErrClosedFd
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint32(fd.raw), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fd *FD) Close() error {
|
|
||||||
if fd.raw < 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
value := int(fd.raw)
|
|
||||||
fd.raw = -1
|
|
||||||
|
|
||||||
fd.Forget()
|
|
||||||
return unix.Close(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fd *FD) Forget() {
|
|
||||||
runtime.SetFinalizer(fd, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fd *FD) Dup() (*FD, error) {
|
|
||||||
if fd.raw < 0 {
|
|
||||||
return nil, ErrClosedFd
|
|
||||||
}
|
|
||||||
|
|
||||||
dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't dup fd")
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewFD(uint32(dup)), nil
|
|
||||||
}
|
|
85
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
85
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
@ -1,85 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnsupportedFeatureError is returned by FeatureTest() functions.
|
|
||||||
type UnsupportedFeatureError struct {
|
|
||||||
// The minimum Linux mainline version required for this feature.
|
|
||||||
// Used for the error string, and for sanity checking during testing.
|
|
||||||
MinimumVersion Version
|
|
||||||
|
|
||||||
// The name of the feature that isn't supported.
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ufe *UnsupportedFeatureError) Error() string {
|
|
||||||
return fmt.Sprintf("%s not supported (requires >= %s)", ufe.Name, ufe.MinimumVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FeatureTest wraps a function so that it is run at most once.
|
|
||||||
//
|
|
||||||
// name should identify the tested feature, while version must be in the
|
|
||||||
// form Major.Minor[.Patch].
|
|
||||||
//
|
|
||||||
// Returns a descriptive UnsupportedFeatureError if the feature is not available.
|
|
||||||
func FeatureTest(name, version string, fn func() bool) func() error {
|
|
||||||
v, err := NewVersion(version)
|
|
||||||
if err != nil {
|
|
||||||
return func() error { return err }
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
once sync.Once
|
|
||||||
result error
|
|
||||||
)
|
|
||||||
|
|
||||||
return func() error {
|
|
||||||
once.Do(func() {
|
|
||||||
if !fn() {
|
|
||||||
result = &UnsupportedFeatureError{
|
|
||||||
MinimumVersion: v,
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Version in the form Major.Minor.Patch.
|
|
||||||
type Version [3]uint16
|
|
||||||
|
|
||||||
// NewVersion creates a version from a string like "Major.Minor.Patch".
|
|
||||||
//
|
|
||||||
// Patch is optional.
|
|
||||||
func NewVersion(ver string) (Version, error) {
|
|
||||||
var major, minor, patch uint16
|
|
||||||
n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
|
|
||||||
if n < 2 {
|
|
||||||
return Version{}, errors.Errorf("invalid version: %s", ver)
|
|
||||||
}
|
|
||||||
return Version{major, minor, patch}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Version) String() string {
|
|
||||||
if v[2] == 0 {
|
|
||||||
return fmt.Sprintf("v%d.%d", v[0], v[1])
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Less returns true if the version is less than another version.
|
|
||||||
func (v Version) Less(other Version) bool {
|
|
||||||
for i, a := range v {
|
|
||||||
if a == other[i] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return a < other[i]
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
16
vendor/github.com/cilium/ebpf/internal/io.go
generated
vendored
16
vendor/github.com/cilium/ebpf/internal/io.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import "github.com/pkg/errors"
|
|
||||||
|
|
||||||
// DiscardZeroes makes sure that all written bytes are zero
|
|
||||||
// before discarding them.
|
|
||||||
type DiscardZeroes struct{}
|
|
||||||
|
|
||||||
func (DiscardZeroes) Write(p []byte) (int, error) {
|
|
||||||
for _, b := range p {
|
|
||||||
if b != 0 {
|
|
||||||
return 0, errors.New("encountered non-zero byte")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
26
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
26
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
// NewPointer creates a 64-bit pointer from an unsafe Pointer.
|
|
||||||
func NewPointer(ptr unsafe.Pointer) Pointer {
|
|
||||||
return Pointer{ptr: ptr}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSlicePointer creates a 64-bit pointer from a byte slice.
|
|
||||||
func NewSlicePointer(buf []byte) Pointer {
|
|
||||||
if len(buf) == 0 {
|
|
||||||
return Pointer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pointer{ptr: unsafe.Pointer(&buf[0])}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStringPointer creates a 64-bit pointer from a string.
|
|
||||||
func NewStringPointer(str string) Pointer {
|
|
||||||
if str == "" {
|
|
||||||
return Pointer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pointer{ptr: unsafe.Pointer(&[]byte(str)[0])}
|
|
||||||
}
|
|
23
vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
23
vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BPF wraps SYS_BPF.
|
|
||||||
//
|
|
||||||
// Any pointers contained in attr must use the Pointer type from this package.
|
|
||||||
func BPF(cmd int, 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
|
|
||||||
}
|
|
9
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
9
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
@ -30,7 +30,6 @@ const (
|
|||||||
PerfBitWatermark = linux.PerfBitWatermark
|
PerfBitWatermark = linux.PerfBitWatermark
|
||||||
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
|
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
|
||||||
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
|
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
|
||||||
RLIM_INFINITY = linux.RLIM_INFINITY
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Statfs_t is a wrapper
|
// Statfs_t is a wrapper
|
||||||
@ -117,11 +116,3 @@ type PerfEventAttr = linux.PerfEventAttr
|
|||||||
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
||||||
return linux.PerfEventOpen(attr, pid, cpu, groupFd, flags)
|
return linux.PerfEventOpen(attr, pid, cpu, groupFd, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utsname is a wrapper
|
|
||||||
type Utsname = linux.Utsname
|
|
||||||
|
|
||||||
// Uname is a wrapper
|
|
||||||
func Uname(buf *Utsname) (err error) {
|
|
||||||
return linux.Uname(buf)
|
|
||||||
}
|
|
||||||
|
10
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
10
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
@ -181,13 +181,3 @@ type PerfEventAttr struct {
|
|||||||
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
||||||
return 0, errNonLinux
|
return 0, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utsname is a wrapper
|
|
||||||
type Utsname struct {
|
|
||||||
Release [65]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uname is a wrapper
|
|
||||||
func Uname(buf *Utsname) (err error) {
|
|
||||||
return errNonLinux
|
|
||||||
}
|
|
||||||
|
28
vendor/github.com/cilium/ebpf/linker.go
generated
vendored
28
vendor/github.com/cilium/ebpf/linker.go
generated
vendored
@ -2,35 +2,23 @@ package ebpf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/internal/btf"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// link resolves bpf-to-bpf calls.
|
// link resolves bpf-to-bpf calls.
|
||||||
//
|
//
|
||||||
// Each library may contain multiple functions / labels, and is only linked
|
// Each section may contain multiple functions / labels, and is only linked
|
||||||
// if the program being edited references one of these functions.
|
// if the program being edited references one of these functions.
|
||||||
//
|
//
|
||||||
// Libraries must not require linking themselves.
|
// Sections must not require linking themselves.
|
||||||
func link(prog *ProgramSpec, libs []*ProgramSpec) error {
|
func link(insns asm.Instructions, sections ...asm.Instructions) (asm.Instructions, error) {
|
||||||
for _, lib := range libs {
|
for _, section := range sections {
|
||||||
insns, err := linkSection(prog.Instructions, lib.Instructions)
|
var err error
|
||||||
|
insns, err = linkSection(insns, section)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "linking %s", lib.Name)
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
if len(insns) == len(prog.Instructions) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
prog.Instructions = insns
|
|
||||||
if prog.BTF != nil && lib.BTF != nil {
|
|
||||||
if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil {
|
|
||||||
return errors.Wrapf(err, "linking BTF of %s", lib.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return insns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func linkSection(insns, section asm.Instructions) (asm.Instructions, error) {
|
func linkSection(insns, section asm.Instructions) (asm.Instructions, error) {
|
||||||
|
120
vendor/github.com/cilium/ebpf/map.go
generated
vendored
120
vendor/github.com/cilium/ebpf/map.go
generated
vendored
@ -2,9 +2,9 @@ package ebpf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
"github.com/cilium/ebpf/internal/btf"
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -20,12 +20,8 @@ type MapSpec struct {
|
|||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
Flags uint32
|
Flags uint32
|
||||||
|
|
||||||
// InnerMap is used as a template for ArrayOfMaps and HashOfMaps
|
// InnerMap is used as a template for ArrayOfMaps and HashOfMaps
|
||||||
InnerMap *MapSpec
|
InnerMap *MapSpec
|
||||||
|
|
||||||
// The BTF associated with this map.
|
|
||||||
BTF *btf.Map
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MapSpec) String() string {
|
func (ms *MapSpec) String() string {
|
||||||
@ -53,9 +49,8 @@ func (ms *MapSpec) Copy() *MapSpec {
|
|||||||
// Implement encoding.BinaryMarshaler or encoding.BinaryUnmarshaler
|
// Implement encoding.BinaryMarshaler or encoding.BinaryUnmarshaler
|
||||||
// if you require custom encoding.
|
// if you require custom encoding.
|
||||||
type Map struct {
|
type Map struct {
|
||||||
name string
|
fd *bpfFD
|
||||||
fd *internal.FD
|
abi MapABI
|
||||||
abi MapABI
|
|
||||||
// Per CPU maps return values larger than the size in the spec
|
// Per CPU maps return values larger than the size in the spec
|
||||||
fullValueSize int
|
fullValueSize int
|
||||||
}
|
}
|
||||||
@ -67,14 +62,14 @@ func NewMapFromFD(fd int) (*Map, error) {
|
|||||||
if fd < 0 {
|
if fd < 0 {
|
||||||
return nil, errors.New("invalid fd")
|
return nil, errors.New("invalid fd")
|
||||||
}
|
}
|
||||||
bpfFd := internal.NewFD(uint32(fd))
|
bpfFd := newBPFFD(uint32(fd))
|
||||||
|
|
||||||
name, abi, err := newMapABIFromFd(bpfFd)
|
abi, err := newMapABIFromFd(bpfFd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bpfFd.Forget()
|
bpfFd.forget()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newMap(bpfFd, name, abi)
|
return newMap(bpfFd, abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMap creates a new Map.
|
// NewMap creates a new Map.
|
||||||
@ -82,47 +77,30 @@ func NewMapFromFD(fd int) (*Map, error) {
|
|||||||
// Creating a map for the first time will perform feature detection
|
// Creating a map for the first time will perform feature detection
|
||||||
// by creating small, temporary maps.
|
// by creating small, temporary maps.
|
||||||
func NewMap(spec *MapSpec) (*Map, error) {
|
func NewMap(spec *MapSpec) (*Map, error) {
|
||||||
if spec.BTF == nil {
|
|
||||||
return newMapWithBTF(spec, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
handle, err := btf.NewHandle(btf.MapSpec(spec.BTF))
|
|
||||||
if err != nil && !btf.IsNotSupported(err) {
|
|
||||||
return nil, errors.Wrap(err, "can't load BTF")
|
|
||||||
}
|
|
||||||
|
|
||||||
return newMapWithBTF(spec, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) {
|
|
||||||
if spec.Type != ArrayOfMaps && spec.Type != HashOfMaps {
|
if spec.Type != ArrayOfMaps && spec.Type != HashOfMaps {
|
||||||
return createMap(spec, nil, handle)
|
return createMap(spec, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.InnerMap == nil {
|
if spec.InnerMap == nil {
|
||||||
return nil, errors.Errorf("%s requires InnerMap", spec.Type)
|
return nil, errors.Errorf("%s requires InnerMap", spec.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
template, err := createMap(spec.InnerMap, nil, handle)
|
template, err := createMap(spec.InnerMap, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer template.Close()
|
defer template.Close()
|
||||||
|
|
||||||
return createMap(spec, template.fd, handle)
|
return createMap(spec, template.fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, error) {
|
func createMap(spec *MapSpec, inner *bpfFD) (*Map, error) {
|
||||||
spec = spec.Copy()
|
spec = spec.Copy()
|
||||||
|
|
||||||
switch spec.Type {
|
switch spec.Type {
|
||||||
case ArrayOfMaps:
|
case ArrayOfMaps:
|
||||||
fallthrough
|
fallthrough
|
||||||
case HashOfMaps:
|
case HashOfMaps:
|
||||||
if err := haveNestedMaps(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if spec.ValueSize != 0 && spec.ValueSize != 4 {
|
if spec.ValueSize != 0 && spec.ValueSize != 4 {
|
||||||
return nil, errors.Errorf("ValueSize must be zero or four for map of map")
|
return nil, errors.Errorf("ValueSize must be zero or four for map of map")
|
||||||
}
|
}
|
||||||
@ -157,24 +135,18 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
|
|||||||
|
|
||||||
if inner != nil {
|
if inner != nil {
|
||||||
var err error
|
var err error
|
||||||
attr.innerMapFd, err = inner.Value()
|
attr.innerMapFd, err = inner.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "map create")
|
return nil, errors.Wrap(err, "map create")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil && spec.BTF != nil {
|
|
||||||
attr.btfFd = uint32(handle.FD())
|
|
||||||
attr.btfKeyTypeID = btf.MapKey(spec.BTF).ID()
|
|
||||||
attr.btfValueTypeID = btf.MapValue(spec.BTF).ID()
|
|
||||||
}
|
|
||||||
|
|
||||||
name, err := newBPFObjName(spec.Name)
|
name, err := newBPFObjName(spec.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "map create")
|
return nil, errors.Wrap(err, "map create")
|
||||||
}
|
}
|
||||||
|
|
||||||
if haveObjName() == nil {
|
if haveObjName.Result() {
|
||||||
attr.mapName = name
|
attr.mapName = name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,12 +155,11 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
|
|||||||
return nil, errors.Wrap(err, "map create")
|
return nil, errors.Wrap(err, "map create")
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMap(fd, spec.Name, newMapABIFromSpec(spec))
|
return newMap(fd, newMapABIFromSpec(spec))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMap(fd *internal.FD, name string, abi *MapABI) (*Map, error) {
|
func newMap(fd *bpfFD, abi *MapABI) (*Map, error) {
|
||||||
m := &Map{
|
m := &Map{
|
||||||
name,
|
|
||||||
fd,
|
fd,
|
||||||
*abi,
|
*abi,
|
||||||
int(abi.ValueSize),
|
int(abi.ValueSize),
|
||||||
@ -208,10 +179,7 @@ func newMap(fd *internal.FD, name string, abi *MapABI) (*Map, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) String() string {
|
func (m *Map) String() string {
|
||||||
if m.name != "" {
|
return fmt.Sprintf("%s#%d", m.abi.Type, m.fd)
|
||||||
return fmt.Sprintf("%s(%s)#%v", m.abi.Type, m.name, m.fd)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s#%v", m.abi.Type, m.fd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABI gets the ABI of the Map
|
// ABI gets the ABI of the Map
|
||||||
@ -274,28 +242,12 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupAndDelete retrieves and deletes a value from a Map.
|
|
||||||
func (m *Map) LookupAndDelete(key, valueOut interface{}) error {
|
|
||||||
valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize)
|
|
||||||
|
|
||||||
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessage(err, "can't marshal key")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil {
|
|
||||||
return errors.WithMessage(err, "lookup and delete and delete failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return unmarshalBytes(valueOut, valueBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupBytes gets a value from Map.
|
// LookupBytes gets a value from Map.
|
||||||
//
|
//
|
||||||
// Returns a nil value if a key doesn't exist.
|
// Returns a nil value if a key doesn't exist.
|
||||||
func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
|
func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
|
||||||
valueBytes := make([]byte, m.fullValueSize)
|
valueBytes := make([]byte, m.fullValueSize)
|
||||||
valuePtr := internal.NewSlicePointer(valueBytes)
|
valuePtr := newPtr(unsafe.Pointer(&valueBytes[0]))
|
||||||
|
|
||||||
err := m.lookup(key, valuePtr)
|
err := m.lookup(key, valuePtr)
|
||||||
if IsNotExist(err) {
|
if IsNotExist(err) {
|
||||||
@ -305,7 +257,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
|
|||||||
return valueBytes, err
|
return valueBytes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error {
|
func (m *Map) lookup(key interface{}, valueOut syscallPtr) error {
|
||||||
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
|
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithMessage(err, "can't marshal key")
|
return errors.WithMessage(err, "can't marshal key")
|
||||||
@ -343,7 +295,7 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
|
|||||||
return errors.WithMessage(err, "can't marshal key")
|
return errors.WithMessage(err, "can't marshal key")
|
||||||
}
|
}
|
||||||
|
|
||||||
var valuePtr internal.Pointer
|
var valuePtr syscallPtr
|
||||||
if m.abi.Type.hasPerCPUValue() {
|
if m.abi.Type.hasPerCPUValue() {
|
||||||
valuePtr, err = marshalPerCPUValue(value, int(m.abi.ValueSize))
|
valuePtr, err = marshalPerCPUValue(value, int(m.abi.ValueSize))
|
||||||
} else {
|
} else {
|
||||||
@ -394,7 +346,7 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error {
|
|||||||
// Use Iterate if you want to traverse all entries in the map.
|
// Use Iterate if you want to traverse all entries in the map.
|
||||||
func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
|
func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
|
||||||
nextKey := make([]byte, m.abi.KeySize)
|
nextKey := make([]byte, m.abi.KeySize)
|
||||||
nextKeyPtr := internal.NewSlicePointer(nextKey)
|
nextKeyPtr := newPtr(unsafe.Pointer(&nextKey[0]))
|
||||||
|
|
||||||
err := m.nextKey(key, nextKeyPtr)
|
err := m.nextKey(key, nextKeyPtr)
|
||||||
if IsNotExist(err) {
|
if IsNotExist(err) {
|
||||||
@ -404,9 +356,9 @@ func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
|
|||||||
return nextKey, err
|
return nextKey, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error {
|
func (m *Map) nextKey(key interface{}, nextKeyOut syscallPtr) error {
|
||||||
var (
|
var (
|
||||||
keyPtr internal.Pointer
|
keyPtr syscallPtr
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -439,14 +391,14 @@ func (m *Map) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.fd.Close()
|
return m.fd.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FD gets the file descriptor of the Map.
|
// FD gets the file descriptor of the Map.
|
||||||
//
|
//
|
||||||
// Calling this function is invalid after Close has been called.
|
// Calling this function is invalid after Close has been called.
|
||||||
func (m *Map) FD() int {
|
func (m *Map) FD() int {
|
||||||
fd, err := m.fd.Value()
|
fd, err := m.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Best effort: -1 is the number most likely to be an
|
// Best effort: -1 is the number most likely to be an
|
||||||
// invalid file descriptor.
|
// invalid file descriptor.
|
||||||
@ -467,12 +419,12 @@ func (m *Map) Clone() (*Map, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dup, err := m.fd.Dup()
|
dup, err := m.fd.dup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "can't clone map")
|
return nil, errors.Wrap(err, "can't clone map")
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMap(dup, m.name, &m.abi)
|
return newMap(dup, &m.abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pin persists the map past the lifetime of the process that created it.
|
// Pin persists the map past the lifetime of the process that created it.
|
||||||
@ -484,19 +436,19 @@ func (m *Map) Pin(fileName string) error {
|
|||||||
|
|
||||||
// LoadPinnedMap load a Map from a BPF file.
|
// LoadPinnedMap load a Map from a BPF file.
|
||||||
//
|
//
|
||||||
// The function is not compatible with nested maps.
|
// Requires at least Linux 4.13, and is not compatible with
|
||||||
// Use LoadPinnedMapExplicit in these situations.
|
// nested maps. Use LoadPinnedMapExplicit in these situations.
|
||||||
func LoadPinnedMap(fileName string) (*Map, error) {
|
func LoadPinnedMap(fileName string) (*Map, error) {
|
||||||
fd, err := bpfGetObject(fileName)
|
fd, err := bpfGetObject(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
name, abi, err := newMapABIFromFd(fd)
|
abi, err := newMapABIFromFd(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fd.Close()
|
_ = fd.close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newMap(fd, name, abi)
|
return newMap(fd, abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPinnedMapExplicit loads a map with explicit parameters.
|
// LoadPinnedMapExplicit loads a map with explicit parameters.
|
||||||
@ -505,7 +457,7 @@ func LoadPinnedMapExplicit(fileName string, abi *MapABI) (*Map, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newMap(fd, "", abi)
|
return newMap(fd, abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalMap(buf []byte) (*Map, error) {
|
func unmarshalMap(buf []byte) (*Map, error) {
|
||||||
@ -521,18 +473,18 @@ func unmarshalMap(buf []byte) (*Map, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
name, abi, err := newMapABIFromFd(fd)
|
abi, err := newMapABIFromFd(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fd.Close()
|
_ = fd.close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMap(fd, name, abi)
|
return newMap(fd, abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalBinary implements BinaryMarshaler.
|
// MarshalBinary implements BinaryMarshaler.
|
||||||
func (m *Map) MarshalBinary() ([]byte, error) {
|
func (m *Map) MarshalBinary() ([]byte, error) {
|
||||||
fd, err := m.fd.Value()
|
fd, err := m.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
33
vendor/github.com/cilium/ebpf/marshalers.go
generated
vendored
33
vendor/github.com/cilium/ebpf/marshalers.go
generated
vendored
@ -13,24 +13,17 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
|
func marshalPtr(data interface{}, length int) (syscallPtr, error) {
|
||||||
if data == nil {
|
|
||||||
if length == 0 {
|
|
||||||
return internal.NewPointer(nil), nil
|
|
||||||
}
|
|
||||||
return internal.Pointer{}, errors.New("can't use nil as key of map")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ptr, ok := data.(unsafe.Pointer); ok {
|
if ptr, ok := data.(unsafe.Pointer); ok {
|
||||||
return internal.NewPointer(ptr), nil
|
return newPtr(ptr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := marshalBytes(data, length)
|
buf, err := marshalBytes(data, length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return internal.Pointer{}, err
|
return syscallPtr{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return internal.NewSlicePointer(buf), nil
|
return newPtr(unsafe.Pointer(&buf[0])), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalBytes(data interface{}, length int) (buf []byte, err error) {
|
func marshalBytes(data interface{}, length int) (buf []byte, err error) {
|
||||||
@ -59,13 +52,13 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
|
|||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) {
|
func makeBuffer(dst interface{}, length int) (syscallPtr, []byte) {
|
||||||
if ptr, ok := dst.(unsafe.Pointer); ok {
|
if ptr, ok := dst.(unsafe.Pointer); ok {
|
||||||
return internal.NewPointer(ptr), nil
|
return newPtr(ptr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, length)
|
buf := make([]byte, length)
|
||||||
return internal.NewSlicePointer(buf), buf
|
return newPtr(unsafe.Pointer(&buf[0])), buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalBytes(data interface{}, buf []byte) error {
|
func unmarshalBytes(data interface{}, buf []byte) error {
|
||||||
@ -106,21 +99,21 @@ func unmarshalBytes(data interface{}, buf []byte) error {
|
|||||||
// Values are initialized to zero if the slice has less elements than CPUs.
|
// Values are initialized to zero if the slice has less elements than CPUs.
|
||||||
//
|
//
|
||||||
// slice must have a type like []elementType.
|
// slice must have a type like []elementType.
|
||||||
func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) {
|
func marshalPerCPUValue(slice interface{}, elemLength int) (syscallPtr, error) {
|
||||||
sliceType := reflect.TypeOf(slice)
|
sliceType := reflect.TypeOf(slice)
|
||||||
if sliceType.Kind() != reflect.Slice {
|
if sliceType.Kind() != reflect.Slice {
|
||||||
return internal.Pointer{}, errors.New("per-CPU value requires slice")
|
return syscallPtr{}, errors.New("per-CPU value requires slice")
|
||||||
}
|
}
|
||||||
|
|
||||||
possibleCPUs, err := internal.PossibleCPUs()
|
possibleCPUs, err := internal.PossibleCPUs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return internal.Pointer{}, err
|
return syscallPtr{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sliceValue := reflect.ValueOf(slice)
|
sliceValue := reflect.ValueOf(slice)
|
||||||
sliceLen := sliceValue.Len()
|
sliceLen := sliceValue.Len()
|
||||||
if sliceLen > possibleCPUs {
|
if sliceLen > possibleCPUs {
|
||||||
return internal.Pointer{}, errors.Errorf("per-CPU value exceeds number of CPUs")
|
return syscallPtr{}, errors.Errorf("per-CPU value exceeds number of CPUs")
|
||||||
}
|
}
|
||||||
|
|
||||||
alignedElemLength := align(elemLength, 8)
|
alignedElemLength := align(elemLength, 8)
|
||||||
@ -130,14 +123,14 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
|
|||||||
elem := sliceValue.Index(i).Interface()
|
elem := sliceValue.Index(i).Interface()
|
||||||
elemBytes, err := marshalBytes(elem, elemLength)
|
elemBytes, err := marshalBytes(elem, elemLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return internal.Pointer{}, err
|
return syscallPtr{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
offset := i * alignedElemLength
|
offset := i * alignedElemLength
|
||||||
copy(buf[offset:offset+elemLength], elemBytes)
|
copy(buf[offset:offset+elemLength], elemBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return internal.NewSlicePointer(buf), nil
|
return newPtr(unsafe.Pointer(&buf[0])), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshalPerCPUValue decodes a buffer into a slice containing one value per
|
// unmarshalPerCPUValue decodes a buffer into a slice containing one value per
|
||||||
|
233
vendor/github.com/cilium/ebpf/prog.go
generated
vendored
233
vendor/github.com/cilium/ebpf/prog.go
generated
vendored
@ -4,18 +4,22 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
"github.com/cilium/ebpf/internal/btf"
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNotSupported = errors.New("ebpf: not supported by kernel")
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN.
|
// Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN.
|
||||||
// This is currently the maximum of spare space allocated for SKB
|
// This is currently the maximum of spare space allocated for SKB
|
||||||
@ -47,11 +51,6 @@ type ProgramSpec struct {
|
|||||||
Instructions asm.Instructions
|
Instructions asm.Instructions
|
||||||
License string
|
License string
|
||||||
KernelVersion uint32
|
KernelVersion uint32
|
||||||
|
|
||||||
// The BTF associated with this program. Changing Instructions
|
|
||||||
// will most likely invalidate the contained data, and may
|
|
||||||
// result in errors when attempting to load it into the kernel.
|
|
||||||
BTF *btf.Program
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns a copy of the spec.
|
// Copy returns a copy of the spec.
|
||||||
@ -74,7 +73,7 @@ type Program struct {
|
|||||||
// otherwise it is empty.
|
// otherwise it is empty.
|
||||||
VerifierLog string
|
VerifierLog string
|
||||||
|
|
||||||
fd *internal.FD
|
fd *bpfFD
|
||||||
name string
|
name string
|
||||||
abi ProgramABI
|
abi ProgramABI
|
||||||
}
|
}
|
||||||
@ -92,20 +91,7 @@ func NewProgram(spec *ProgramSpec) (*Program, error) {
|
|||||||
// Loading a program for the first time will perform
|
// Loading a program for the first time will perform
|
||||||
// feature detection by loading small, temporary programs.
|
// feature detection by loading small, temporary programs.
|
||||||
func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) {
|
func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) {
|
||||||
if spec.BTF == nil {
|
attr, err := convertProgramSpec(spec, haveObjName.Result())
|
||||||
return newProgramWithBTF(spec, nil, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
handle, err := btf.NewHandle(btf.ProgramSpec(spec.BTF))
|
|
||||||
if err != nil && !btf.IsNotSupported(err) {
|
|
||||||
return nil, errors.Wrap(err, "can't load BTF")
|
|
||||||
}
|
|
||||||
|
|
||||||
return newProgramWithBTF(spec, handle, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions) (*Program, error) {
|
|
||||||
attr, err := convertProgramSpec(spec, btf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -120,51 +106,62 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
|
|||||||
logBuf = make([]byte, logSize)
|
logBuf = make([]byte, logSize)
|
||||||
attr.logLevel = opts.LogLevel
|
attr.logLevel = opts.LogLevel
|
||||||
attr.logSize = uint32(len(logBuf))
|
attr.logSize = uint32(len(logBuf))
|
||||||
attr.logBuf = internal.NewSlicePointer(logBuf)
|
attr.logBuf = newPtr(unsafe.Pointer(&logBuf[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := bpfProgLoad(attr)
|
fd, err := bpfProgLoad(attr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
prog := newProgram(fd, spec.Name, &ProgramABI{spec.Type})
|
prog := newProgram(fd, spec.Name, &ProgramABI{spec.Type})
|
||||||
prog.VerifierLog = internal.CString(logBuf)
|
prog.VerifierLog = convertCString(logBuf)
|
||||||
return prog, nil
|
return prog, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
truncated := errors.Cause(err) == unix.ENOSPC
|
||||||
if opts.LogLevel == 0 {
|
if opts.LogLevel == 0 {
|
||||||
// Re-run with the verifier enabled to get better error messages.
|
// Re-run with the verifier enabled to get better error messages.
|
||||||
logBuf = make([]byte, logSize)
|
logBuf = make([]byte, logSize)
|
||||||
attr.logLevel = 1
|
attr.logLevel = 1
|
||||||
attr.logSize = uint32(len(logBuf))
|
attr.logSize = uint32(len(logBuf))
|
||||||
attr.logBuf = internal.NewSlicePointer(logBuf)
|
attr.logBuf = newPtr(unsafe.Pointer(&logBuf[0]))
|
||||||
|
|
||||||
_, logErr := bpfProgLoad(attr)
|
_, nerr := bpfProgLoad(attr)
|
||||||
err = internal.ErrorWithLog(err, logBuf, logErr)
|
truncated = errors.Cause(nerr) == unix.ENOSPC
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.Wrap(err, "can't load program")
|
logs := convertCString(logBuf)
|
||||||
|
if truncated {
|
||||||
|
logs += "\n(truncated...)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &loadError{err, logs}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProgramFromFD creates a program from a raw fd.
|
// NewProgramFromFD creates a program from a raw fd.
|
||||||
//
|
//
|
||||||
// You should not use fd after calling this function.
|
// You should not use fd after calling this function.
|
||||||
//
|
|
||||||
// Requires at least Linux 4.11.
|
|
||||||
func NewProgramFromFD(fd int) (*Program, error) {
|
func NewProgramFromFD(fd int) (*Program, error) {
|
||||||
if fd < 0 {
|
if fd < 0 {
|
||||||
return nil, errors.New("invalid fd")
|
return nil, errors.New("invalid fd")
|
||||||
}
|
}
|
||||||
bpfFd := internal.NewFD(uint32(fd))
|
bpfFd := newBPFFD(uint32(fd))
|
||||||
|
|
||||||
name, abi, err := newProgramABIFromFd(bpfFd)
|
info, err := bpfGetProgInfoByFD(bpfFd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bpfFd.Forget()
|
bpfFd.forget()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newProgram(bpfFd, name, abi), nil
|
var name string
|
||||||
|
if bpfName := convertCString(info.name[:]); bpfName != "" {
|
||||||
|
name = bpfName
|
||||||
|
} else {
|
||||||
|
name = convertCString(info.tag[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return newProgram(bpfFd, name, newProgramABIFromInfo(info)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProgram(fd *internal.FD, name string, abi *ProgramABI) *Program {
|
func newProgram(fd *bpfFD, name string, abi *ProgramABI) *Program {
|
||||||
return &Program{
|
return &Program{
|
||||||
name: name,
|
name: name,
|
||||||
fd: fd,
|
fd: fd,
|
||||||
@ -172,7 +169,7 @@ func newProgram(fd *internal.FD, name string, abi *ProgramABI) *Program {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr, error) {
|
func convertProgramSpec(spec *ProgramSpec, includeName bool) (*bpfProgLoadAttr, error) {
|
||||||
if len(spec.Instructions) == 0 {
|
if len(spec.Instructions) == 0 {
|
||||||
return nil, errors.New("Instructions cannot be empty")
|
return nil, errors.New("Instructions cannot be empty")
|
||||||
}
|
}
|
||||||
@ -189,12 +186,13 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
|
|||||||
|
|
||||||
bytecode := buf.Bytes()
|
bytecode := buf.Bytes()
|
||||||
insCount := uint32(len(bytecode) / asm.InstructionSize)
|
insCount := uint32(len(bytecode) / asm.InstructionSize)
|
||||||
|
lic := []byte(spec.License)
|
||||||
attr := &bpfProgLoadAttr{
|
attr := &bpfProgLoadAttr{
|
||||||
progType: spec.Type,
|
progType: spec.Type,
|
||||||
expectedAttachType: spec.AttachType,
|
expectedAttachType: spec.AttachType,
|
||||||
insCount: insCount,
|
insCount: insCount,
|
||||||
instructions: internal.NewSlicePointer(bytecode),
|
instructions: newPtr(unsafe.Pointer(&bytecode[0])),
|
||||||
license: internal.NewStringPointer(spec.License),
|
license: newPtr(unsafe.Pointer(&lic[0])),
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := newBPFObjName(spec.Name)
|
name, err := newBPFObjName(spec.Name)
|
||||||
@ -202,38 +200,18 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if haveObjName() == nil {
|
if includeName {
|
||||||
attr.progName = name
|
attr.progName = name
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil && spec.BTF != nil {
|
|
||||||
attr.progBTFFd = uint32(handle.FD())
|
|
||||||
|
|
||||||
recSize, bytes, err := btf.ProgramLineInfos(spec.BTF)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get BTF line infos")
|
|
||||||
}
|
|
||||||
attr.lineInfoRecSize = recSize
|
|
||||||
attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
|
|
||||||
attr.lineInfo = internal.NewSlicePointer(bytes)
|
|
||||||
|
|
||||||
recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "can't get BTF function infos")
|
|
||||||
}
|
|
||||||
attr.funcInfoRecSize = recSize
|
|
||||||
attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
|
|
||||||
attr.funcInfo = internal.NewSlicePointer(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return attr, nil
|
return attr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) String() string {
|
func (p *Program) String() string {
|
||||||
if p.name != "" {
|
if p.name != "" {
|
||||||
return fmt.Sprintf("%s(%s)#%v", p.abi.Type, p.name, p.fd)
|
return fmt.Sprintf("%s(%s)#%s", p.abi.Type, p.name, p.fd)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s#%v", p.abi.Type, p.fd)
|
return fmt.Sprintf("%s#%s", p.abi.Type, p.fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABI gets the ABI of the Program
|
// ABI gets the ABI of the Program
|
||||||
@ -245,7 +223,7 @@ func (p *Program) ABI() ProgramABI {
|
|||||||
//
|
//
|
||||||
// It is invalid to call this function after Close has been called.
|
// It is invalid to call this function after Close has been called.
|
||||||
func (p *Program) FD() int {
|
func (p *Program) FD() int {
|
||||||
fd, err := p.fd.Value()
|
fd, err := p.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Best effort: -1 is the number most likely to be an
|
// Best effort: -1 is the number most likely to be an
|
||||||
// invalid file descriptor.
|
// invalid file descriptor.
|
||||||
@ -265,7 +243,7 @@ func (p *Program) Clone() (*Program, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dup, err := p.fd.Dup()
|
dup, err := p.fd.dup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "can't clone program")
|
return nil, errors.Wrap(err, "can't clone program")
|
||||||
}
|
}
|
||||||
@ -286,7 +264,7 @@ func (p *Program) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.fd.Close()
|
return p.fd.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test runs the Program in the kernel with the given input and returns the
|
// Test runs the Program in the kernel with the given input and returns the
|
||||||
@ -298,7 +276,7 @@ func (p *Program) Close() error {
|
|||||||
// This function requires at least Linux 4.12.
|
// This function requires at least Linux 4.12.
|
||||||
func (p *Program) Test(in []byte) (uint32, []byte, error) {
|
func (p *Program) Test(in []byte) (uint32, []byte, error) {
|
||||||
ret, out, _, err := p.testRun(in, 1)
|
ret, out, _, err := p.testRun(in, 1)
|
||||||
return ret, out, errors.Wrap(err, "can't test program")
|
return ret, out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmark runs the Program with the given input for a number of times
|
// Benchmark runs the Program with the given input for a number of times
|
||||||
@ -310,43 +288,42 @@ func (p *Program) Test(in []byte) (uint32, []byte, error) {
|
|||||||
// This function requires at least Linux 4.12.
|
// This function requires at least Linux 4.12.
|
||||||
func (p *Program) Benchmark(in []byte, repeat int) (uint32, time.Duration, error) {
|
func (p *Program) Benchmark(in []byte, repeat int) (uint32, time.Duration, error) {
|
||||||
ret, _, total, err := p.testRun(in, repeat)
|
ret, _, total, err := p.testRun(in, repeat)
|
||||||
return ret, total, errors.Wrap(err, "can't benchmark program")
|
return ret, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() bool {
|
var noProgTestRun = featureTest{
|
||||||
prog, err := NewProgram(&ProgramSpec{
|
Fn: func() bool {
|
||||||
Type: SocketFilter,
|
prog, err := NewProgram(&ProgramSpec{
|
||||||
Instructions: asm.Instructions{
|
Type: SocketFilter,
|
||||||
asm.LoadImm(asm.R0, 0, asm.DWord),
|
Instructions: asm.Instructions{
|
||||||
asm.Return(),
|
asm.LoadImm(asm.R0, 0, asm.DWord),
|
||||||
},
|
asm.Return(),
|
||||||
License: "MIT",
|
},
|
||||||
})
|
License: "MIT",
|
||||||
if err != nil {
|
})
|
||||||
// This may be because we lack sufficient permissions, etc.
|
if err != nil {
|
||||||
return false
|
// This may be because we lack sufficient permissions, etc.
|
||||||
}
|
return false
|
||||||
defer prog.Close()
|
}
|
||||||
|
defer prog.Close()
|
||||||
|
|
||||||
fd, err := prog.fd.Value()
|
fd, err := prog.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Programs require at least 14 bytes input
|
// Programs require at least 14 bytes input
|
||||||
in := make([]byte, 14)
|
in := make([]byte, 14)
|
||||||
attr := bpfProgTestRunAttr{
|
attr := bpfProgTestRunAttr{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
dataSizeIn: uint32(len(in)),
|
dataSizeIn: uint32(len(in)),
|
||||||
dataIn: internal.NewSlicePointer(in),
|
dataIn: newPtr(unsafe.Pointer(&in[0])),
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
|
return errors.Cause(err) == unix.EINVAL
|
||||||
// Check for EINVAL specifically, rather than err != nil since we
|
},
|
||||||
// otherwise misdetect due to insufficient permissions.
|
}
|
||||||
return errors.Cause(err) != unix.EINVAL
|
|
||||||
})
|
|
||||||
|
|
||||||
func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, error) {
|
func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, error) {
|
||||||
if uint(repeat) > math.MaxUint32 {
|
if uint(repeat) > math.MaxUint32 {
|
||||||
@ -361,8 +338,8 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration,
|
|||||||
return 0, nil, 0, fmt.Errorf("input is too long")
|
return 0, nil, 0, fmt.Errorf("input is too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := haveProgTestRun(); err != nil {
|
if noProgTestRun.Result() {
|
||||||
return 0, nil, 0, err
|
return 0, nil, 0, errNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Older kernels ignore the dataSizeOut argument when copying to user space.
|
// Older kernels ignore the dataSizeOut argument when copying to user space.
|
||||||
@ -372,7 +349,7 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration,
|
|||||||
// See https://patchwork.ozlabs.org/cover/1006822/
|
// See https://patchwork.ozlabs.org/cover/1006822/
|
||||||
out := make([]byte, len(in)+outputPad)
|
out := make([]byte, len(in)+outputPad)
|
||||||
|
|
||||||
fd, err := p.fd.Value()
|
fd, err := p.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, 0, err
|
return 0, nil, 0, err
|
||||||
}
|
}
|
||||||
@ -381,12 +358,12 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration,
|
|||||||
fd: fd,
|
fd: fd,
|
||||||
dataSizeIn: uint32(len(in)),
|
dataSizeIn: uint32(len(in)),
|
||||||
dataSizeOut: uint32(len(out)),
|
dataSizeOut: uint32(len(out)),
|
||||||
dataIn: internal.NewSlicePointer(in),
|
dataIn: newPtr(unsafe.Pointer(&in[0])),
|
||||||
dataOut: internal.NewSlicePointer(out),
|
dataOut: newPtr(unsafe.Pointer(&out[0])),
|
||||||
repeat: uint32(repeat),
|
repeat: uint32(repeat),
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, 0, errors.Wrap(err, "can't run test")
|
return 0, nil, 0, errors.Wrap(err, "can't run test")
|
||||||
}
|
}
|
||||||
@ -415,18 +392,18 @@ func unmarshalProgram(buf []byte) (*Program, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
name, abi, err := newProgramABIFromFd(fd)
|
abi, err := newProgramABIFromFd(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fd.Close()
|
_ = fd.close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newProgram(fd, name, abi), nil
|
return newProgram(fd, "", abi), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalBinary implements BinaryMarshaler.
|
// MarshalBinary implements BinaryMarshaler.
|
||||||
func (p *Program) MarshalBinary() ([]byte, error) {
|
func (p *Program) MarshalBinary() ([]byte, error) {
|
||||||
value, err := p.fd.Value()
|
value, err := p.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -442,7 +419,7 @@ func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
|
|||||||
return errors.New("invalid fd")
|
return errors.New("invalid fd")
|
||||||
}
|
}
|
||||||
|
|
||||||
pfd, err := p.fd.Value()
|
pfd, err := p.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -463,7 +440,7 @@ func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
|
|||||||
return errors.New("invalid fd")
|
return errors.New("invalid fd")
|
||||||
}
|
}
|
||||||
|
|
||||||
pfd, err := p.fd.Value()
|
pfd, err := p.fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -480,20 +457,31 @@ func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
|
|||||||
|
|
||||||
// LoadPinnedProgram loads a Program from a BPF file.
|
// LoadPinnedProgram loads a Program from a BPF file.
|
||||||
//
|
//
|
||||||
// Requires at least Linux 4.11.
|
// Requires at least Linux 4.13, use LoadPinnedProgramExplicit on
|
||||||
|
// earlier versions.
|
||||||
func LoadPinnedProgram(fileName string) (*Program, error) {
|
func LoadPinnedProgram(fileName string) (*Program, error) {
|
||||||
fd, err := bpfGetObject(fileName)
|
fd, err := bpfGetObject(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
name, abi, err := newProgramABIFromFd(fd)
|
abi, err := newProgramABIFromFd(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fd.Close()
|
_ = fd.close()
|
||||||
return nil, errors.Wrapf(err, "can't get ABI for %s", fileName)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newProgram(fd, name, abi), nil
|
return newProgram(fd, filepath.Base(fileName), abi), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPinnedProgramExplicit loads a program with explicit parameters.
|
||||||
|
func LoadPinnedProgramExplicit(fileName string, abi *ProgramABI) (*Program, error) {
|
||||||
|
fd, err := bpfGetObject(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newProgram(fd, filepath.Base(fileName), abi), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SanitizeName replaces all invalid characters in name.
|
// SanitizeName replaces all invalid characters in name.
|
||||||
@ -512,9 +500,24 @@ func SanitizeName(name string, replacement rune) string {
|
|||||||
}, name)
|
}, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type loadError struct {
|
||||||
|
cause error
|
||||||
|
verifierLog string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (le *loadError) Error() string {
|
||||||
|
if le.verifierLog == "" {
|
||||||
|
return fmt.Sprintf("failed to load program: %s", le.cause)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("failed to load program: %s: %s", le.cause, le.verifierLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (le *loadError) Cause() error {
|
||||||
|
return le.cause
|
||||||
|
}
|
||||||
|
|
||||||
// IsNotSupported returns true if an error occurred because
|
// IsNotSupported returns true if an error occurred because
|
||||||
// the kernel does not have support for a specific feature.
|
// the kernel does not have support for a specific feature.
|
||||||
func IsNotSupported(err error) bool {
|
func IsNotSupported(err error) bool {
|
||||||
_, notSupported := errors.Cause(err).(*internal.UnsupportedFeatureError)
|
return errors.Cause(err) == errNotSupported
|
||||||
return notSupported
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// +build armbe mips mips64p32
|
// +build armbe mips mips64p32
|
||||||
|
|
||||||
package internal
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pointer wraps an unsafe.Pointer to be 64bit to
|
// ptr wraps an unsafe.Pointer to be 64bit to
|
||||||
// conform to the syscall specification.
|
// conform to the syscall specification.
|
||||||
type Pointer struct {
|
type syscallPtr struct {
|
||||||
pad uint32
|
pad uint32
|
||||||
ptr unsafe.Pointer
|
ptr unsafe.Pointer
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
// +build 386 amd64p32 arm mipsle mips64p32le
|
// +build 386 amd64p32 arm mipsle mips64p32le
|
||||||
|
|
||||||
package internal
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pointer wraps an unsafe.Pointer to be 64bit to
|
// ptr wraps an unsafe.Pointer to be 64bit to
|
||||||
// conform to the syscall specification.
|
// conform to the syscall specification.
|
||||||
type Pointer struct {
|
type syscallPtr struct {
|
||||||
ptr unsafe.Pointer
|
ptr unsafe.Pointer
|
||||||
pad uint32
|
pad uint32
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le
|
// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le
|
||||||
// +build !armbe,!mips,!mips64p32
|
// +build !armbe,!mips,!mips64p32
|
||||||
|
|
||||||
package internal
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pointer wraps an unsafe.Pointer to be 64bit to
|
// ptr wraps an unsafe.Pointer to be 64bit to
|
||||||
// conform to the syscall specification.
|
// conform to the syscall specification.
|
||||||
type Pointer struct {
|
type syscallPtr struct {
|
||||||
ptr unsafe.Pointer
|
ptr unsafe.Pointer
|
||||||
}
|
}
|
13
vendor/github.com/cilium/ebpf/run-tests.sh
generated
vendored
13
vendor/github.com/cilium/ebpf/run-tests.sh
generated
vendored
@ -12,13 +12,10 @@ if [[ "${1:-}" = "--in-vm" ]]; then
|
|||||||
|
|
||||||
mount -t bpf bpf /sys/fs/bpf
|
mount -t bpf bpf /sys/fs/bpf
|
||||||
export CGO_ENABLED=0
|
export CGO_ENABLED=0
|
||||||
export GOFLAGS=-mod=readonly
|
|
||||||
export GOPROXY=file:///run/go-proxy
|
|
||||||
export GOCACHE=/run/go-cache
|
|
||||||
export HOME="$home"
|
export HOME="$home"
|
||||||
|
|
||||||
echo Running tests...
|
echo Running tests...
|
||||||
/usr/local/bin/go test -coverprofile="$1/coverage.txt" -covermode=atomic -v ./...
|
/usr/local/bin/go test -mod=vendor -coverprofile="$1/coverage.txt" -covermode=atomic -v ./...
|
||||||
touch "$1/success"
|
touch "$1/success"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@ -28,7 +25,7 @@ export GO111MODULE=on
|
|||||||
|
|
||||||
# Pull all dependencies, so that we can run tests without the
|
# Pull all dependencies, so that we can run tests without the
|
||||||
# vm having network access.
|
# vm having network access.
|
||||||
go mod download
|
go mod vendor
|
||||||
|
|
||||||
# Use sudo if /dev/kvm isn't accessible by the current user.
|
# Use sudo if /dev/kvm isn't accessible by the current user.
|
||||||
sudo=""
|
sudo=""
|
||||||
@ -53,11 +50,7 @@ test -e "${tmp_dir}/${kernel}" || {
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo Testing on ${kernel_version}
|
echo Testing on ${kernel_version}
|
||||||
$sudo virtme-run --kimg "${tmp_dir}/${kernel}" --memory 256M --pwd \
|
$sudo virtme-run --kimg "${tmp_dir}/${kernel}" --memory 256M --pwd --rwdir=/run/output="${output}" --script-sh "$(realpath "$0") --in-vm /run/output"
|
||||||
--rwdir=/run/output="${output}" \
|
|
||||||
--rodir=/run/go-proxy="$(go env GOPATH)/pkg/mod/cache/download" \
|
|
||||||
--rwdir=/run/go-cache="$(go env GOCACHE)" \
|
|
||||||
--script-sh "$(realpath "$0") --in-vm /run/output" --qemu-opts -smp 2
|
|
||||||
|
|
||||||
if [[ ! -e "${output}/success" ]]; then
|
if [[ ! -e "${output}/success" ]]; then
|
||||||
echo "Test failed on ${kernel_version}"
|
echo "Test failed on ${kernel_version}"
|
||||||
|
302
vendor/github.com/cilium/ebpf/syscalls.go
generated
vendored
302
vendor/github.com/cilium/ebpf/syscalls.go
generated
vendored
@ -1,17 +1,71 @@
|
|||||||
package ebpf
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal"
|
|
||||||
"github.com/cilium/ebpf/internal/btf"
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errClosedFd = errors.New("use of closed file descriptor")
|
||||||
|
|
||||||
|
type bpfFD struct {
|
||||||
|
raw int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBPFFD(value uint32) *bpfFD {
|
||||||
|
fd := &bpfFD{int64(value)}
|
||||||
|
runtime.SetFinalizer(fd, (*bpfFD).close)
|
||||||
|
return fd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *bpfFD) String() string {
|
||||||
|
return strconv.FormatInt(fd.raw, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *bpfFD) value() (uint32, error) {
|
||||||
|
if fd.raw < 0 {
|
||||||
|
return 0, errClosedFd
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(fd.raw), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *bpfFD) close() error {
|
||||||
|
if fd.raw < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
value := int(fd.raw)
|
||||||
|
fd.raw = -1
|
||||||
|
|
||||||
|
fd.forget()
|
||||||
|
return unix.Close(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *bpfFD) forget() {
|
||||||
|
runtime.SetFinalizer(fd, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *bpfFD) dup() (*bpfFD, error) {
|
||||||
|
if fd.raw < 0 {
|
||||||
|
return nil, errClosedFd
|
||||||
|
}
|
||||||
|
|
||||||
|
dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "can't dup fd")
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBPFFD(uint32(dup)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// bpfObjName is a null-terminated string made up of
|
// bpfObjName is a null-terminated string made up of
|
||||||
// 'A-Za-z0-9_' characters.
|
// 'A-Za-z0-9_' characters.
|
||||||
type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte
|
type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte
|
||||||
@ -44,25 +98,21 @@ func invalidBPFObjNameChar(char rune) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type bpfMapCreateAttr struct {
|
type bpfMapCreateAttr struct {
|
||||||
mapType MapType
|
mapType MapType
|
||||||
keySize uint32
|
keySize uint32
|
||||||
valueSize uint32
|
valueSize uint32
|
||||||
maxEntries uint32
|
maxEntries uint32
|
||||||
flags uint32
|
flags uint32
|
||||||
innerMapFd uint32 // since 4.12 56f668dfe00d
|
innerMapFd uint32 // since 4.12 56f668dfe00d
|
||||||
numaNode uint32 // since 4.14 96eabe7a40aa
|
numaNode uint32 // since 4.14 96eabe7a40aa
|
||||||
mapName bpfObjName // since 4.15 ad5b177bd73f
|
mapName bpfObjName // since 4.15 ad5b177bd73f
|
||||||
mapIfIndex uint32
|
|
||||||
btfFd uint32
|
|
||||||
btfKeyTypeID btf.TypeID
|
|
||||||
btfValueTypeID btf.TypeID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type bpfMapOpAttr struct {
|
type bpfMapOpAttr struct {
|
||||||
mapFd uint32
|
mapFd uint32
|
||||||
padding uint32
|
padding uint32
|
||||||
key internal.Pointer
|
key syscallPtr
|
||||||
value internal.Pointer
|
value syscallPtr
|
||||||
flags uint64
|
flags uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +127,7 @@ type bpfMapInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type bpfPinObjAttr struct {
|
type bpfPinObjAttr struct {
|
||||||
fileName internal.Pointer
|
fileName syscallPtr
|
||||||
fd uint32
|
fd uint32
|
||||||
padding uint32
|
padding uint32
|
||||||
}
|
}
|
||||||
@ -85,23 +135,16 @@ type bpfPinObjAttr struct {
|
|||||||
type bpfProgLoadAttr struct {
|
type bpfProgLoadAttr struct {
|
||||||
progType ProgramType
|
progType ProgramType
|
||||||
insCount uint32
|
insCount uint32
|
||||||
instructions internal.Pointer
|
instructions syscallPtr
|
||||||
license internal.Pointer
|
license syscallPtr
|
||||||
logLevel uint32
|
logLevel uint32
|
||||||
logSize uint32
|
logSize uint32
|
||||||
logBuf internal.Pointer
|
logBuf syscallPtr
|
||||||
kernelVersion uint32 // since 4.1 2541517c32be
|
kernelVersion uint32 // since 4.1 2541517c32be
|
||||||
progFlags uint32 // since 4.11 e07b98d9bffe
|
progFlags uint32 // since 4.11 e07b98d9bffe
|
||||||
progName bpfObjName // since 4.15 067cae47771c
|
progName bpfObjName // since 4.15 067cae47771c
|
||||||
progIfIndex uint32 // since 4.15 1f6f4cb7ba21
|
progIfIndex uint32 // since 4.15 1f6f4cb7ba21
|
||||||
expectedAttachType AttachType // since 4.17 5e43f899b03a
|
expectedAttachType AttachType // since 4.17 5e43f899b03a
|
||||||
progBTFFd uint32
|
|
||||||
funcInfoRecSize uint32
|
|
||||||
funcInfo internal.Pointer
|
|
||||||
funcInfoCnt uint32
|
|
||||||
lineInfoRecSize uint32
|
|
||||||
lineInfo internal.Pointer
|
|
||||||
lineInfoCnt uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type bpfProgInfo struct {
|
type bpfProgInfo struct {
|
||||||
@ -110,12 +153,12 @@ type bpfProgInfo struct {
|
|||||||
tag [unix.BPF_TAG_SIZE]byte
|
tag [unix.BPF_TAG_SIZE]byte
|
||||||
jitedLen uint32
|
jitedLen uint32
|
||||||
xlatedLen uint32
|
xlatedLen uint32
|
||||||
jited internal.Pointer
|
jited syscallPtr
|
||||||
xlated internal.Pointer
|
xlated syscallPtr
|
||||||
loadTime uint64 // since 4.15 cb4d2b3f03d8
|
loadTime uint64 // since 4.15 cb4d2b3f03d8
|
||||||
createdByUID uint32
|
createdByUID uint32
|
||||||
nrMapIDs uint32
|
nrMapIDs uint32
|
||||||
mapIds internal.Pointer
|
mapIds syscallPtr
|
||||||
name bpfObjName
|
name bpfObjName
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +167,8 @@ type bpfProgTestRunAttr struct {
|
|||||||
retval uint32
|
retval uint32
|
||||||
dataSizeIn uint32
|
dataSizeIn uint32
|
||||||
dataSizeOut uint32
|
dataSizeOut uint32
|
||||||
dataIn internal.Pointer
|
dataIn syscallPtr
|
||||||
dataOut internal.Pointer
|
dataOut syscallPtr
|
||||||
repeat uint32
|
repeat uint32
|
||||||
duration uint32
|
duration uint32
|
||||||
}
|
}
|
||||||
@ -140,7 +183,7 @@ type bpfProgAlterAttr struct {
|
|||||||
type bpfObjGetInfoByFDAttr struct {
|
type bpfObjGetInfoByFDAttr struct {
|
||||||
fd uint32
|
fd uint32
|
||||||
infoLen uint32
|
infoLen uint32
|
||||||
info internal.Pointer // May be either bpfMapInfo or bpfProgInfo
|
info syscallPtr // May be either bpfMapInfo or bpfProgInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type bpfGetFDByIDAttr struct {
|
type bpfGetFDByIDAttr struct {
|
||||||
@ -148,9 +191,13 @@ type bpfGetFDByIDAttr struct {
|
|||||||
next uint32
|
next uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) {
|
func newPtr(ptr unsafe.Pointer) syscallPtr {
|
||||||
|
return syscallPtr{ptr: ptr}
|
||||||
|
}
|
||||||
|
|
||||||
|
func bpfProgLoad(attr *bpfProgLoadAttr) (*bpfFD, error) {
|
||||||
for {
|
for {
|
||||||
fd, err := internal.BPF(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
fd, err := bpfCall(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||||
// As of ~4.20 the verifier can be interrupted by a signal,
|
// As of ~4.20 the verifier can be interrupted by a signal,
|
||||||
// and returns EAGAIN in that case.
|
// and returns EAGAIN in that case.
|
||||||
if err == unix.EAGAIN {
|
if err == unix.EAGAIN {
|
||||||
@ -161,54 +208,26 @@ func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return internal.NewFD(uint32(fd)), nil
|
return newBPFFD(uint32(fd)), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfProgAlter(cmd int, attr *bpfProgAlterAttr) error {
|
func bpfProgAlter(cmd int, attr *bpfProgAlterAttr) error {
|
||||||
_, err := internal.BPF(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
_, err := bpfCall(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) {
|
func bpfMapCreate(attr *bpfMapCreateAttr) (*bpfFD, error) {
|
||||||
fd, err := internal.BPF(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
fd, err := bpfCall(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return internal.NewFD(uint32(fd)), nil
|
return newBPFFD(uint32(fd)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool {
|
func bpfMapLookupElem(m *bpfFD, key, valueOut syscallPtr) error {
|
||||||
inner, err := bpfMapCreate(&bpfMapCreateAttr{
|
fd, err := m.value()
|
||||||
mapType: Array,
|
|
||||||
keySize: 4,
|
|
||||||
valueSize: 4,
|
|
||||||
maxEntries: 1,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defer inner.Close()
|
|
||||||
|
|
||||||
innerFd, _ := inner.Value()
|
|
||||||
nested, err := bpfMapCreate(&bpfMapCreateAttr{
|
|
||||||
mapType: ArrayOfMaps,
|
|
||||||
keySize: 4,
|
|
||||||
valueSize: 4,
|
|
||||||
maxEntries: 1,
|
|
||||||
innerMapFd: innerFd,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = nested.Close()
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error {
|
|
||||||
fd, err := m.Value()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -218,27 +237,12 @@ func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error {
|
|||||||
key: key,
|
key: key,
|
||||||
value: valueOut,
|
value: valueOut,
|
||||||
}
|
}
|
||||||
_, err = internal.BPF(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error {
|
func bpfMapUpdateElem(m *bpfFD, key, valueOut syscallPtr, flags uint64) error {
|
||||||
fd, err := m.Value()
|
fd, err := m.value()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
attr := bpfMapOpAttr{
|
|
||||||
mapFd: fd,
|
|
||||||
key: key,
|
|
||||||
value: valueOut,
|
|
||||||
}
|
|
||||||
_, err = internal.BPF(_MapLookupAndDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint64) error {
|
|
||||||
fd, err := m.Value()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -249,12 +253,12 @@ func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint
|
|||||||
value: valueOut,
|
value: valueOut,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
}
|
}
|
||||||
_, err = internal.BPF(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error {
|
func bpfMapDeleteElem(m *bpfFD, key syscallPtr) error {
|
||||||
fd, err := m.Value()
|
fd, err := m.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -263,12 +267,12 @@ func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error {
|
|||||||
mapFd: fd,
|
mapFd: fd,
|
||||||
key: key,
|
key: key,
|
||||||
}
|
}
|
||||||
_, err = internal.BPF(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error {
|
func bpfMapGetNextKey(m *bpfFD, key, nextKeyOut syscallPtr) error {
|
||||||
fd, err := m.Value()
|
fd, err := m.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -278,13 +282,13 @@ func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error {
|
|||||||
key: key,
|
key: key,
|
||||||
value: nextKeyOut,
|
value: nextKeyOut,
|
||||||
}
|
}
|
||||||
_, err = internal.BPF(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const bpfFSType = 0xcafe4a11
|
const bpfFSType = 0xcafe4a11
|
||||||
|
|
||||||
func bpfPinObject(fileName string, fd *internal.FD) error {
|
func bpfPinObject(fileName string, fd *bpfFD) error {
|
||||||
dirName := filepath.Dir(fileName)
|
dirName := filepath.Dir(fileName)
|
||||||
var statfs unix.Statfs_t
|
var statfs unix.Statfs_t
|
||||||
if err := unix.Statfs(dirName, &statfs); err != nil {
|
if err := unix.Statfs(dirName, &statfs); err != nil {
|
||||||
@ -294,30 +298,30 @@ func bpfPinObject(fileName string, fd *internal.FD) error {
|
|||||||
return errors.Errorf("%s is not on a bpf filesystem", fileName)
|
return errors.Errorf("%s is not on a bpf filesystem", fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
value, err := fd.Value()
|
value, err := fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = internal.BPF(_ObjPin, unsafe.Pointer(&bpfPinObjAttr{
|
_, err = bpfCall(_ObjPin, unsafe.Pointer(&bpfPinObjAttr{
|
||||||
fileName: internal.NewStringPointer(fileName),
|
fileName: newPtr(unsafe.Pointer(&[]byte(fileName)[0])),
|
||||||
fd: value,
|
fd: value,
|
||||||
}), 16)
|
}), 16)
|
||||||
return errors.Wrapf(err, "pin object %s", fileName)
|
return errors.Wrapf(err, "pin object %s", fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfGetObject(fileName string) (*internal.FD, error) {
|
func bpfGetObject(fileName string) (*bpfFD, error) {
|
||||||
ptr, err := internal.BPF(_ObjGet, unsafe.Pointer(&bpfPinObjAttr{
|
ptr, err := bpfCall(_ObjGet, unsafe.Pointer(&bpfPinObjAttr{
|
||||||
fileName: internal.NewStringPointer(fileName),
|
fileName: newPtr(unsafe.Pointer(&[]byte(fileName)[0])),
|
||||||
}), 16)
|
}), 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "get object %s", fileName)
|
return nil, errors.Wrapf(err, "get object %s", fileName)
|
||||||
}
|
}
|
||||||
return internal.NewFD(uint32(ptr)), nil
|
return newBPFFD(uint32(ptr)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) error {
|
func bpfGetObjectInfoByFD(fd *bpfFD, info unsafe.Pointer, size uintptr) error {
|
||||||
value, err := fd.Value()
|
value, err := fd.value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -326,69 +330,91 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er
|
|||||||
attr := bpfObjGetInfoByFDAttr{
|
attr := bpfObjGetInfoByFDAttr{
|
||||||
fd: value,
|
fd: value,
|
||||||
infoLen: uint32(size),
|
infoLen: uint32(size),
|
||||||
info: internal.NewPointer(info),
|
info: newPtr(info),
|
||||||
}
|
}
|
||||||
_, err = internal.BPF(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
_, err = bpfCall(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
return errors.Wrapf(err, "fd %d", fd)
|
return errors.Wrapf(err, "fd %d", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) {
|
func bpfGetProgInfoByFD(fd *bpfFD) (*bpfProgInfo, error) {
|
||||||
var info bpfProgInfo
|
var info bpfProgInfo
|
||||||
err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
|
err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
|
||||||
return &info, errors.Wrap(err, "can't get program info")
|
return &info, errors.Wrap(err, "can't get program info")
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) {
|
func bpfGetMapInfoByFD(fd *bpfFD) (*bpfMapInfo, error) {
|
||||||
var info bpfMapInfo
|
var info bpfMapInfo
|
||||||
err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
|
err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
|
||||||
return &info, errors.Wrap(err, "can't get map info")
|
return &info, errors.Wrap(err, "can't get map info:")
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveObjName = internal.FeatureTest("object names", "4.15", func() bool {
|
var haveObjName = featureTest{
|
||||||
name, err := newBPFObjName("feature_test")
|
Fn: func() bool {
|
||||||
if err != nil {
|
name, err := newBPFObjName("feature_test")
|
||||||
// This really is a fatal error, but it should be caught
|
if err != nil {
|
||||||
// by the unit tests not working.
|
// This really is a fatal error, but it should be caught
|
||||||
return false
|
// by the unit tests not working.
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
attr := bpfMapCreateAttr{
|
attr := bpfMapCreateAttr{
|
||||||
mapType: Array,
|
mapType: Array,
|
||||||
keySize: 4,
|
keySize: 4,
|
||||||
valueSize: 4,
|
valueSize: 4,
|
||||||
maxEntries: 1,
|
maxEntries: 1,
|
||||||
mapName: name,
|
mapName: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := bpfMapCreate(&attr)
|
fd, err := bpfMapCreate(&attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = fd.Close()
|
_ = fd.close()
|
||||||
return true
|
return true
|
||||||
})
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func bpfGetMapFDByID(id uint32) (*internal.FD, error) {
|
func bpfGetMapFDByID(id uint32) (*bpfFD, error) {
|
||||||
// available from 4.13
|
// available from 4.13
|
||||||
attr := bpfGetFDByIDAttr{
|
attr := bpfGetFDByIDAttr{
|
||||||
id: id,
|
id: id,
|
||||||
}
|
}
|
||||||
ptr, err := internal.BPF(_MapGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
ptr, err := bpfCall(_MapGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "can't get fd for map id %d", id)
|
return nil, errors.Wrapf(err, "can't get fd for map id %d", id)
|
||||||
}
|
}
|
||||||
return internal.NewFD(uint32(ptr)), nil
|
return newBPFFD(uint32(ptr)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bpfGetProgramFDByID(id uint32) (*internal.FD, error) {
|
func bpfGetProgramFDByID(id uint32) (*bpfFD, error) {
|
||||||
// available from 4.13
|
// available from 4.13
|
||||||
attr := bpfGetFDByIDAttr{
|
attr := bpfGetFDByIDAttr{
|
||||||
id: id,
|
id: id,
|
||||||
}
|
}
|
||||||
ptr, err := internal.BPF(_ProgGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
ptr, err := bpfCall(_ProgGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "can't get fd for program id %d", id)
|
return nil, errors.Wrapf(err, "can't get fd for program id %d", id)
|
||||||
}
|
}
|
||||||
return internal.NewFD(uint32(ptr)), nil
|
return newBPFFD(uint32(ptr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bpfCall(cmd int, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCString(in []byte) string {
|
||||||
|
inLen := bytes.IndexByte(in, 0)
|
||||||
|
if inLen == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(in[:inLen])
|
||||||
}
|
}
|
||||||
|
36
vendor/github.com/cilium/ebpf/types.go
generated
vendored
36
vendor/github.com/cilium/ebpf/types.go
generated
vendored
@ -57,30 +57,6 @@ const (
|
|||||||
// HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps
|
// HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps
|
||||||
// itself.
|
// itself.
|
||||||
HashOfMaps
|
HashOfMaps
|
||||||
// DevMap - Specialized map to store references to network devices.
|
|
||||||
DevMap
|
|
||||||
// SockMap - Specialized map to store references to sockets.
|
|
||||||
SockMap
|
|
||||||
// CPUMap - Specialized map to store references to CPUs.
|
|
||||||
CPUMap
|
|
||||||
// XSKMap - Specialized map for XDP programs to store references to open sockets.
|
|
||||||
XSKMap
|
|
||||||
// SockHash - Specialized hash to store references to sockets.
|
|
||||||
SockHash
|
|
||||||
// CGroupStorage - Special map for CGroups.
|
|
||||||
CGroupStorage
|
|
||||||
// ReusePortSockArray - Specialized map to store references to sockets that can be reused.
|
|
||||||
ReusePortSockArray
|
|
||||||
// PerCPUCGroupStorage - Special per CPU map for CGroups.
|
|
||||||
PerCPUCGroupStorage
|
|
||||||
// Queue - FIFO storage for BPF programs.
|
|
||||||
Queue
|
|
||||||
// Stack - LIFO storage for BPF programs.
|
|
||||||
Stack
|
|
||||||
// SkStorage - Specialized map for local storage at SK for BPF programs.
|
|
||||||
SkStorage
|
|
||||||
// DevMapHash - Hash-based indexing scheme for references to network devices.
|
|
||||||
DevMapHash
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// hasPerCPUValue returns true if the Map stores a value per CPU.
|
// hasPerCPUValue returns true if the Map stores a value per CPU.
|
||||||
@ -108,13 +84,6 @@ const (
|
|||||||
_ProgGetFDByID
|
_ProgGetFDByID
|
||||||
_MapGetFDByID
|
_MapGetFDByID
|
||||||
_ObjGetInfoByFD
|
_ObjGetInfoByFD
|
||||||
_ProgQuery
|
|
||||||
_RawTracepointOpen
|
|
||||||
_BTFLoad
|
|
||||||
_BTFGetFDByID
|
|
||||||
_TaskFDQuery
|
|
||||||
_MapLookupAndDeleteElem
|
|
||||||
_MapFreeze
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -180,8 +149,6 @@ const (
|
|||||||
RawTracepointWritable
|
RawTracepointWritable
|
||||||
// CGroupSockopt program
|
// CGroupSockopt program
|
||||||
CGroupSockopt
|
CGroupSockopt
|
||||||
// Tracing program
|
|
||||||
Tracing
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AttachType of the eBPF program, needed to differentiate allowed context accesses in
|
// AttachType of the eBPF program, needed to differentiate allowed context accesses in
|
||||||
@ -216,9 +183,6 @@ const (
|
|||||||
AttachCGroupUDP6Recvmsg
|
AttachCGroupUDP6Recvmsg
|
||||||
AttachCGroupGetsockopt
|
AttachCGroupGetsockopt
|
||||||
AttachCGroupSetsockopt
|
AttachCGroupSetsockopt
|
||||||
AttachTraceRawTp
|
|
||||||
AttachTraceFEntry
|
|
||||||
AttachTraceFExit
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
|
// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
|
||||||
|
21
vendor/github.com/cilium/ebpf/types_string.go
generated
vendored
21
vendor/github.com/cilium/ebpf/types_string.go
generated
vendored
@ -22,23 +22,11 @@ func _() {
|
|||||||
_ = x[LPMTrie-11]
|
_ = x[LPMTrie-11]
|
||||||
_ = x[ArrayOfMaps-12]
|
_ = x[ArrayOfMaps-12]
|
||||||
_ = x[HashOfMaps-13]
|
_ = x[HashOfMaps-13]
|
||||||
_ = x[DevMap-14]
|
|
||||||
_ = x[SockMap-15]
|
|
||||||
_ = x[CPUMap-16]
|
|
||||||
_ = x[XSKMap-17]
|
|
||||||
_ = x[SockHash-18]
|
|
||||||
_ = x[CGroupStorage-19]
|
|
||||||
_ = x[ReusePortSockArray-20]
|
|
||||||
_ = x[PerCPUCGroupStorage-21]
|
|
||||||
_ = x[Queue-22]
|
|
||||||
_ = x[Stack-23]
|
|
||||||
_ = x[SkStorage-24]
|
|
||||||
_ = x[DevMapHash-25]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHash"
|
const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMaps"
|
||||||
|
|
||||||
var _MapType_index = [...]uint8{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248}
|
var _MapType_index = [...]uint8{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136}
|
||||||
|
|
||||||
func (i MapType) String() string {
|
func (i MapType) String() string {
|
||||||
if i >= MapType(len(_MapType_index)-1) {
|
if i >= MapType(len(_MapType_index)-1) {
|
||||||
@ -76,12 +64,11 @@ func _() {
|
|||||||
_ = x[CGroupSysctl-23]
|
_ = x[CGroupSysctl-23]
|
||||||
_ = x[RawTracepointWritable-24]
|
_ = x[RawTracepointWritable-24]
|
||||||
_ = x[CGroupSockopt-25]
|
_ = x[CGroupSockopt-25]
|
||||||
_ = x[Tracing-26]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracing"
|
const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockopt"
|
||||||
|
|
||||||
var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265}
|
var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258}
|
||||||
|
|
||||||
func (i ProgramType) String() string {
|
func (i ProgramType) String() string {
|
||||||
if i >= ProgramType(len(_ProgramType_index)-1) {
|
if i >= ProgramType(len(_ProgramType_index)-1) {
|
||||||
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -155,11 +155,10 @@ github.com/chai2010/gettext-go/gettext/plural
|
|||||||
github.com/chai2010/gettext-go/gettext/po
|
github.com/chai2010/gettext-go/gettext/po
|
||||||
# github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 => github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48
|
# github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 => github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48
|
||||||
github.com/checkpoint-restore/go-criu/rpc
|
github.com/checkpoint-restore/go-criu/rpc
|
||||||
# github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3 => github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3
|
# github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed => github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed
|
||||||
github.com/cilium/ebpf
|
github.com/cilium/ebpf
|
||||||
github.com/cilium/ebpf/asm
|
github.com/cilium/ebpf/asm
|
||||||
github.com/cilium/ebpf/internal
|
github.com/cilium/ebpf/internal
|
||||||
github.com/cilium/ebpf/internal/btf
|
|
||||||
github.com/cilium/ebpf/internal/unix
|
github.com/cilium/ebpf/internal/unix
|
||||||
# github.com/client9/misspell v0.3.4 => github.com/client9/misspell v0.3.4
|
# github.com/client9/misspell v0.3.4 => github.com/client9/misspell v0.3.4
|
||||||
github.com/client9/misspell
|
github.com/client9/misspell
|
||||||
|
Loading…
Reference in New Issue
Block a user