mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
184 lines
4.0 KiB
Go
184 lines
4.0 KiB
Go
|
package ebpf
|
||
|
|
||
|
import (
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
// 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 MapType
|
||
|
KeySize uint32
|
||
|
ValueSize uint32
|
||
|
MaxEntries uint32
|
||
|
InnerMap *MapABI
|
||
|
}
|
||
|
|
||
|
func newMapABIFromSpec(spec *MapSpec) *MapABI {
|
||
|
var inner *MapABI
|
||
|
if spec.InnerMap != nil {
|
||
|
inner = newMapABIFromSpec(spec.InnerMap)
|
||
|
}
|
||
|
|
||
|
return &MapABI{
|
||
|
spec.Type,
|
||
|
spec.KeySize,
|
||
|
spec.ValueSize,
|
||
|
spec.MaxEntries,
|
||
|
inner,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func newMapABIFromFd(fd *bpfFD) (*MapABI, error) {
|
||
|
info, err := bpfGetMapInfoByFD(fd)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
mapType := MapType(info.mapType)
|
||
|
if mapType == ArrayOfMaps || mapType == HashOfMaps {
|
||
|
return nil, errors.New("can't get map info for nested maps")
|
||
|
}
|
||
|
|
||
|
return &MapABI{
|
||
|
mapType,
|
||
|
info.keySize,
|
||
|
info.valueSize,
|
||
|
info.maxEntries,
|
||
|
nil,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// 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 ProgramType
|
||
|
}
|
||
|
|
||
|
func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI {
|
||
|
return &ProgramABI{
|
||
|
spec.Type,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func newProgramABIFromFd(fd *bpfFD) (*ProgramABI, error) {
|
||
|
info, err := bpfGetProgInfoByFD(fd)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return newProgramABIFromInfo(info), nil
|
||
|
}
|
||
|
|
||
|
func newProgramABIFromInfo(info *bpfProgInfo) *ProgramABI {
|
||
|
return &ProgramABI{
|
||
|
Type: ProgramType(info.progType),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check verifies that a Program conforms to the ABI.
|
||
|
//
|
||
|
// Members which have the zero value of their type
|
||
|
// are not checked.
|
||
|
func (abi *ProgramABI) Check(prog *Program) error {
|
||
|
if abi.Type != UnspecifiedProgram && prog.abi.Type != abi.Type {
|
||
|
return errors.Errorf("expected program type %s, have %s", abi.Type, prog.abi.Type)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func checkUint32(name string, want, have uint32) error {
|
||
|
if want != 0 && have != want {
|
||
|
return errors.Errorf("expected %s to be %d, have %d", name, want, have)
|
||
|
}
|
||
|
return nil
|
||
|
}
|