Skip to content

Value unmarshalling skipped for partial batch in BatchLookup #1741

@aibor

Description

@aibor

Describe the bug

If batchLookupCmd returns ErrKeyNotExist in batchLookup, the unmarshalling of valuesOut is skipped.

My expectation is that the unmarshalling of valuesOut is called for the last batch as well. Just like it happens for keysOut.

How to reproduce

The batch size should be chosen in a way so the last batch is less than batch size and ErrKeyNotExist is returned.

package ebpf_test

import (
	"errors"
	"testing"

	"github.com/cilium/ebpf"
)

var (
	keysMockCalled   int
	valuesMockCalled int
)

type keysMock []any

func (u keysMock) UnmarshalBinary(data []byte) error {
	keysMockCalled++
	return nil
}

type valuesMock []any

func (u valuesMock) UnmarshalBinary(data []byte) error {
	valuesMockCalled++
	return nil
}

func TestLastBatchUnmarshalValuesNotCalled(t *testing.T) {
	// Choose batch size in a way that last batch returns ErrKeyNotExist.
	var maxEntries, batchSize uint32 = 4, 3

	m, err := ebpf.NewMap(&ebpf.MapSpec{
		Type:       ebpf.Array,
		MaxEntries: maxEntries,
		KeySize:    4,
		ValueSize:  4,
	})
	if err != nil {
		t.Fatalf("create map: %v", err)
	}

	var (
		cursor    ebpf.MapBatchCursor
		keysOut   = make(keysMock, batchSize)
		valuesOut = make(valuesMock, batchSize)
	)

	_, err = m.BatchLookup(&cursor, keysOut, valuesOut, nil)
	if err != nil {
		t.Fatalf("first batch lookup failed: %v", err)
	}

	_, err = m.BatchLookup(&cursor, keysOut, valuesOut, nil)
	if !errors.Is(err, ebpf.ErrKeyNotExist) {
		t.Fatalf("second batch lookup must return ErrKeyNotExist, got %v", err)
	}

	if keysMockCalled != 2 {
		t.Errorf("keys mock calls: got %d, want %d", keysMockCalled, 2)
	}

	// This fails unexpectedly. It should be 2 (called for both batches), but
	// is 1 (not called for last batch).
	if valuesMockCalled != 2 {
		t.Errorf("values mock calls: got %d, want %d", valuesMockCalled, 2)
	}
}

This fails with:

=== RUN   TestLastBatchUnmarshalValuesNotCalled
    main_test.go:66: values mock calls: got 1, want 2
--- FAIL: TestLastBatchUnmarshalValuesNotCalled (0.00s)
FAIL

Version information

github.com/cilium/ebpf v0.18.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions