package gobpfld import ( "fmt" "github.com/dylandreimerink/gobpfld/bpfsys" "github.com/dylandreimerink/gobpfld/kernelsupport" ) var _ BPFMap = (*HashMap)(nil) // HashMap is a generic map type, both the key and value may be of any type. The value of the key is hashed so values // do not need to be contiguous. type HashMap struct { AbstractMap } func (m *HashMap) Load() error { // NOTE: do not enforce definition type of map since hash map is currently still a catch all map type err := m.load(nil) if err != nil { return err } err = mapRegister.add(m) if err != nil { return fmt.Errorf("map register: %w", err) } return nil } // Close closes the file descriptor associate with the map, this will cause the map to unload from the kernel // if it is not still in use by a eBPF program, bpf FS, or a userspace program still holding a fd to the map. func (m *HashMap) Close() error { err := mapRegister.delete(m) if err != nil { return fmt.Errorf("map register: %w", err) } return m.close() } func (m *HashMap) Get(key interface{}, value interface{}) error { return m.get(key, value) } // GetBatch fills the keys and values array/slice with the keys and values inside the map up to a maximum of // maxBatchSize entries. The keys and values array/slice must have at least a length of maxBatchSize. // The key and value of an entry is has the same index, so for example the value for keys[2] is in values[2]. // Count is the amount of entries returns, partial is true if not all elements of keys and values could be set. // // This function is intended for small maps which can be read into userspace all at once since // GetBatch can only read from the beginning of the map. If the map is to large to read all at once // a iterator should be used instead of the Get or GetBatch function. func (m *HashMap) GetBatch( keys interface{}, values interface{}, maxBatchSize uint32, ) ( count int, partial bool, err error, ) { return m.getBatch(keys, values, maxBatchSize) } func (m *HashMap) Set(key interface{}, value interface{}, flags bpfsys.BPFAttrMapElemFlags) error { return m.set(key, value, flags) } func (m *HashMap) SetBatch( keys interface{}, values interface{}, flags bpfsys.BPFAttrMapElemFlags, maxBatchSize uint32, ) ( count int, err error, ) { return m.setBatch(keys, values, flags, maxBatchSize) } func (m *HashMap) Delete(key interface{}) error { return m.delete(key) } func (m *HashMap) DeleteBatch( keys interface{}, maxBatchSize uint32, ) ( count int, err error, ) { return m.deleteBatch(keys, maxBatchSize) } func (m *HashMap) GetAndDelete(key interface{}, value interface{}) error { return m.getAndDelete(key, value) } func (m *HashMap) GetAndDeleteBatch( keys interface{}, values interface{}, maxBatchSize uint32, ) ( count int, err error, ) { return m.getAndDeleteBatch(keys, values, maxBatchSize) } func (m *HashMap) Iterator() MapIterator { // If the kernel doesn't have support for batch lookup, use single lookup if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBatchOps) { return &singleLookupIterator{ BPFMap: m, } } // TODO change batch lookup iterator to support per-cpu values if m.isPerCPUMap() { return &singleLookupIterator{ BPFMap: m, } } // If there is no reason not to use the batch lookup iterator, use it return &batchLookupIterator{ BPFMap: m, } }