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

     1  package emulator
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/hex"
     6  	"fmt"
     7  
     8  	"github.com/dylandreimerink/gobpfld/bpfsys"
     9  )
    10  
    11  type HashMap struct {
    12  	AbstractMap
    13  
    14  	// Go can't use slices as map values, so what we do is we sha256 hash the slice which always results in a
    15  	// uniform sized array which we can use as key. Since we now don't index by the actual key, we also need to
    16  	// store the actual key value so we can return k/v pairs
    17  
    18  	KeysMap map[[sha256.Size]byte]*ByteMemory
    19  	Values  map[[sha256.Size]byte]*ByteMemory
    20  }
    21  
    22  func (m *HashMap) Init() error {
    23  	m.KeysMap = make(map[[sha256.Size]byte]*ByteMemory)
    24  	m.Values = make(map[[sha256.Size]byte]*ByteMemory)
    25  
    26  	// NOTE: we always ignore the BPFMapFlagsNoPreAlloc flag since we never pre-alloc, it is an optimization which
    27  	// we don't need for the current purposes of the emulator.
    28  
    29  	return nil
    30  }
    31  
    32  func (m *HashMap) Keys() []RegisterValue {
    33  	keys := make([]RegisterValue, len(m.KeysMap))
    34  	i := 0
    35  	for _, val := range m.KeysMap {
    36  		keys[i] = &MemoryPtr{
    37  			Memory: val.Clone(), // Clone since we don't want to give access to a modifyable reference
    38  		}
    39  		i++
    40  	}
    41  	return keys
    42  }
    43  
    44  func (m *HashMap) Lookup(key RegisterValue) (RegisterValue, error) {
    45  	keyPtr, ok := key.(PointerValue)
    46  	if !ok {
    47  		return nil, errMapKeyNoPtr
    48  	}
    49  
    50  	keyVal, err := keyPtr.ReadRange(0, int(m.Def.KeySize))
    51  	if !ok {
    52  		return nil, fmt.Errorf("key read range: %w", err)
    53  	}
    54  
    55  	keyHash := sha256.Sum256(keyVal)
    56  	value, found := m.Values[keyHash]
    57  	if !found {
    58  		// Return NULL if value doesn't exist
    59  		return newIMM(0), nil
    60  	}
    61  
    62  	return &MemoryPtr{Memory: value, Offset: 0}, nil
    63  }
    64  
    65  func (m *HashMap) Update(
    66  	key RegisterValue,
    67  	value RegisterValue,
    68  	flags bpfsys.BPFAttrMapElemFlags,
    69  ) (
    70  	RegisterValue,
    71  	error,
    72  ) {
    73  	keyPtr, ok := key.(PointerValue)
    74  	if !ok {
    75  		return nil, errMapKeyNoPtr
    76  	}
    77  
    78  	keyVal, err := keyPtr.ReadRange(0, int(m.Def.KeySize))
    79  	if !ok {
    80  		return nil, fmt.Errorf("key read range: %w", err)
    81  	}
    82  
    83  	keyHash := sha256.Sum256(keyVal)
    84  	existingValue, found := m.Values[keyHash]
    85  	if !found {
    86  		if len(m.Values)+1 > int(m.Def.MaxEntries) {
    87  			// Exceeding max map size
    88  			return nil, errMapOutOfMemory
    89  		}
    90  
    91  		existingValue = &ByteMemory{
    92  			MemName: fmt.Sprintf("%s[0x%s]", m.Name, hex.EncodeToString(keyVal)),
    93  			Backing: make([]byte, m.Def.ValueSize),
    94  		}
    95  	}
    96  	existingKey, found := m.KeysMap[keyHash]
    97  	if !found {
    98  		existingKey = &ByteMemory{
    99  			MemName: hex.EncodeToString(keyVal),
   100  			Backing: make([]byte, m.Def.KeySize),
   101  		}
   102  	}
   103  
   104  	valPtr, ok := value.(PointerValue)
   105  	if !ok {
   106  		return nil, errMapValNoPtr
   107  	}
   108  
   109  	valVal, err := valPtr.ReadRange(0, int(m.Def.ValueSize))
   110  	if !ok {
   111  		return nil, fmt.Errorf("val read range: %w", err)
   112  	}
   113  
   114  	// We can safely assing, valVal is otherwise unreferenced
   115  	existingValue.Backing = valVal
   116  	m.Values[keyHash] = existingValue
   117  
   118  	// We can safely assing, valVal is otherwise unreferenced
   119  	existingKey.Backing = keyVal
   120  	m.KeysMap[keyHash] = existingKey
   121  
   122  	return newIMM(0), nil
   123  }
   124  
   125  func (m *HashMap) Delete(key RegisterValue, flags bpfsys.BPFAttrMapElemFlags) error {
   126  	keyPtr, ok := key.(PointerValue)
   127  	if !ok {
   128  		return errMapKeyNoPtr
   129  	}
   130  
   131  	keyVal, err := keyPtr.ReadRange(0, int(m.Def.KeySize))
   132  	if !ok {
   133  		return fmt.Errorf("key read range: %w", err)
   134  	}
   135  	keyHash := sha256.Sum256(keyVal)
   136  
   137  	delete(m.KeysMap, keyHash)
   138  	delete(m.Values, keyHash)
   139  
   140  	return nil
   141  }