func()

in pkg/events/ringbuffer.go [63:105]


func (r *RingBuffer) ParseRingData(consumerPosition uint64) *RingData {
	updateConsumerPosition := (uintptr(consumerPosition) & uintptr(r.Mask))
	data := (*int32)(unsafe.Pointer(uintptr(r.Data) + updateConsumerPosition))

	// Single record will have [header,payload] and header maintains [len, pgoff]
	// len field in the header, is the u32 data len but kernel overloads this field with busy and discard bit
	// BPF_RINGBUF_BUSY_BIT		= (1U << 31)
	// BPF_RINGBUF_DISCARD_BIT	= (1U << 30) [Ref kernel bpf.h]
	// If busy bit is set we skip read i.e, not update consumer position and re-read during next poll
	// if Discard bit is set we just update consumer position but not read the record.
	// We fetch 32 bits value from the data pointer which is the start of the record.
	entryLen := atomic.LoadInt32(data)

	// entryLen now is the "len" in ringbuf Header struct.
	// But this is overloaded with busy and discard bit so skip it to get actual data/record length
	strippedDataLen := ((uint32(entryLen) << 2) >> 2)

	// recordLen will include actual data/record length + header length
	recordLen := (strippedDataLen + uint32(ringbufHeaderSize))

	// round up recordLen to nearest 8-byte alignment which will be the offset for next record start position
	// ref to __bpf_ringbuf_reserve
	// https://github.com/torvalds/linux/blob/master/kernel/bpf/ringbuf.c#L418
	roundedEntryLen := (recordLen + 7) &^ 7

	ringdata := &RingData{
		Data:      data,
		Len:       uint32(entryLen),
		DataLen:   uint32(strippedDataLen),
		RecordLen: uint32(roundedEntryLen),
	}

	// Check if busy bit is set
	if (ringdata.Len & unix.BPF_RINGBUF_BUSY_BIT) != 0 {
		ringdata.BusyRecord = true
	}

	// Check if record has to be discarded
	if (ringdata.Len & unix.BPF_RINGBUF_DISCARD_BIT) != 0 {
		ringdata.DiscardRecord = true
	}
	return ringdata
}