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 )