github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/map_percpu_array.go (about) 1 package gobpfld 2 3 import ( 4 "fmt" 5 6 "github.com/dylandreimerink/gobpfld/bpfsys" 7 "github.com/dylandreimerink/gobpfld/bpftypes" 8 "github.com/dylandreimerink/gobpfld/kernelsupport" 9 ) 10 11 var _ BPFMap = (*PerCPUArrayMap)(nil) 12 13 // PerCPUArrayMap is a map which has a integer key from 0 to MaxEntries. It is a generic map type so the value can be 14 // any type. This map type stores an array of values for each key, the size of the array is equal to the CPU count 15 // returned by the runtime.NumCPU() function. 16 type PerCPUArrayMap struct { 17 AbstractMap 18 } 19 20 func (m *PerCPUArrayMap) Load() error { 21 if m.Definition.Type != bpftypes.BPF_MAP_TYPE_PERCPU_ARRAY { 22 return fmt.Errorf("map type in definition must be BPF_MAP_TYPE_PERCPU_ARRAY when using an PerCPUArrayMap") 23 } 24 25 err := m.load(nil) 26 if err != nil { 27 return err 28 } 29 30 err = mapRegister.add(m) 31 if err != nil { 32 return fmt.Errorf("map register: %w", err) 33 } 34 35 return nil 36 } 37 38 // Close closes the file descriptor associate with the map, this will cause the map to unload from the kernel 39 // if it is not still in use by a eBPF program, bpf FS, or a userspace program still holding a fd to the map. 40 func (m *PerCPUArrayMap) Close() error { 41 err := mapRegister.delete(m) 42 if err != nil { 43 return fmt.Errorf("map register: %w", err) 44 } 45 46 return m.close() 47 } 48 49 func (m *PerCPUArrayMap) Get(key uint32, value interface{}) error { 50 return m.get(&key, value) 51 } 52 53 // GetBatch fills the keys slice and values array/slice with the keys and values inside the map. 54 // The keys slice and values array/slice must have the same length. The key and value of an entry is has the same 55 // index, so for example the value for keys[2] is in values[2]. Count is the amount of entries returns, 56 // partial is true if not all elements of keys and values could be set. 57 // 58 // This function is intended for small maps which can be read into userspace all at once since 59 // GetBatch can only read from the beginning of the map. If the map is to large to read all at once 60 // a iterator should be used instead of the Get or GetBatch function. 61 func (m *PerCPUArrayMap) GetBatch( 62 keys []uint32, 63 values interface{}, 64 ) ( 65 count int, 66 partial bool, 67 err error, 68 ) { 69 if !kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapPerCPUArrayBatchOps) { 70 return 0, 71 false, 72 fmt.Errorf("batch get operation not support on Per CPU array map type on current kernel version") 73 } 74 75 keysLen := len(keys) 76 77 // Very unlikely, but we have to check 78 if keysLen > maxUint32 { 79 return 0, false, fmt.Errorf("max len of 'keys' allowed is %d", maxUint32) 80 } 81 82 return m.getBatch(&keys, values, uint32(keysLen)) 83 } 84 85 func (m *PerCPUArrayMap) Set(key uint32, value interface{}, flags bpfsys.BPFAttrMapElemFlags) error { 86 return m.set(&key, value, flags) 87 } 88 89 func (m *PerCPUArrayMap) SetBatch( 90 keys []uint32, 91 values interface{}, 92 flags bpfsys.BPFAttrMapElemFlags, 93 ) ( 94 count int, 95 err error, 96 ) { 97 if !kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapPerCPUArrayBatchOps) { 98 return 0, fmt.Errorf("batch set operation not support on Per CPU array map type on current kernel version") 99 } 100 101 keysLen := len(keys) 102 103 // Very unlikely, but we have to check 104 if keysLen > maxUint32 { 105 return 0, fmt.Errorf("max len of 'keys' allowed is %d", maxUint32) 106 } 107 108 return m.setBatch(&keys, values, flags, uint32(keysLen)) 109 } 110 111 func (m *PerCPUArrayMap) Iterator() MapIterator { 112 // If the kernel doesn't have support for batch lookup, use single lookup 113 if !kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapPerCPUArrayBatchOps) { 114 return &singleLookupIterator{ 115 BPFMap: m, 116 } 117 } 118 119 // If there is no reason not to use the batch lookup iterator, use it 120 return &batchLookupIterator{ 121 BPFMap: m, 122 } 123 }