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

     1  package emulator
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/dylandreimerink/gobpfld/bpfsys"
     9  	"github.com/dylandreimerink/gobpfld/ebpf"
    10  )
    11  
    12  type ArrayMap struct {
    13  	AbstractMap
    14  	Memory        ByteMemory
    15  	InitialDataBO binary.ByteOrder
    16  	InitialData   map[interface{}]interface{}
    17  }
    18  
    19  func (m *ArrayMap) Init() error {
    20  	m.Memory = ByteMemory{
    21  		MemName: m.Name,
    22  		Backing: make([]byte, m.Def.ValueSize*m.Def.MaxEntries),
    23  	}
    24  
    25  	if m.InitialData != nil {
    26  		m.Memory.ByteOrder = m.InitialDataBO
    27  
    28  		for k, v := range m.InitialData {
    29  			keyInt, ok := k.(int)
    30  			if !ok {
    31  				return fmt.Errorf("the key type of the initial data must be an int")
    32  			}
    33  
    34  			vSlice, ok := v.([]byte)
    35  			if !ok {
    36  				return fmt.Errorf("the value type of the initial data must be an []byte")
    37  			}
    38  
    39  			copy(m.Memory.Backing[keyInt*int(m.Def.ValueSize):], vSlice)
    40  		}
    41  	}
    42  
    43  	return nil
    44  }
    45  
    46  func (m *ArrayMap) Keys() []RegisterValue {
    47  	keys := make([]RegisterValue, m.Def.MaxEntries)
    48  	for i := range keys {
    49  		imm := newIMM(int64(i))
    50  		keys[i] = &MemoryPtr{
    51  			Memory: &ValueMemory{
    52  				MemName: fmt.Sprintf("%s[%d]", m.Name, m.Def.ValueSize),
    53  				Mapping: []RegisterValue{
    54  					imm,
    55  					imm,
    56  					imm,
    57  					imm,
    58  				},
    59  			},
    60  		}
    61  	}
    62  	return keys
    63  }
    64  
    65  func (m *ArrayMap) Lookup(key RegisterValue) (RegisterValue, error) {
    66  	keyPtr, ok := key.(PointerValue)
    67  	if !ok {
    68  		return nil, errMapKeyNoPtr
    69  	}
    70  
    71  	keyValReg, err := keyPtr.Deref(0, ebpf.BPF_W)
    72  	if !ok {
    73  		return nil, fmt.Errorf("key pointer deref: %w", err)
    74  	}
    75  
    76  	kv := keyValReg.Value()
    77  	off := kv * int64(m.Def.ValueSize)
    78  
    79  	// Outside of map
    80  	if off >= int64(m.Memory.Size()) {
    81  		// Return NULL if key out of bounds
    82  		// https://elixir.bootlin.com/linux/v5.16.4/source/kernel/bpf/arraymap.c#L164
    83  		return newIMM(0), nil
    84  	}
    85  
    86  	return &MemoryPtr{Memory: &m.Memory, Offset: off}, nil
    87  }
    88  
    89  func (m *ArrayMap) Update(
    90  	key RegisterValue,
    91  	value RegisterValue,
    92  	flags bpfsys.BPFAttrMapElemFlags,
    93  ) (
    94  	RegisterValue,
    95  	error,
    96  ) {
    97  	vPtr, ok := value.(*MemoryPtr)
    98  	if !ok {
    99  		return nil, errMapValNoPtr
   100  	}
   101  
   102  	keyPtr, ok := key.(*MemoryPtr)
   103  	if !ok {
   104  		return nil, errMapValNoPtr
   105  	}
   106  
   107  	keyVar, err := keyPtr.Deref(0, ebpf.BPF_W)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	kv := keyVar.Value()
   113  	// Outside of map
   114  	if kv >= int64(m.Memory.Size()) {
   115  		return nil, errMapOutOfMemory
   116  	}
   117  
   118  	for i := 0; i < int(m.Def.ValueSize); i++ {
   119  		v, err := vPtr.Memory.Read(i, ebpf.BPF_B)
   120  		if err != nil {
   121  			return nil, fmt.Errorf("memory read: %w", err)
   122  		}
   123  
   124  		err = m.Memory.Write(int(kv*int64(m.Def.ValueSize))+i, v, ebpf.BPF_B)
   125  		if err != nil {
   126  			return nil, fmt.Errorf("memory write: %w", err)
   127  		}
   128  	}
   129  
   130  	return newIMM(0), nil
   131  }
   132  
   133  func (m *ArrayMap) Delete(key RegisterValue, flags bpfsys.BPFAttrMapElemFlags) error {
   134  	return errors.New("not yet implemented")
   135  }