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

     1  package emulator
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/dylandreimerink/gobpfld/bpfsys"
     7  	"github.com/dylandreimerink/gobpfld/ebpf"
     8  )
     9  
    10  // PerfEventArray is the emulated implementation of BPF_MAP_TYPE_PERF_EVENT_ARRAY. In linux this is a pseudo map type
    11  // which is not actually a map, rater a way to one-way data stream using the perf sub system. The userspace program
    12  // would have to consume data while it is being produced or risk losing data if the buffer is full.
    13  //
    14  // This emulated map type has to be consumed by the caller of virtual machine, the event data is stored in a slice
    15  // which is currently unlimited in size, it can be read and consumed just like an array map.
    16  type PerfEventArray struct {
    17  	AbstractMap
    18  
    19  	Events [][]byte
    20  }
    21  
    22  func (m *PerfEventArray) Init() error {
    23  	return nil
    24  }
    25  
    26  func (m *PerfEventArray) Keys() []RegisterValue {
    27  	keys := make([]RegisterValue, len(m.Events))
    28  	for i := range keys {
    29  		imm := newIMM(int64(i))
    30  		keys[i] = &MemoryPtr{
    31  			Memory: &ValueMemory{
    32  				MemName: fmt.Sprintf("%s[%d]", m.Name, m.Def.ValueSize),
    33  				Mapping: []RegisterValue{
    34  					imm,
    35  					imm,
    36  					imm,
    37  					imm,
    38  				},
    39  			},
    40  		}
    41  	}
    42  	return keys
    43  }
    44  
    45  func (m *PerfEventArray) Lookup(key RegisterValue) (RegisterValue, error) {
    46  	keyPtr, ok := key.(PointerValue)
    47  	if !ok {
    48  		return nil, errMapKeyNoPtr
    49  	}
    50  
    51  	keyValReg, err := keyPtr.Deref(0, ebpf.BPF_W)
    52  	if !ok {
    53  		return nil, fmt.Errorf("key pointer deref: %w", err)
    54  	}
    55  
    56  	kv := keyValReg.Value()
    57  	if int(kv) >= len(m.Events) {
    58  		return newIMM(0), nil
    59  	}
    60  
    61  	return &MemoryPtr{Memory: &ByteMemory{
    62  		MemName: fmt.Sprintf("%s[%d]", m.Name, kv),
    63  		Backing: m.Events[kv],
    64  	}, Offset: 0}, nil
    65  }
    66  
    67  func (m *PerfEventArray) Update(
    68  	key RegisterValue,
    69  	value RegisterValue,
    70  	flags bpfsys.BPFAttrMapElemFlags,
    71  ) (
    72  	RegisterValue,
    73  	error,
    74  ) {
    75  	// Not allowed to update values, since this kind of map is a sort of stream, not an actual map
    76  	return nil, errMapNotImplemented
    77  }
    78  
    79  func (m *PerfEventArray) Delete(key RegisterValue, flags bpfsys.BPFAttrMapElemFlags) error {
    80  	keyPtr, ok := key.(PointerValue)
    81  	if !ok {
    82  		return errMapKeyNoPtr
    83  	}
    84  
    85  	keyValReg, err := keyPtr.Deref(0, ebpf.BPF_W)
    86  	if !ok {
    87  		return fmt.Errorf("key pointer deref: %w", err)
    88  	}
    89  
    90  	kv := keyValReg.Value()
    91  	if int(kv) >= len(m.Events) {
    92  		return nil
    93  	}
    94  
    95  	copy(m.Events[kv:], m.Events[kv+1:])
    96  	m.Events = m.Events[:len(m.Events)-1]
    97  
    98  	return nil
    99  }
   100  
   101  func (m *PerfEventArray) Push(value RegisterValue, size int64) error {
   102  	valuePtr, ok := value.(PointerValue)
   103  	if !ok {
   104  		return errMapKeyNoPtr
   105  	}
   106  
   107  	val, err := valuePtr.ReadRange(0, int(size))
   108  	if !ok {
   109  		return fmt.Errorf("value pointer read range: %w", err)
   110  	}
   111  
   112  	m.Events = append(m.Events, val)
   113  
   114  	return nil
   115  }