github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/emulator/maps.go (about)

     1  package emulator
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/dylandreimerink/gobpfld"
     8  	"github.com/dylandreimerink/gobpfld/bpfsys"
     9  	"github.com/dylandreimerink/gobpfld/bpftypes"
    10  )
    11  
    12  // Map represents an emulated eBPF map
    13  type Map interface {
    14  	Init() error
    15  
    16  	GetName() string
    17  
    18  	GetDef() gobpfld.BPFMapDef
    19  	GetType() gobpfld.BTFMap
    20  
    21  	// Keys returns all keys contained in the map
    22  	Keys() []RegisterValue
    23  
    24  	// Lookup looks up a value in the map for a given key and return a pointer to the value or NULL/0 if it can't find
    25  	// it.
    26  	Lookup(key RegisterValue) (RegisterValue, error)
    27  
    28  	// Update sets or updates a map with value at the given key, it returns 0 on success or a negative value
    29  	// on error.
    30  	Update(key RegisterValue, value RegisterValue, flags bpfsys.BPFAttrMapElemFlags) (RegisterValue, error)
    31  
    32  	// Delete deletes the value at the given key from the map
    33  	Delete(key RegisterValue, flags bpfsys.BPFAttrMapElemFlags) error
    34  
    35  	// Push pushes/enqueues values into maps which are not keyed like perf_arrays, ringbuffers, stacks and queues
    36  	Push(value RegisterValue, size int64) error
    37  
    38  	// Pop pops/dequeues values from maps which are not keyed like perf_arrays, ringbuffers, stacks and queues.
    39  	// This action removed the value from the map (like a lookup+delete)
    40  	Pop() (RegisterValue, error)
    41  }
    42  
    43  type AbstractMap struct {
    44  	Name    string
    45  	Def     gobpfld.BPFMapDef
    46  	BTFType gobpfld.BTFMap
    47  }
    48  
    49  func (m *AbstractMap) GetName() string {
    50  	return m.Name
    51  }
    52  
    53  func (m *AbstractMap) GetDef() gobpfld.BPFMapDef {
    54  	return m.Def
    55  }
    56  
    57  func (m *AbstractMap) GetType() gobpfld.BTFMap {
    58  	return m.BTFType
    59  }
    60  
    61  func (m *AbstractMap) Update(
    62  	key RegisterValue,
    63  	value RegisterValue,
    64  	flags bpfsys.BPFAttrMapElemFlags,
    65  ) (
    66  	RegisterValue,
    67  	error,
    68  ) {
    69  	return nil, errors.New("update not available on this map type")
    70  }
    71  
    72  func (m *AbstractMap) Delete(key RegisterValue, flags bpfsys.BPFAttrMapElemFlags) error {
    73  	return errors.New("delete not available on this map type")
    74  }
    75  
    76  func (m *AbstractMap) Push(value RegisterValue, size int64) error {
    77  	return errors.New("push not available on this map type")
    78  }
    79  
    80  func (m *AbstractMap) Pop() (RegisterValue, error) {
    81  	return nil, errors.New("pop not available on this map type")
    82  }
    83  
    84  // AbstractMapToVM converts an AbstractMap to an emulated version
    85  func AbstractMapToVM(am gobpfld.AbstractMap) (Map, error) {
    86  	eam := AbstractMap{
    87  		Name:    am.Name.String(),
    88  		Def:     am.Definition,
    89  		BTFType: am.BTFMapType,
    90  	}
    91  
    92  	switch am.Definition.Type {
    93  	case bpftypes.BPF_MAP_TYPE_HASH, bpftypes.BPF_MAP_TYPE_PERCPU_HASH:
    94  		// NOTE since the emulator currently only support single threading, a per-cpu map is effectively the same
    95  		// as a normal map. As soon as we want to support parallel execution, we should add an actual separate
    96  		// type
    97  		return &HashMap{
    98  			AbstractMap: eam,
    99  		}, nil
   100  
   101  	case bpftypes.BPF_MAP_TYPE_ARRAY, bpftypes.BPF_MAP_TYPE_PERCPU_ARRAY:
   102  		// NOTE since the emulator currently only support single threading, a per-cpu map is effectively the same
   103  		// as a normal map. As soon as we want to support parallel execution, we should add an actual separate
   104  		// type
   105  		return &ArrayMap{
   106  			AbstractMap: eam,
   107  			InitialData: am.InitialData,
   108  		}, nil
   109  
   110  	case bpftypes.BPF_MAP_TYPE_PROG_ARRAY:
   111  		// In linux this needs to be a special map type because it holds addresses to programs, but in the emulator
   112  		// we can just insert the program indexes, so it is effectively a normal array map with an int32 value
   113  		return &ArrayMap{
   114  			AbstractMap: eam,
   115  		}, nil
   116  
   117  	case bpftypes.BPF_MAP_TYPE_PERF_EVENT_ARRAY:
   118  		return &PerfEventArray{
   119  			AbstractMap: eam,
   120  		}, nil
   121  
   122  	case bpftypes.BPF_MAP_TYPE_LRU_HASH, bpftypes.BPF_MAP_TYPE_LRU_PERCPU_HASH:
   123  		// NOTE since the emulator currently only support single threading, a per-cpu map is effectively the same
   124  		// as a normal map. As soon as we want to support parallel execution, we should add an actual separate
   125  		// type
   126  		return &HashMapLRU{
   127  			AbstractMap: eam,
   128  		}, nil
   129  
   130  	case bpftypes.BPF_MAP_TYPE_ARRAY_OF_MAPS:
   131  		// In linux this needs to be a special may type because it holds addresses to maps, but in the emulator
   132  		// we can just insert the map indexes, so it is effectively a normal array map with a int32 value
   133  		return &ArrayMap{
   134  			AbstractMap: eam,
   135  		}, nil
   136  
   137  	case bpftypes.BPF_MAP_TYPE_HASH_OF_MAPS:
   138  		// In linux this needs to be a special may type because it holds addresses to maps, but in the emulator
   139  		// we can just insert the map indexes, so it is effectively a normal hash map with a int32 value
   140  		return &HashMap{
   141  			AbstractMap: eam,
   142  		}, nil
   143  
   144  	case bpftypes.BPF_MAP_TYPE_STACK:
   145  		return &StackMap{
   146  			AbstractMap: eam,
   147  		}, nil
   148  
   149  	case bpftypes.BPF_MAP_TYPE_QUEUE:
   150  		return &QueueMap{
   151  			AbstractMap: eam,
   152  		}, nil
   153  	}
   154  
   155  	return nil, fmt.Errorf("map type '%s' not yet implemented", am.Definition.Type)
   156  }
   157  
   158  var (
   159  	errMapNotImplemented = errors.New("feature is not implemented on this map type")
   160  	errMapKeyNoPtr       = errors.New("key is not a pointer")
   161  	errMapValNoPtr       = errors.New("value is not a pointer")
   162  	errMapOutOfMemory    = errors.New("map is full or access outside of bounds")
   163  )