Pin dependency github.com/cilium/ebpf

Use same as opencontainers/runc
This commit is contained in:
Odin Ugedal 2020-01-24 13:13:44 +01:00
parent 088ee920e0
commit 5ba2a8da09
No known key found for this signature in database
GPG Key ID: AFF9C8242CF7A7AF
35 changed files with 600 additions and 2731 deletions

4
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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
View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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
View 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
}

View File

@ -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"],

View File

@ -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"],
)

View File

@ -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
})

View File

@ -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})
}
}

View File

@ -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

View File

@ -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,
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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])
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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])}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
View File

@ -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
} }

View File

@ -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
View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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}"

View File

@ -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])
} }

View File

@ -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

View File

@ -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
View File

@ -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