github.com/cilium/ebpf@v0.10.0/map_test.go (about)

     1  package ebpf
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"sort"
    11  	"testing"
    12  	"unsafe"
    13  
    14  	"github.com/cilium/ebpf/asm"
    15  	"github.com/cilium/ebpf/internal"
    16  	"github.com/cilium/ebpf/internal/sys"
    17  	"github.com/cilium/ebpf/internal/testutils"
    18  	"github.com/cilium/ebpf/internal/unix"
    19  
    20  	qt "github.com/frankban/quicktest"
    21  )
    22  
    23  var (
    24  	spec1 = &MapSpec{
    25  		Name:       "foo",
    26  		Type:       Hash,
    27  		KeySize:    4,
    28  		ValueSize:  4,
    29  		MaxEntries: 1,
    30  		Pinning:    PinByName,
    31  	}
    32  )
    33  
    34  func TestMap(t *testing.T) {
    35  	m := createArray(t)
    36  	defer m.Close()
    37  
    38  	t.Log(m)
    39  
    40  	if err := m.Put(uint32(0), uint32(42)); err != nil {
    41  		t.Fatal("Can't put:", err)
    42  	}
    43  	if err := m.Put(uint32(1), uint32(4242)); err != nil {
    44  		t.Fatal("Can't put:", err)
    45  	}
    46  
    47  	m2, err := m.Clone()
    48  	if err != nil {
    49  		t.Fatal("Can't clone map:", err)
    50  	}
    51  	defer m2.Close()
    52  
    53  	m.Close()
    54  	m = m2
    55  
    56  	var v uint32
    57  	if err := m.Lookup(uint32(0), &v); err != nil {
    58  		t.Fatal("Can't lookup 0:", err)
    59  	}
    60  	if v != 42 {
    61  		t.Error("Want value 42, got", v)
    62  	}
    63  
    64  	var k uint32
    65  	if err := m.NextKey(uint32(0), &k); err != nil {
    66  		t.Fatal("Can't get:", err)
    67  	}
    68  	if k != 1 {
    69  		t.Error("Want key 1, got", k)
    70  	}
    71  }
    72  
    73  func TestBatchAPIArray(t *testing.T) {
    74  	if err := haveBatchAPI(); err != nil {
    75  		t.Skipf("batch api not available: %v", err)
    76  	}
    77  	m, err := NewMap(&MapSpec{
    78  		Type:       Array,
    79  		KeySize:    4,
    80  		ValueSize:  4,
    81  		MaxEntries: 2,
    82  	})
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	defer m.Close()
    87  
    88  	var (
    89  		nextKey      uint32
    90  		keys         = []uint32{0, 1}
    91  		values       = []uint32{42, 4242}
    92  		lookupKeys   = make([]uint32, 2)
    93  		lookupValues = make([]uint32, 2)
    94  		deleteKeys   = make([]uint32, 2)
    95  		deleteValues = make([]uint32, 2)
    96  	)
    97  
    98  	count, err := m.BatchUpdate(keys, values, nil)
    99  	if err != nil {
   100  		t.Fatalf("BatchUpdate: %v", err)
   101  	}
   102  	if count != len(keys) {
   103  		t.Fatalf("BatchUpdate: expected count, %d, to be %d", count, len(keys))
   104  	}
   105  
   106  	var v uint32
   107  	if err := m.Lookup(uint32(0), &v); err != nil {
   108  		t.Fatal("Can't lookup 0:", err)
   109  	}
   110  	if v != 42 {
   111  		t.Error("Want value 42, got", v)
   112  	}
   113  
   114  	count, err = m.BatchLookup(nil, &nextKey, lookupKeys, lookupValues, nil)
   115  	if err != nil {
   116  		t.Fatalf("BatchLookup: %v", err)
   117  	}
   118  	if count != len(lookupKeys) {
   119  		t.Fatalf("BatchLookup: returned %d results, expected %d", count, len(lookupKeys))
   120  	}
   121  	if nextKey != lookupKeys[1] {
   122  		t.Fatalf("BatchLookup: expected nextKey, %d, to be the same as the lastKey returned, %d", nextKey, lookupKeys[1])
   123  	}
   124  	if !reflect.DeepEqual(keys, lookupKeys) {
   125  		t.Errorf("BatchUpdate and BatchLookup keys disagree: %v %v", keys, lookupKeys)
   126  	}
   127  	if !reflect.DeepEqual(values, lookupValues) {
   128  		t.Errorf("BatchUpdate and BatchLookup values disagree: %v %v", values, lookupValues)
   129  	}
   130  
   131  	_, err = m.BatchLookupAndDelete(nil, &nextKey, deleteKeys, deleteValues, nil)
   132  	if !errors.Is(err, ErrNotSupported) {
   133  		t.Fatalf("BatchLookUpDelete: expected error %v, but got %v", ErrNotSupported, err)
   134  	}
   135  }
   136  
   137  func TestBatchAPIHash(t *testing.T) {
   138  	if err := haveBatchAPI(); err != nil {
   139  		t.Skipf("batch api not available: %v", err)
   140  	}
   141  	m, err := NewMap(&MapSpec{
   142  		Type:       Hash,
   143  		KeySize:    4,
   144  		ValueSize:  4,
   145  		MaxEntries: 10,
   146  	})
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	defer m.Close()
   151  
   152  	var (
   153  		nextKey      uint32
   154  		keys         = []uint32{0, 1}
   155  		values       = []uint32{42, 4242}
   156  		lookupKeys   = make([]uint32, 2)
   157  		lookupValues = make([]uint32, 2)
   158  		deleteKeys   = make([]uint32, 2)
   159  		deleteValues = make([]uint32, 2)
   160  	)
   161  
   162  	count, err := m.BatchUpdate(keys, values, nil)
   163  	if err != nil {
   164  		t.Fatalf("BatchUpdate: %v", err)
   165  	}
   166  	if count != len(keys) {
   167  		t.Fatalf("BatchUpdate: expected count, %d, to be %d", count, len(keys))
   168  	}
   169  
   170  	var v uint32
   171  	if err := m.Lookup(uint32(0), &v); err != nil {
   172  		t.Fatal("Can't lookup 0:", err)
   173  	}
   174  	if v != 42 {
   175  		t.Error("Want value 42, got", v)
   176  	}
   177  
   178  	count, err = m.BatchLookup(nil, &nextKey, lookupKeys, lookupValues, nil)
   179  	if !errors.Is(err, ErrKeyNotExist) {
   180  		t.Fatalf("BatchLookup: expected %v got %v", ErrKeyNotExist, err)
   181  	}
   182  	if count != len(lookupKeys) {
   183  		t.Fatalf("BatchLookup: returned %d results, expected %d", count, len(lookupKeys))
   184  	}
   185  	sort.Slice(lookupKeys, func(i, j int) bool { return lookupKeys[i] < lookupKeys[j] })
   186  	if !reflect.DeepEqual(keys, lookupKeys) {
   187  		t.Errorf("BatchUpdate and BatchLookup keys disagree: %v %v", keys, lookupKeys)
   188  	}
   189  	sort.Slice(lookupValues, func(i, j int) bool { return lookupValues[i] < lookupValues[j] })
   190  	if !reflect.DeepEqual(values, lookupValues) {
   191  		t.Errorf("BatchUpdate and BatchLookup values disagree: %v %v", values, lookupValues)
   192  	}
   193  
   194  	count, err = m.BatchLookupAndDelete(nil, &nextKey, deleteKeys, deleteValues, nil)
   195  	if !errors.Is(err, ErrKeyNotExist) {
   196  		t.Fatalf("BatchLookupAndDelete: expected %v got %v", ErrKeyNotExist, err)
   197  	}
   198  	if count != len(deleteKeys) {
   199  		t.Fatalf("BatchLookupAndDelete: returned %d results, expected %d", count, len(deleteKeys))
   200  	}
   201  	sort.Slice(deleteKeys, func(i, j int) bool { return deleteKeys[i] < deleteKeys[j] })
   202  	if !reflect.DeepEqual(keys, deleteKeys) {
   203  		t.Errorf("BatchUpdate and BatchLookupAndDelete keys disagree: %v %v", keys, deleteKeys)
   204  	}
   205  	sort.Slice(deleteValues, func(i, j int) bool { return deleteValues[i] < deleteValues[j] })
   206  	if !reflect.DeepEqual(values, deleteValues) {
   207  		t.Errorf("BatchUpdate and BatchLookupAndDelete values disagree: %v %v", values, deleteValues)
   208  	}
   209  
   210  	if err := m.Lookup(uint32(0), &v); !errors.Is(err, ErrKeyNotExist) {
   211  		t.Fatalf("Lookup should have failed with error, %v, instead error is %v", ErrKeyNotExist, err)
   212  	}
   213  }
   214  
   215  func TestBatchAPIMapDelete(t *testing.T) {
   216  	if err := haveBatchAPI(); err != nil {
   217  		t.Skipf("batch api not available: %v", err)
   218  	}
   219  	m, err := NewMap(&MapSpec{
   220  		Type:       Hash,
   221  		KeySize:    4,
   222  		ValueSize:  4,
   223  		MaxEntries: 10,
   224  	})
   225  	if err != nil {
   226  		t.Fatal(err)
   227  	}
   228  	defer m.Close()
   229  
   230  	var (
   231  		keys   = []uint32{0, 1}
   232  		values = []uint32{42, 4242}
   233  	)
   234  
   235  	count, err := m.BatchUpdate(keys, values, nil)
   236  	if err != nil {
   237  		t.Fatalf("BatchUpdate: %v", err)
   238  	}
   239  	if count != len(keys) {
   240  		t.Fatalf("BatchUpdate: expected count, %d, to be %d", count, len(keys))
   241  	}
   242  
   243  	var v uint32
   244  	if err := m.Lookup(uint32(0), &v); err != nil {
   245  		t.Fatal("Can't lookup 0:", err)
   246  	}
   247  	if v != 42 {
   248  		t.Error("Want value 42, got", v)
   249  	}
   250  
   251  	count, err = m.BatchDelete(keys, nil)
   252  	if err != nil {
   253  		t.Fatalf("BatchDelete: %v", err)
   254  	}
   255  	if count != len(keys) {
   256  		t.Fatalf("BatchDelete: expected %d deletions got %d", len(keys), count)
   257  	}
   258  
   259  	if err := m.Lookup(uint32(0), &v); !errors.Is(err, ErrKeyNotExist) {
   260  		t.Fatalf("Lookup should have failed with error, %v, instead error is %v", ErrKeyNotExist, err)
   261  	}
   262  }
   263  
   264  func TestMapClose(t *testing.T) {
   265  	m := createArray(t)
   266  
   267  	if err := m.Close(); err != nil {
   268  		t.Fatal("Can't close map:", err)
   269  	}
   270  
   271  	if err := m.Put(uint32(0), uint32(42)); !errors.Is(err, sys.ErrClosedFd) {
   272  		t.Fatal("Put doesn't check for closed fd", err)
   273  	}
   274  
   275  	if _, err := m.LookupBytes(uint32(0)); !errors.Is(err, sys.ErrClosedFd) {
   276  		t.Fatal("Get doesn't check for closed fd", err)
   277  	}
   278  }
   279  
   280  func TestBatchMapWithLock(t *testing.T) {
   281  	testutils.SkipOnOldKernel(t, "5.13", "MAP BATCH BPF_F_LOCK")
   282  	testutils.Files(t, testutils.Glob(t, "./testdata/map_spin_lock-*.elf"), func(t *testing.T, file string) {
   283  		spec, err := LoadCollectionSpec(file)
   284  		if err != nil {
   285  			t.Fatal("Can't parse ELF:", err)
   286  		}
   287  		if spec.ByteOrder != internal.NativeEndian {
   288  			return
   289  		}
   290  
   291  		coll, err := NewCollection(spec)
   292  		if err != nil {
   293  			t.Fatal("Can't parse ELF:", err)
   294  		}
   295  		defer coll.Close()
   296  
   297  		type spinLockValue struct {
   298  			Cnt     uint32
   299  			Padding uint32
   300  		}
   301  
   302  		m, ok := coll.Maps["spin_lock_map"]
   303  		if !ok {
   304  			t.Fatal(err)
   305  		}
   306  
   307  		keys := []uint32{0, 1}
   308  		values := []spinLockValue{{Cnt: 42}, {Cnt: 4242}}
   309  		count, err := m.BatchUpdate(keys, values, &BatchOptions{ElemFlags: uint64(UpdateLock)})
   310  		if err != nil {
   311  			t.Fatalf("BatchUpdate: %v", err)
   312  		}
   313  		if count != len(keys) {
   314  			t.Fatalf("BatchUpdate: expected count, %d, to be %d", count, len(keys))
   315  		}
   316  
   317  		nextKey := uint32(0)
   318  		lookupKeys := make([]uint32, 2)
   319  		lookupValues := make([]spinLockValue, 2)
   320  		count, err = m.BatchLookup(nil, &nextKey, lookupKeys, lookupValues, &BatchOptions{ElemFlags: uint64(LookupLock)})
   321  		if !errors.Is(err, ErrKeyNotExist) {
   322  			t.Fatalf("BatchLookup: %v", err)
   323  		}
   324  		if count != 2 {
   325  			t.Fatalf("BatchLookup: expected two keys, got %d", count)
   326  		}
   327  
   328  		nextKey = uint32(0)
   329  		deleteKeys := []uint32{0, 1}
   330  		deleteValues := make([]spinLockValue, 2)
   331  		count, err = m.BatchLookupAndDelete(nil, &nextKey, deleteKeys, deleteValues, nil)
   332  		if !errors.Is(err, ErrKeyNotExist) {
   333  			t.Fatalf("BatchLookupAndDelete: %v", err)
   334  		}
   335  		if count != 2 {
   336  			t.Fatalf("BatchLookupAndDelete: expected two keys, got %d", count)
   337  		}
   338  	})
   339  }
   340  
   341  func TestMapWithLock(t *testing.T) {
   342  	testutils.SkipOnOldKernel(t, "5.13", "MAP BPF_F_LOCK")
   343  	testutils.Files(t, testutils.Glob(t, "./testdata/map_spin_lock-*.elf"), func(t *testing.T, file string) {
   344  		spec, err := LoadCollectionSpec(file)
   345  		if err != nil {
   346  			t.Fatal("Can't parse ELF:", err)
   347  		}
   348  		if spec.ByteOrder != internal.NativeEndian {
   349  			return
   350  		}
   351  
   352  		coll, err := NewCollection(spec)
   353  		if err != nil {
   354  			t.Fatal("Can't parse ELF:", err)
   355  		}
   356  		defer coll.Close()
   357  
   358  		type spinLockValue struct {
   359  			Cnt     uint32
   360  			Padding uint32
   361  		}
   362  
   363  		m, ok := coll.Maps["spin_lock_map"]
   364  		if !ok {
   365  			t.Fatal(err)
   366  		}
   367  
   368  		key := uint32(1)
   369  		value := spinLockValue{Cnt: 5}
   370  		err = m.Update(key, value, UpdateLock)
   371  		if err != nil {
   372  			t.Fatal(err)
   373  		}
   374  
   375  		value.Cnt = 0
   376  		err = m.LookupWithFlags(&key, &value, LookupLock)
   377  		if err != nil {
   378  			t.Fatal(err)
   379  		}
   380  		if value.Cnt != 5 {
   381  			t.Fatalf("Want value 5, got %d", value.Cnt)
   382  		}
   383  
   384  		t.Run("LookupAndDelete", func(t *testing.T) {
   385  			testutils.SkipOnOldKernel(t, "5.14", "LOOKUP_AND_DELETE flags")
   386  
   387  			value.Cnt = 0
   388  			err = m.LookupAndDeleteWithFlags(&key, &value, LookupLock)
   389  			if err != nil {
   390  				t.Fatal(err)
   391  			}
   392  			if value.Cnt != 5 {
   393  				t.Fatalf("Want value 5, got %d", value.Cnt)
   394  			}
   395  
   396  			err = m.LookupWithFlags(&key, &value, LookupLock)
   397  			if err != nil && !errors.Is(err, ErrKeyNotExist) {
   398  				t.Fatal(err)
   399  			}
   400  		})
   401  	})
   402  }
   403  
   404  func TestMapCloneNil(t *testing.T) {
   405  	m, err := (*Map)(nil).Clone()
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	if m != nil {
   411  		t.Fatal("Cloning a nil map doesn't return nil")
   412  	}
   413  }
   414  
   415  func TestMapPin(t *testing.T) {
   416  	m := createArray(t)
   417  	c := qt.New(t)
   418  	defer m.Close()
   419  
   420  	if err := m.Put(uint32(0), uint32(42)); err != nil {
   421  		t.Fatal("Can't put:", err)
   422  	}
   423  
   424  	tmp := testutils.TempBPFFS(t)
   425  	path := filepath.Join(tmp, "map")
   426  
   427  	if err := m.Pin(path); err != nil {
   428  		testutils.SkipIfNotSupported(t, err)
   429  		t.Fatal(err)
   430  	}
   431  
   432  	pinned := m.IsPinned()
   433  	c.Assert(pinned, qt.IsTrue)
   434  
   435  	m.Close()
   436  
   437  	m, err := LoadPinnedMap(path, nil)
   438  	testutils.SkipIfNotSupported(t, err)
   439  	if err != nil {
   440  		t.Fatal(err)
   441  	}
   442  	defer m.Close()
   443  
   444  	var v uint32
   445  	if err := m.Lookup(uint32(0), &v); err != nil {
   446  		t.Fatal("Can't lookup 0:", err)
   447  	}
   448  	if v != 42 {
   449  		t.Error("Want value 42, got", v)
   450  	}
   451  }
   452  
   453  func TestNestedMapPin(t *testing.T) {
   454  	m, err := NewMap(&MapSpec{
   455  		Type:       ArrayOfMaps,
   456  		KeySize:    4,
   457  		ValueSize:  4,
   458  		MaxEntries: 2,
   459  		InnerMap: &MapSpec{
   460  			Type:       Array,
   461  			KeySize:    4,
   462  			ValueSize:  4,
   463  			MaxEntries: 1,
   464  		},
   465  	})
   466  	testutils.SkipIfNotSupported(t, err)
   467  	if err != nil {
   468  		t.Fatal(err)
   469  	}
   470  	defer m.Close()
   471  
   472  	tmp, err := os.MkdirTemp("/sys/fs/bpf", "ebpf-test")
   473  	if err != nil {
   474  		t.Fatal(err)
   475  	}
   476  	defer os.RemoveAll(tmp)
   477  
   478  	path := filepath.Join(tmp, "nested")
   479  	if err := m.Pin(path); err != nil {
   480  		t.Fatal(err)
   481  	}
   482  	m.Close()
   483  
   484  	m, err = LoadPinnedMap(path, nil)
   485  	testutils.SkipIfNotSupported(t, err)
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  	defer m.Close()
   490  }
   491  
   492  func TestNestedMapPinNested(t *testing.T) {
   493  	if _, err := NewMap(&MapSpec{
   494  		Type:       ArrayOfMaps,
   495  		KeySize:    4,
   496  		ValueSize:  4,
   497  		MaxEntries: 2,
   498  		InnerMap: &MapSpec{
   499  			Name:       "inner",
   500  			Type:       Array,
   501  			KeySize:    4,
   502  			ValueSize:  4,
   503  			MaxEntries: 1,
   504  			Pinning:    PinByName,
   505  		},
   506  	}); err == nil {
   507  		t.Error("Inner maps should not be pinnable")
   508  	}
   509  }
   510  
   511  func TestMapPinMultiple(t *testing.T) {
   512  	testutils.SkipOnOldKernel(t, "4.9", "atomic re-pinning was introduced in 4.9 series")
   513  
   514  	tmp := testutils.TempBPFFS(t)
   515  	c := qt.New(t)
   516  
   517  	spec := spec1.Copy()
   518  
   519  	m1, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
   520  	if err != nil {
   521  		t.Fatal("Can't create map:", err)
   522  	}
   523  	defer m1.Close()
   524  	pinned := m1.IsPinned()
   525  	c.Assert(pinned, qt.IsTrue)
   526  
   527  	newPath := filepath.Join(tmp, "bar")
   528  	err = m1.Pin(newPath)
   529  	testutils.SkipIfNotSupported(t, err)
   530  	c.Assert(err, qt.IsNil)
   531  	oldPath := filepath.Join(tmp, spec.Name)
   532  	if _, err := os.Stat(oldPath); err == nil {
   533  		t.Fatal("Previous pinned map path still exists:", err)
   534  	}
   535  	m2, err := LoadPinnedMap(newPath, nil)
   536  	c.Assert(err, qt.IsNil)
   537  	pinned = m2.IsPinned()
   538  	c.Assert(pinned, qt.IsTrue)
   539  	defer m2.Close()
   540  }
   541  
   542  func TestMapPinWithEmptyPath(t *testing.T) {
   543  	m := createArray(t)
   544  	c := qt.New(t)
   545  	defer m.Close()
   546  
   547  	err := m.Pin("")
   548  
   549  	c.Assert(err, qt.Not(qt.IsNil))
   550  }
   551  
   552  func TestMapPinFailReplace(t *testing.T) {
   553  	tmp := testutils.TempBPFFS(t)
   554  	c := qt.New(t)
   555  	spec := spec1.Copy()
   556  	spec2 := spec1.Copy()
   557  	spec2.Name = spec1.Name + "bar"
   558  
   559  	m, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
   560  	if err != nil {
   561  		t.Fatal("Failed to create map:", err)
   562  	}
   563  	defer m.Close()
   564  	m2, err := NewMapWithOptions(spec2, MapOptions{PinPath: tmp})
   565  	if err != nil {
   566  		t.Fatal("Failed to create map2:", err)
   567  	}
   568  	defer m2.Close()
   569  	c.Assert(m.IsPinned(), qt.IsTrue)
   570  	newPath := filepath.Join(tmp, spec2.Name)
   571  
   572  	c.Assert(m.Pin(newPath), qt.Not(qt.IsNil), qt.Commentf("Pin didn't"+
   573  		" fail new path from replacing an existing path"))
   574  }
   575  
   576  func TestMapUnpin(t *testing.T) {
   577  	tmp := testutils.TempBPFFS(t)
   578  	c := qt.New(t)
   579  	spec := spec1.Copy()
   580  
   581  	m, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
   582  	if err != nil {
   583  		t.Fatal("Failed to create map:", err)
   584  	}
   585  	defer m.Close()
   586  
   587  	pinned := m.IsPinned()
   588  	c.Assert(pinned, qt.IsTrue)
   589  	path := filepath.Join(tmp, spec.Name)
   590  	m2, err := LoadPinnedMap(path, nil)
   591  	testutils.SkipIfNotSupported(t, err)
   592  	c.Assert(err, qt.IsNil)
   593  	defer m2.Close()
   594  
   595  	if err = m.Unpin(); err != nil {
   596  		t.Fatal("Failed to unpin map:", err)
   597  	}
   598  	if _, err := os.Stat(path); err == nil {
   599  		t.Fatal("Pinned map path still exists after unpinning:", err)
   600  	}
   601  }
   602  
   603  func TestMapLoadPinned(t *testing.T) {
   604  	tmp := testutils.TempBPFFS(t)
   605  	c := qt.New(t)
   606  
   607  	spec := spec1.Copy()
   608  
   609  	m1, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
   610  	c.Assert(err, qt.IsNil)
   611  	defer m1.Close()
   612  	pinned := m1.IsPinned()
   613  	c.Assert(pinned, qt.IsTrue)
   614  
   615  	path := filepath.Join(tmp, spec.Name)
   616  	m2, err := LoadPinnedMap(path, nil)
   617  	testutils.SkipIfNotSupported(t, err)
   618  	c.Assert(err, qt.IsNil)
   619  	defer m2.Close()
   620  	pinned = m2.IsPinned()
   621  	c.Assert(pinned, qt.IsTrue)
   622  }
   623  
   624  func TestMapLoadPinnedUnpin(t *testing.T) {
   625  	tmp := testutils.TempBPFFS(t)
   626  	c := qt.New(t)
   627  
   628  	spec := spec1.Copy()
   629  
   630  	m1, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
   631  	c.Assert(err, qt.IsNil)
   632  	defer m1.Close()
   633  	pinned := m1.IsPinned()
   634  	c.Assert(pinned, qt.IsTrue)
   635  
   636  	path := filepath.Join(tmp, spec.Name)
   637  	m2, err := LoadPinnedMap(path, nil)
   638  	testutils.SkipIfNotSupported(t, err)
   639  	c.Assert(err, qt.IsNil)
   640  	defer m2.Close()
   641  	err = m1.Unpin()
   642  	c.Assert(err, qt.IsNil)
   643  	err = m2.Unpin()
   644  	c.Assert(err, qt.IsNil)
   645  }
   646  
   647  func TestMapLoadPinnedWithOptions(t *testing.T) {
   648  	// Introduced in commit 6e71b04a8224.
   649  	testutils.SkipOnOldKernel(t, "4.15", "file_flags in BPF_OBJ_GET")
   650  
   651  	array := createArray(t)
   652  	defer array.Close()
   653  
   654  	tmp := testutils.TempBPFFS(t)
   655  
   656  	path := filepath.Join(tmp, "map")
   657  	if err := array.Pin(path); err != nil {
   658  		t.Fatal(err)
   659  	}
   660  	if err := array.Put(uint32(0), uint32(123)); err != nil {
   661  		t.Fatal(err)
   662  	}
   663  	array.Close()
   664  
   665  	t.Run("read-only", func(t *testing.T) {
   666  		array, err := LoadPinnedMap(path, &LoadPinOptions{
   667  			ReadOnly: true,
   668  		})
   669  		testutils.SkipIfNotSupported(t, err)
   670  		if err != nil {
   671  			t.Fatal("Can't load map:", err)
   672  		}
   673  		defer array.Close()
   674  
   675  		if err := array.Put(uint32(0), uint32(1)); !errors.Is(err, unix.EPERM) {
   676  			t.Fatal("Expected EPERM from Put, got", err)
   677  		}
   678  	})
   679  
   680  	t.Run("write-only", func(t *testing.T) {
   681  		array, err := LoadPinnedMap(path, &LoadPinOptions{
   682  			WriteOnly: true,
   683  		})
   684  		testutils.SkipIfNotSupported(t, err)
   685  		if err != nil {
   686  			t.Fatal("Can't load map:", err)
   687  		}
   688  		defer array.Close()
   689  
   690  		var value uint32
   691  		if err := array.Lookup(uint32(0), &value); !errors.Is(err, unix.EPERM) {
   692  			t.Fatal("Expected EPERM from Lookup, got", err)
   693  		}
   694  	})
   695  }
   696  
   697  func TestMapPinFlags(t *testing.T) {
   698  	tmp := testutils.TempBPFFS(t)
   699  
   700  	spec := &MapSpec{
   701  		Name:       "map",
   702  		Type:       Array,
   703  		KeySize:    4,
   704  		ValueSize:  4,
   705  		MaxEntries: 1,
   706  		Pinning:    PinByName,
   707  	}
   708  
   709  	m, err := NewMapWithOptions(spec, MapOptions{
   710  		PinPath: tmp,
   711  	})
   712  	qt.Assert(t, err, qt.IsNil)
   713  	m.Close()
   714  
   715  	_, err = NewMapWithOptions(spec, MapOptions{
   716  		PinPath: tmp,
   717  		LoadPinOptions: LoadPinOptions{
   718  			Flags: math.MaxUint32,
   719  		},
   720  	})
   721  	if !errors.Is(err, unix.EINVAL) {
   722  		t.Fatal("Invalid flags should trigger EINVAL:", err)
   723  	}
   724  }
   725  
   726  func createArray(t *testing.T) *Map {
   727  	t.Helper()
   728  
   729  	m, err := NewMap(&MapSpec{
   730  		Type:       Array,
   731  		KeySize:    4,
   732  		ValueSize:  4,
   733  		MaxEntries: 2,
   734  	})
   735  	if err != nil {
   736  		t.Fatal(err)
   737  	}
   738  	return m
   739  }
   740  
   741  func TestMapQueue(t *testing.T) {
   742  	testutils.SkipOnOldKernel(t, "4.20", "map type queue")
   743  
   744  	m, err := NewMap(&MapSpec{
   745  		Type:       Queue,
   746  		ValueSize:  4,
   747  		MaxEntries: 2,
   748  	})
   749  	if err != nil {
   750  		t.Fatal(err)
   751  	}
   752  	defer m.Close()
   753  
   754  	for _, v := range []uint32{42, 4242} {
   755  		if err := m.Put(nil, v); err != nil {
   756  			t.Fatalf("Can't put %d: %s", v, err)
   757  		}
   758  	}
   759  
   760  	var v uint32
   761  	if err := m.LookupAndDelete(nil, &v); err != nil {
   762  		t.Fatal("Can't lookup and delete element:", err)
   763  	}
   764  	if v != 42 {
   765  		t.Error("Want value 42, got", v)
   766  	}
   767  
   768  	v = 0
   769  	if err := m.LookupAndDelete(nil, unsafe.Pointer(&v)); err != nil {
   770  		t.Fatal("Can't lookup and delete element using unsafe.Pointer:", err)
   771  	}
   772  	if v != 4242 {
   773  		t.Error("Want value 4242, got", v)
   774  	}
   775  
   776  	if err := m.LookupAndDelete(nil, &v); !errors.Is(err, ErrKeyNotExist) {
   777  		t.Fatal("Lookup and delete on empty Queue:", err)
   778  	}
   779  }
   780  
   781  func TestMapInMap(t *testing.T) {
   782  	for _, typ := range []MapType{ArrayOfMaps, HashOfMaps} {
   783  		t.Run(typ.String(), func(t *testing.T) {
   784  			spec := &MapSpec{
   785  				Type:       typ,
   786  				KeySize:    4,
   787  				MaxEntries: 2,
   788  				InnerMap: &MapSpec{
   789  					Type:       Array,
   790  					KeySize:    4,
   791  					ValueSize:  4,
   792  					MaxEntries: 2,
   793  				},
   794  			}
   795  
   796  			inner, err := NewMap(spec.InnerMap)
   797  			if err != nil {
   798  				t.Fatal(err)
   799  			}
   800  			if err := inner.Put(uint32(1), uint32(4242)); err != nil {
   801  				t.Fatal(err)
   802  			}
   803  			defer inner.Close()
   804  
   805  			outer, err := NewMap(spec)
   806  			testutils.SkipIfNotSupported(t, err)
   807  			if err != nil {
   808  				t.Fatal(err)
   809  			}
   810  			defer outer.Close()
   811  
   812  			if err := outer.Put(uint32(0), inner); err != nil {
   813  				t.Fatal("Can't put inner map:", err)
   814  			}
   815  
   816  			var inner2 *Map
   817  			if err := outer.Lookup(uint32(0), &inner2); err != nil {
   818  				t.Fatal("Can't lookup 0:", err)
   819  			}
   820  			defer inner2.Close()
   821  
   822  			var v uint32
   823  			if err := inner2.Lookup(uint32(1), &v); err != nil {
   824  				t.Fatal("Can't lookup 1 in inner2:", err)
   825  			}
   826  
   827  			if v != 4242 {
   828  				t.Error("Expected value 4242, got", v)
   829  			}
   830  
   831  			inner2.Close()
   832  
   833  			// Make sure we can still access the original map
   834  			if err := inner.Lookup(uint32(1), &v); err != nil {
   835  				t.Fatal("Can't lookup 1 in inner:", err)
   836  			}
   837  
   838  			if v != 4242 {
   839  				t.Error("Expected value 4242, got", v)
   840  			}
   841  		})
   842  	}
   843  }
   844  
   845  func TestNewMapInMapFromFD(t *testing.T) {
   846  	nested, err := NewMap(&MapSpec{
   847  		Type:       ArrayOfMaps,
   848  		KeySize:    4,
   849  		MaxEntries: 2,
   850  		InnerMap: &MapSpec{
   851  			Type:       Array,
   852  			KeySize:    4,
   853  			ValueSize:  4,
   854  			MaxEntries: 2,
   855  		},
   856  	})
   857  	testutils.SkipIfNotSupported(t, err)
   858  	if err != nil {
   859  		t.Fatal(err)
   860  	}
   861  	defer nested.Close()
   862  
   863  	// Do not copy this, use Clone instead.
   864  	another, err := NewMapFromFD(nested.FD())
   865  	if err != nil {
   866  		t.Fatal("Can't create a new nested map from an FD")
   867  	}
   868  	another.Close()
   869  }
   870  
   871  func TestPerfEventArray(t *testing.T) {
   872  	specs := []*MapSpec{
   873  		{Type: PerfEventArray},
   874  		{Type: PerfEventArray, KeySize: 4},
   875  		{Type: PerfEventArray, ValueSize: 4},
   876  	}
   877  
   878  	for _, spec := range specs {
   879  		m, err := NewMap(spec)
   880  		if err != nil {
   881  			t.Errorf("Can't create perf event array from %v: %s", spec, err)
   882  		} else {
   883  			m.Close()
   884  		}
   885  	}
   886  }
   887  
   888  func createMapInMap(t *testing.T, typ MapType) *Map {
   889  	t.Helper()
   890  
   891  	spec := &MapSpec{
   892  		Type:       typ,
   893  		KeySize:    4,
   894  		MaxEntries: 2,
   895  		InnerMap: &MapSpec{
   896  			Type:       Array,
   897  			KeySize:    4,
   898  			ValueSize:  4,
   899  			MaxEntries: 2,
   900  		},
   901  	}
   902  
   903  	m, err := NewMap(spec)
   904  	testutils.SkipIfNotSupported(t, err)
   905  	if err != nil {
   906  		t.Fatal(err)
   907  	}
   908  	return m
   909  }
   910  
   911  func TestMapInMapValueSize(t *testing.T) {
   912  	spec := &MapSpec{
   913  		Type:       ArrayOfMaps,
   914  		KeySize:    4,
   915  		ValueSize:  0,
   916  		MaxEntries: 2,
   917  		InnerMap: &MapSpec{
   918  			Type:       Array,
   919  			KeySize:    4,
   920  			ValueSize:  4,
   921  			MaxEntries: 2,
   922  		},
   923  	}
   924  
   925  	m, err := NewMap(spec)
   926  	testutils.SkipIfNotSupported(t, err)
   927  	if err != nil {
   928  		t.Fatal(err)
   929  	}
   930  	m.Close()
   931  
   932  	spec.ValueSize = 4
   933  	m, err = NewMap(spec)
   934  	if err != nil {
   935  		t.Fatal(err)
   936  	}
   937  	m.Close()
   938  
   939  	spec.ValueSize = 1
   940  	if _, err := NewMap(spec); err == nil {
   941  		t.Fatal("Expected an error")
   942  	}
   943  }
   944  
   945  func TestIterateEmptyMap(t *testing.T) {
   946  	makeMap := func(t *testing.T, mapType MapType) *Map {
   947  		m, err := NewMap(&MapSpec{
   948  			Type:       mapType,
   949  			KeySize:    4,
   950  			ValueSize:  8,
   951  			MaxEntries: 2,
   952  		})
   953  		if errors.Is(err, unix.EINVAL) {
   954  			t.Skip(mapType, "is not supported")
   955  		}
   956  		if err != nil {
   957  			t.Fatal("Can't create map:", err)
   958  		}
   959  		t.Cleanup(func() { m.Close() })
   960  		return m
   961  	}
   962  
   963  	for _, mapType := range []MapType{
   964  		Hash,
   965  		SockHash,
   966  	} {
   967  		t.Run(mapType.String(), func(t *testing.T) {
   968  			m := makeMap(t, mapType)
   969  			entries := m.Iterate()
   970  
   971  			var key string
   972  			var value uint32
   973  			if entries.Next(&key, &value) != false {
   974  				t.Error("Empty hash should not be iterable")
   975  			}
   976  			if err := entries.Err(); err != nil {
   977  				t.Error("Empty hash shouldn't return an error:", err)
   978  			}
   979  		})
   980  	}
   981  
   982  	for _, mapType := range []MapType{
   983  		Array,
   984  		SockMap,
   985  	} {
   986  		t.Run(mapType.String(), func(t *testing.T) {
   987  			m := makeMap(t, mapType)
   988  			entries := m.Iterate()
   989  			var key string
   990  			var value uint32
   991  			for entries.Next(&key, &value) {
   992  				// Some empty arrays like sockmap don't return any keys.
   993  			}
   994  			if err := entries.Err(); err != nil {
   995  				t.Error("Empty array shouldn't return an error:", err)
   996  			}
   997  		})
   998  	}
   999  }
  1000  
  1001  func TestMapIterate(t *testing.T) {
  1002  	hash, err := NewMap(&MapSpec{
  1003  		Type:       Hash,
  1004  		KeySize:    5,
  1005  		ValueSize:  4,
  1006  		MaxEntries: 2,
  1007  	})
  1008  	if err != nil {
  1009  		t.Fatal(err)
  1010  	}
  1011  	defer hash.Close()
  1012  
  1013  	if err := hash.Put("hello", uint32(21)); err != nil {
  1014  		t.Fatal(err)
  1015  	}
  1016  
  1017  	if err := hash.Put("world", uint32(42)); err != nil {
  1018  		t.Fatal(err)
  1019  	}
  1020  
  1021  	var key string
  1022  	var value uint32
  1023  	var keys []string
  1024  
  1025  	entries := hash.Iterate()
  1026  	for entries.Next(&key, &value) {
  1027  		keys = append(keys, key)
  1028  	}
  1029  
  1030  	if err := entries.Err(); err != nil {
  1031  		t.Fatal(err)
  1032  	}
  1033  
  1034  	sort.Strings(keys)
  1035  
  1036  	if n := len(keys); n != 2 {
  1037  		t.Fatal("Expected to get 2 keys, have", n)
  1038  	}
  1039  	if keys[0] != "hello" {
  1040  		t.Error("Expected index 0 to be hello, got", keys[0])
  1041  	}
  1042  	if keys[1] != "world" {
  1043  		t.Error("Expected index 1 to be hello, got", keys[1])
  1044  	}
  1045  }
  1046  
  1047  func TestMapIterateHashKeyOneByteFull(t *testing.T) {
  1048  	hash, err := NewMap(&MapSpec{
  1049  		Type:       Hash,
  1050  		KeySize:    1,
  1051  		ValueSize:  1,
  1052  		MaxEntries: 256,
  1053  	})
  1054  	if err != nil {
  1055  		t.Fatal(err)
  1056  	}
  1057  	defer hash.Close()
  1058  
  1059  	for i := 0; i < int(hash.MaxEntries()); i++ {
  1060  		if err := hash.Put(uint8(i), uint8(i)); err != nil {
  1061  			t.Fatal(err)
  1062  		}
  1063  	}
  1064  	var key uint8
  1065  	var value uint8
  1066  	var keys int
  1067  
  1068  	entries := hash.Iterate()
  1069  	for entries.Next(&key, &value) {
  1070  		if key != value {
  1071  			t.Fatalf("Expected key == value, got key %v value %v", key, value)
  1072  		}
  1073  		keys++
  1074  	}
  1075  
  1076  	if err := entries.Err(); err != nil {
  1077  		t.Fatal(err)
  1078  	}
  1079  
  1080  	if keys != int(hash.MaxEntries()) {
  1081  		t.Fatalf("Expected to get %d keys, have %d", hash.MaxEntries(), keys)
  1082  	}
  1083  }
  1084  
  1085  func TestMapGuessNonExistentKey(t *testing.T) {
  1086  	tests := []struct {
  1087  		name    string
  1088  		mapType MapType
  1089  		keys    []uint32
  1090  	}{
  1091  		{
  1092  			"empty", Hash, []uint32{},
  1093  		},
  1094  		{
  1095  			"all zero key", Hash, []uint32{0},
  1096  		},
  1097  		{
  1098  			"all ones key", Hash, []uint32{math.MaxUint32},
  1099  		},
  1100  		{
  1101  			"alternating bits key", Hash, []uint32{0x5555_5555},
  1102  		},
  1103  		{
  1104  			"all special patterns", Hash, []uint32{0, math.MaxUint32, 0x5555_5555},
  1105  		},
  1106  		{
  1107  			"empty", Array, []uint32{},
  1108  		},
  1109  		{
  1110  			"all zero key", Array, []uint32{0},
  1111  		},
  1112  		{
  1113  			"full", Array, []uint32{0, 1},
  1114  		},
  1115  	}
  1116  
  1117  	for _, tt := range tests {
  1118  		t.Run(fmt.Sprintf("%s: %s", tt.mapType, tt.name), func(t *testing.T) {
  1119  			maxEntries := uint32(len(tt.keys))
  1120  			if maxEntries == 0 {
  1121  				maxEntries = 1
  1122  			}
  1123  
  1124  			m, err := NewMap(&MapSpec{
  1125  				Type:       tt.mapType,
  1126  				KeySize:    4,
  1127  				ValueSize:  4,
  1128  				MaxEntries: maxEntries,
  1129  			})
  1130  			if err != nil {
  1131  				t.Fatal(err)
  1132  			}
  1133  			defer m.Close()
  1134  
  1135  			for _, key := range tt.keys {
  1136  				if err := m.Put(key, key); err != nil {
  1137  					t.Fatal(err)
  1138  				}
  1139  			}
  1140  
  1141  			guess, err := m.guessNonExistentKey()
  1142  			if err != nil {
  1143  				t.Fatal(err)
  1144  			}
  1145  
  1146  			if len(guess) != int(m.keySize) {
  1147  				t.Fatal("Guessed key has wrong size")
  1148  			}
  1149  
  1150  			var value uint32
  1151  			if err := m.Lookup(guess, &value); !errors.Is(err, unix.ENOENT) {
  1152  				t.Fatal("Doesn't return ENOENT:", err)
  1153  			}
  1154  		})
  1155  	}
  1156  
  1157  	t.Run("Hash: full", func(t *testing.T) {
  1158  		const n = math.MaxUint8 + 1
  1159  
  1160  		hash, err := NewMap(&MapSpec{
  1161  			Type:       Hash,
  1162  			KeySize:    1,
  1163  			ValueSize:  1,
  1164  			MaxEntries: n,
  1165  		})
  1166  		if err != nil {
  1167  			t.Fatal(err)
  1168  		}
  1169  		defer hash.Close()
  1170  
  1171  		for i := 0; i < n; i++ {
  1172  			if err := hash.Put(uint8(i), uint8(i)); err != nil {
  1173  				t.Fatal(err)
  1174  			}
  1175  		}
  1176  
  1177  		_, err = hash.guessNonExistentKey()
  1178  		if err == nil {
  1179  			t.Fatal("guessNonExistentKey doesn't return error on full hash table")
  1180  		}
  1181  	})
  1182  }
  1183  
  1184  func TestNotExist(t *testing.T) {
  1185  	hash := createHash()
  1186  	defer hash.Close()
  1187  
  1188  	var tmp uint32
  1189  	err := hash.Lookup("hello", &tmp)
  1190  	if !errors.Is(err, ErrKeyNotExist) {
  1191  		t.Error("Lookup doesn't return ErrKeyNotExist")
  1192  	}
  1193  
  1194  	buf, err := hash.LookupBytes("hello")
  1195  	if err != nil {
  1196  		t.Error("Looking up non-existent key return an error:", err)
  1197  	}
  1198  	if buf != nil {
  1199  		t.Error("LookupBytes returns non-nil buffer for non-existent key")
  1200  	}
  1201  
  1202  	if err := hash.Delete("hello"); !errors.Is(err, ErrKeyNotExist) {
  1203  		t.Error("Deleting unknown key doesn't return ErrKeyNotExist", err)
  1204  	}
  1205  
  1206  	var k = []byte{1, 2, 3, 4, 5}
  1207  	if err := hash.NextKey(&k, &tmp); !errors.Is(err, ErrKeyNotExist) {
  1208  		t.Error("Looking up next key in empty map doesn't return a non-existing error", err)
  1209  	}
  1210  
  1211  	if err := hash.NextKey(nil, &tmp); !errors.Is(err, ErrKeyNotExist) {
  1212  		t.Error("Looking up next key in empty map doesn't return a non-existing error", err)
  1213  	}
  1214  }
  1215  
  1216  func TestExist(t *testing.T) {
  1217  	hash := createHash()
  1218  	defer hash.Close()
  1219  
  1220  	if err := hash.Put("hello", uint32(21)); err != nil {
  1221  		t.Errorf("Failed to put key/value pair into hash: %v", err)
  1222  	}
  1223  
  1224  	if err := hash.Update("hello", uint32(42), UpdateNoExist); !errors.Is(err, ErrKeyExist) {
  1225  		t.Error("Updating existing key doesn't return ErrKeyExist")
  1226  	}
  1227  }
  1228  
  1229  func TestIterateMapInMap(t *testing.T) {
  1230  	const idx = uint32(1)
  1231  
  1232  	parent := createMapInMap(t, ArrayOfMaps)
  1233  	defer parent.Close()
  1234  
  1235  	a := createArray(t)
  1236  	defer a.Close()
  1237  
  1238  	if err := parent.Put(idx, a); err != nil {
  1239  		t.Fatal(err)
  1240  	}
  1241  
  1242  	var (
  1243  		key     uint32
  1244  		m       *Map
  1245  		entries = parent.Iterate()
  1246  	)
  1247  
  1248  	if !entries.Next(&key, &m) {
  1249  		t.Fatal("Iterator encountered error:", entries.Err())
  1250  	}
  1251  	m.Close()
  1252  
  1253  	if key != 1 {
  1254  		t.Error("Iterator didn't skip first entry")
  1255  	}
  1256  
  1257  	if m == nil {
  1258  		t.Fatal("Map is nil")
  1259  	}
  1260  }
  1261  
  1262  func TestPerCPUMarshaling(t *testing.T) {
  1263  	for _, typ := range []MapType{PerCPUHash, PerCPUArray, LRUCPUHash} {
  1264  		t.Run(typ.String(), func(t *testing.T) {
  1265  			numCPU, err := internal.PossibleCPUs()
  1266  			if err != nil {
  1267  				t.Fatal(err)
  1268  			}
  1269  			if numCPU < 2 {
  1270  				t.Skip("Test requires at least two CPUs")
  1271  			}
  1272  			if typ == PerCPUHash || typ == PerCPUArray {
  1273  				testutils.SkipOnOldKernel(t, "4.6", "per-CPU hash and array")
  1274  			}
  1275  			if typ == LRUCPUHash {
  1276  				testutils.SkipOnOldKernel(t, "4.10", "LRU per-CPU hash")
  1277  			}
  1278  
  1279  			arr, err := NewMap(&MapSpec{
  1280  				Type:       typ,
  1281  				KeySize:    4,
  1282  				ValueSize:  5,
  1283  				MaxEntries: 1,
  1284  			})
  1285  			if err != nil {
  1286  				t.Fatal(err)
  1287  			}
  1288  			defer arr.Close()
  1289  
  1290  			values := []*customEncoding{
  1291  				{"hello"},
  1292  				{"world"},
  1293  			}
  1294  			if err := arr.Put(uint32(0), values); err != nil {
  1295  				t.Fatal(err)
  1296  			}
  1297  
  1298  			// Make sure unmarshaling works on slices containing pointers
  1299  			var retrieved []*customEncoding
  1300  			if err := arr.Lookup(uint32(0), &retrieved); err != nil {
  1301  				t.Fatal("Can't retrieve key 0:", err)
  1302  			}
  1303  
  1304  			for i, want := range []string{"HELLO", "WORLD"} {
  1305  				if retrieved[i] == nil {
  1306  					t.Error("First item is nil")
  1307  				} else if have := retrieved[i].data; have != want {
  1308  					t.Errorf("Put doesn't use BinaryMarshaler, expected %s but got %s", want, have)
  1309  				}
  1310  			}
  1311  
  1312  		})
  1313  	}
  1314  }
  1315  
  1316  type bpfCgroupStorageKey struct {
  1317  	CgroupInodeId uint64
  1318  	AttachType    AttachType
  1319  	_             [4]byte // Padding
  1320  }
  1321  
  1322  func TestCgroupPerCPUStorageMarshaling(t *testing.T) {
  1323  	numCPU, err := internal.PossibleCPUs()
  1324  	if err != nil {
  1325  		t.Fatal(err)
  1326  	}
  1327  	if numCPU < 2 {
  1328  		t.Skip("Test requires at least two CPUs")
  1329  	}
  1330  	testutils.SkipOnOldKernel(t, "5.9", "per-CPU CGoup storage with write from user space support")
  1331  
  1332  	cgroup := testutils.CreateCgroup(t)
  1333  
  1334  	arr, err := NewMap(&MapSpec{
  1335  		Type:      PerCPUCGroupStorage,
  1336  		KeySize:   uint32(unsafe.Sizeof(bpfCgroupStorageKey{})),
  1337  		ValueSize: uint32(unsafe.Sizeof(uint64(0))),
  1338  	})
  1339  	if err != nil {
  1340  		t.Fatal(err)
  1341  	}
  1342  	t.Cleanup(func() {
  1343  		arr.Close()
  1344  	})
  1345  
  1346  	prog, err := NewProgram(&ProgramSpec{
  1347  		Type:       CGroupSKB,
  1348  		AttachType: AttachCGroupInetEgress,
  1349  		License:    "MIT",
  1350  		Instructions: asm.Instructions{
  1351  			asm.LoadMapPtr(asm.R1, arr.FD()),
  1352  			asm.Mov.Imm(asm.R2, 0),
  1353  			asm.FnGetLocalStorage.Call(),
  1354  			asm.Mov.Imm(asm.R0, 0),
  1355  			asm.Return(),
  1356  		},
  1357  	})
  1358  	if err != nil {
  1359  		t.Fatal(err)
  1360  	}
  1361  	defer prog.Close()
  1362  
  1363  	progAttachAttrs := sys.ProgAttachAttr{
  1364  		TargetFd:     uint32(cgroup.Fd()),
  1365  		AttachBpfFd:  uint32(prog.FD()),
  1366  		AttachType:   uint32(AttachCGroupInetEgress),
  1367  		AttachFlags:  0,
  1368  		ReplaceBpfFd: 0,
  1369  	}
  1370  	err = sys.ProgAttach(&progAttachAttrs)
  1371  	if err != nil {
  1372  		t.Fatal(err)
  1373  	}
  1374  	defer func() {
  1375  		attr := sys.ProgDetachAttr{
  1376  			TargetFd:    uint32(cgroup.Fd()),
  1377  			AttachBpfFd: uint32(prog.FD()),
  1378  			AttachType:  uint32(AttachCGroupInetEgress),
  1379  		}
  1380  		if err := sys.ProgDetach(&attr); err != nil {
  1381  			t.Fatal(err)
  1382  		}
  1383  	}()
  1384  
  1385  	var mapKey = &bpfCgroupStorageKey{
  1386  		CgroupInodeId: testutils.GetCgroupIno(t, cgroup),
  1387  		AttachType:    AttachCGroupInetEgress,
  1388  	}
  1389  
  1390  	values := []uint64{1, 2}
  1391  	if err := arr.Put(mapKey, values); err != nil {
  1392  		t.Fatalf("Can't set cgroup %s storage: %s", cgroup.Name(), err)
  1393  	}
  1394  
  1395  	var retrieved []uint64
  1396  	if err := arr.Lookup(mapKey, &retrieved); err != nil {
  1397  		t.Fatalf("Can't retrieve cgroup %s storage: %s", cgroup.Name(), err)
  1398  	}
  1399  
  1400  	for i, want := range []uint64{1, 2} {
  1401  		if retrieved[i] == 0 {
  1402  			t.Errorf("Item %d is 0", i)
  1403  		} else if have := retrieved[i]; have != want {
  1404  			t.Errorf("PerCPUCGroupStorage map is not correctly unmarshaled, expected %d but got %d", want, have)
  1405  		}
  1406  	}
  1407  }
  1408  
  1409  func TestMapMarshalUnsafe(t *testing.T) {
  1410  	m, err := NewMap(&MapSpec{
  1411  		Type:       Hash,
  1412  		KeySize:    4,
  1413  		ValueSize:  4,
  1414  		MaxEntries: 1,
  1415  	})
  1416  	if err != nil {
  1417  		t.Fatal(err)
  1418  	}
  1419  	defer m.Close()
  1420  
  1421  	key := uint32(1)
  1422  	value := uint32(42)
  1423  
  1424  	if err := m.Put(unsafe.Pointer(&key), unsafe.Pointer(&value)); err != nil {
  1425  		t.Fatal(err)
  1426  	}
  1427  
  1428  	var res uint32
  1429  	if err := m.Lookup(unsafe.Pointer(&key), unsafe.Pointer(&res)); err != nil {
  1430  		t.Fatal("Can't get item:", err)
  1431  	}
  1432  
  1433  	var sum uint32
  1434  	iter := m.Iterate()
  1435  	for iter.Next(&key, unsafe.Pointer(&res)) {
  1436  		sum += res
  1437  	}
  1438  	if err := iter.Err(); err != nil {
  1439  		t.Fatal(err)
  1440  	}
  1441  
  1442  	if res != 42 {
  1443  		t.Fatalf("Expected 42, got %d", res)
  1444  	}
  1445  
  1446  	iter = m.Iterate()
  1447  	iter.Next(unsafe.Pointer(&key), &res)
  1448  	if err := iter.Err(); err != nil {
  1449  		t.Error(err)
  1450  	}
  1451  	if key != 1 {
  1452  		t.Errorf("Expected key 1, got %d", key)
  1453  	}
  1454  
  1455  	if err := m.Delete(unsafe.Pointer(&key)); err != nil {
  1456  		t.Fatal("Can't delete:", err)
  1457  	}
  1458  }
  1459  
  1460  func TestMapName(t *testing.T) {
  1461  	if err := haveObjName(); err != nil {
  1462  		t.Skip(err)
  1463  	}
  1464  
  1465  	m, err := NewMap(&MapSpec{
  1466  		Name:       "test",
  1467  		Type:       Array,
  1468  		KeySize:    4,
  1469  		ValueSize:  4,
  1470  		MaxEntries: 1,
  1471  	})
  1472  	if err != nil {
  1473  		t.Fatal(err)
  1474  	}
  1475  	defer m.Close()
  1476  
  1477  	var info sys.MapInfo
  1478  	if err := sys.ObjInfo(m.fd, &info); err != nil {
  1479  		t.Fatal(err)
  1480  	}
  1481  
  1482  	if name := unix.ByteSliceToString(info.Name[:]); name != "test" {
  1483  		t.Error("Expected name to be test, got", name)
  1484  	}
  1485  }
  1486  
  1487  func TestMapFromFD(t *testing.T) {
  1488  	m := createArray(t)
  1489  	defer m.Close()
  1490  
  1491  	if err := m.Put(uint32(0), uint32(123)); err != nil {
  1492  		t.Fatal(err)
  1493  	}
  1494  
  1495  	// If you're thinking about copying this, don't. Use
  1496  	// Clone() instead.
  1497  	m2, err := NewMapFromFD(m.FD())
  1498  	testutils.SkipIfNotSupported(t, err)
  1499  	if err != nil {
  1500  		t.Fatal(err)
  1501  	}
  1502  
  1503  	// Both m and m2 refer to the same fd now. Closing either of them will
  1504  	// release the fd to the OS, which then might re-use that fd for another
  1505  	// test. Once we close the second map we might close the re-used fd
  1506  	// inadvertently, leading to spurious test failures.
  1507  	// To avoid this we have to "leak" one of the maps.
  1508  	m2.fd.Forget()
  1509  
  1510  	var val uint32
  1511  	if err := m2.Lookup(uint32(0), &val); err != nil {
  1512  		t.Fatal("Can't look up key:", err)
  1513  	}
  1514  
  1515  	if val != 123 {
  1516  		t.Error("Wrong value")
  1517  	}
  1518  }
  1519  
  1520  func TestMapContents(t *testing.T) {
  1521  	spec := &MapSpec{
  1522  		Type:       Array,
  1523  		KeySize:    4,
  1524  		ValueSize:  4,
  1525  		MaxEntries: 2,
  1526  		Contents: []MapKV{
  1527  			{uint32(0), uint32(23)},
  1528  			{uint32(1), uint32(42)},
  1529  		},
  1530  	}
  1531  
  1532  	m, err := NewMap(spec)
  1533  	if err != nil {
  1534  		t.Fatal("Can't create map:", err)
  1535  	}
  1536  	defer m.Close()
  1537  
  1538  	var value uint32
  1539  	if err := m.Lookup(uint32(0), &value); err != nil {
  1540  		t.Error("Can't look up key 0:", err)
  1541  	} else if value != 23 {
  1542  		t.Errorf("Incorrect value for key 0, expected 23, have %d", value)
  1543  	}
  1544  
  1545  	if err := m.Lookup(uint32(1), &value); err != nil {
  1546  		t.Error("Can't look up key 1:", err)
  1547  	} else if value != 42 {
  1548  		t.Errorf("Incorrect value for key 0, expected 23, have %d", value)
  1549  	}
  1550  
  1551  	spec.Contents = []MapKV{
  1552  		// Key is larger than MaxEntries
  1553  		{uint32(14), uint32(0)},
  1554  	}
  1555  
  1556  	if _, err = NewMap(spec); err == nil {
  1557  		t.Error("Invalid contents should be rejected")
  1558  	}
  1559  }
  1560  
  1561  func TestMapFreeze(t *testing.T) {
  1562  	arr := createArray(t)
  1563  	defer arr.Close()
  1564  
  1565  	err := arr.Freeze()
  1566  	testutils.SkipIfNotSupported(t, err)
  1567  
  1568  	if err != nil {
  1569  		t.Fatal("Can't freeze map:", err)
  1570  	}
  1571  
  1572  	if err := arr.Put(uint32(0), uint32(1)); err == nil {
  1573  		t.Error("Freeze doesn't prevent modification from user space")
  1574  	}
  1575  }
  1576  
  1577  func TestMapGetNextID(t *testing.T) {
  1578  	testutils.SkipOnOldKernel(t, "4.13", "bpf_map_get_next_id")
  1579  	var next MapID
  1580  	var err error
  1581  
  1582  	hash := createHash()
  1583  	defer hash.Close()
  1584  
  1585  	if next, err = MapGetNextID(MapID(0)); err != nil {
  1586  		t.Fatal("Can't get next ID:", err)
  1587  	}
  1588  	if next == MapID(0) {
  1589  		t.Fatal("Expected next ID other than 0")
  1590  	}
  1591  
  1592  	// As there can be multiple eBPF maps, we loop over all of them and
  1593  	// make sure, the IDs increase and the last call will return ErrNotExist
  1594  	for {
  1595  		last := next
  1596  		if next, err = MapGetNextID(last); err != nil {
  1597  			if !errors.Is(err, os.ErrNotExist) {
  1598  				t.Fatal("Expected ErrNotExist, got:", err)
  1599  			}
  1600  			break
  1601  		}
  1602  		if next <= last {
  1603  			t.Fatalf("Expected next ID (%d) to be higher than the last ID (%d)", next, last)
  1604  		}
  1605  	}
  1606  }
  1607  
  1608  func TestNewMapFromID(t *testing.T) {
  1609  	hash := createHash()
  1610  	defer hash.Close()
  1611  
  1612  	info, err := hash.Info()
  1613  	testutils.SkipIfNotSupported(t, err)
  1614  	if err != nil {
  1615  		t.Fatal("Couldn't get map info:", err)
  1616  	}
  1617  
  1618  	id, ok := info.ID()
  1619  	if !ok {
  1620  		t.Skip("Map ID not supported")
  1621  	}
  1622  
  1623  	hash2, err := NewMapFromID(id)
  1624  	if err != nil {
  1625  		t.Fatalf("Can't get map for ID %d: %v", id, err)
  1626  	}
  1627  	hash2.Close()
  1628  
  1629  	// As there can be multiple maps, we use max(uint32) as MapID to trigger an expected error.
  1630  	_, err = NewMapFromID(MapID(math.MaxUint32))
  1631  	if !errors.Is(err, os.ErrNotExist) {
  1632  		t.Fatal("Expected ErrNotExist, got:", err)
  1633  	}
  1634  }
  1635  
  1636  func TestMapPinning(t *testing.T) {
  1637  	tmp := testutils.TempBPFFS(t)
  1638  	c := qt.New(t)
  1639  
  1640  	spec := &MapSpec{
  1641  		Name:       "test",
  1642  		Type:       Hash,
  1643  		KeySize:    4,
  1644  		ValueSize:  4,
  1645  		MaxEntries: 1,
  1646  		Pinning:    PinByName,
  1647  	}
  1648  
  1649  	m1, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
  1650  	if err != nil {
  1651  		t.Fatal("Can't create map:", err)
  1652  	}
  1653  	defer m1.Close()
  1654  	pinned := m1.IsPinned()
  1655  	c.Assert(pinned, qt.IsTrue)
  1656  
  1657  	m1Info, err := m1.Info()
  1658  	c.Assert(err, qt.IsNil)
  1659  
  1660  	if err := m1.Put(uint32(0), uint32(42)); err != nil {
  1661  		t.Fatal("Can't write value:", err)
  1662  	}
  1663  
  1664  	m2, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
  1665  	testutils.SkipIfNotSupported(t, err)
  1666  	if err != nil {
  1667  		t.Fatal("Can't create map:", err)
  1668  	}
  1669  	defer m2.Close()
  1670  
  1671  	m2Info, err := m2.Info()
  1672  	c.Assert(err, qt.IsNil)
  1673  
  1674  	if m1ID, ok := m1Info.ID(); ok {
  1675  		m2ID, _ := m2Info.ID()
  1676  		c.Assert(m2ID, qt.Equals, m1ID)
  1677  	}
  1678  
  1679  	var value uint32
  1680  	if err := m2.Lookup(uint32(0), &value); err != nil {
  1681  		t.Fatal("Can't read from map:", err)
  1682  	}
  1683  
  1684  	if value != 42 {
  1685  		t.Fatal("Pinning doesn't use pinned maps")
  1686  	}
  1687  
  1688  	spec.KeySize = 8
  1689  	m3, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp})
  1690  	if err == nil {
  1691  		m3.Close()
  1692  		t.Fatalf("Opening a pinned map with a mismatching spec did not fail")
  1693  	}
  1694  	if !errors.Is(err, ErrMapIncompatible) {
  1695  		t.Fatalf("Opening a pinned map with a mismatching spec failed with the wrong error")
  1696  	}
  1697  }
  1698  
  1699  type benchValue struct {
  1700  	ID      uint32
  1701  	Val16   uint16
  1702  	Val16_2 uint16
  1703  	Name    [8]byte
  1704  	LID     uint64
  1705  }
  1706  
  1707  type customBenchValue benchValue
  1708  
  1709  func (cbv *customBenchValue) UnmarshalBinary(buf []byte) error {
  1710  	cbv.ID = internal.NativeEndian.Uint32(buf)
  1711  	cbv.Val16 = internal.NativeEndian.Uint16(buf[4:])
  1712  	cbv.Val16_2 = internal.NativeEndian.Uint16(buf[6:])
  1713  	copy(cbv.Name[:], buf[8:])
  1714  	cbv.LID = internal.NativeEndian.Uint64(buf[16:])
  1715  	return nil
  1716  }
  1717  
  1718  func (cbv *customBenchValue) MarshalBinary() ([]byte, error) {
  1719  	buf := make([]byte, 24)
  1720  	internal.NativeEndian.PutUint32(buf, cbv.ID)
  1721  	internal.NativeEndian.PutUint16(buf[4:], cbv.Val16)
  1722  	internal.NativeEndian.PutUint16(buf[6:], cbv.Val16_2)
  1723  	copy(buf[8:], cbv.Name[:])
  1724  	internal.NativeEndian.PutUint64(buf[16:], cbv.LID)
  1725  	return buf, nil
  1726  }
  1727  
  1728  func BenchmarkMarshalling(b *testing.B) {
  1729  	newMap := func(valueSize uint32) *Map {
  1730  		m, err := NewMap(&MapSpec{
  1731  			Type:       Hash,
  1732  			KeySize:    8,
  1733  			ValueSize:  valueSize,
  1734  			MaxEntries: 1,
  1735  		})
  1736  		if err != nil {
  1737  			b.Fatal(err)
  1738  		}
  1739  		return m
  1740  	}
  1741  
  1742  	key := uint64(0)
  1743  
  1744  	m := newMap(24)
  1745  	if err := m.Put(key, benchValue{}); err != nil {
  1746  		b.Fatal(err)
  1747  	}
  1748  	b.Cleanup(func() { m.Close() })
  1749  
  1750  	b.Run("reflection", func(b *testing.B) {
  1751  		b.ReportAllocs()
  1752  		b.ResetTimer()
  1753  
  1754  		var value benchValue
  1755  
  1756  		for i := 0; i < b.N; i++ {
  1757  			err := m.Lookup(unsafe.Pointer(&key), &value)
  1758  			if err != nil {
  1759  				b.Fatal("Can't get key:", err)
  1760  			}
  1761  		}
  1762  	})
  1763  
  1764  	b.Run("custom", func(b *testing.B) {
  1765  		b.ReportAllocs()
  1766  		b.ResetTimer()
  1767  
  1768  		var value customBenchValue
  1769  
  1770  		for i := 0; i < b.N; i++ {
  1771  			err := m.Lookup(unsafe.Pointer(&key), &value)
  1772  			if err != nil {
  1773  				b.Fatal("Can't get key:", err)
  1774  			}
  1775  		}
  1776  	})
  1777  
  1778  	b.Run("unsafe", func(b *testing.B) {
  1779  		b.ReportAllocs()
  1780  		b.ResetTimer()
  1781  
  1782  		var value benchValue
  1783  
  1784  		for i := 0; i < b.N; i++ {
  1785  			err := m.Lookup(unsafe.Pointer(&key), unsafe.Pointer(&value))
  1786  			if err != nil {
  1787  				b.Fatal("Can't get key:", err)
  1788  			}
  1789  		}
  1790  	})
  1791  }
  1792  
  1793  func BenchmarkPerCPUMarshalling(b *testing.B) {
  1794  	newMap := func(valueSize uint32) *Map {
  1795  		m, err := NewMap(&MapSpec{
  1796  			Type:       PerCPUHash,
  1797  			KeySize:    8,
  1798  			ValueSize:  valueSize,
  1799  			MaxEntries: 1,
  1800  		})
  1801  		if err != nil {
  1802  			b.Fatal(err)
  1803  		}
  1804  		return m
  1805  	}
  1806  
  1807  	key := uint64(1)
  1808  	val := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
  1809  
  1810  	m := newMap(8)
  1811  	if err := m.Put(key, val[0:]); err != nil {
  1812  		b.Fatal(err)
  1813  	}
  1814  	b.Cleanup(func() { m.Close() })
  1815  
  1816  	b.Run("reflection", func(b *testing.B) {
  1817  		b.ReportAllocs()
  1818  		b.ResetTimer()
  1819  
  1820  		var value []uint64
  1821  
  1822  		for i := 0; i < b.N; i++ {
  1823  			err := m.Lookup(unsafe.Pointer(&key), &value)
  1824  			if err != nil {
  1825  				b.Fatal("Can't get key:", err)
  1826  			}
  1827  		}
  1828  	})
  1829  }
  1830  
  1831  func BenchmarkMap(b *testing.B) {
  1832  	m, err := NewMap(&MapSpec{
  1833  		Type:       Hash,
  1834  		KeySize:    4,
  1835  		ValueSize:  4,
  1836  		MaxEntries: 1,
  1837  	})
  1838  	if err != nil {
  1839  		b.Fatal(err)
  1840  	}
  1841  	b.Cleanup(func() { m.Close() })
  1842  
  1843  	if err := m.Put(uint32(0), uint32(42)); err != nil {
  1844  		b.Fatal(err)
  1845  	}
  1846  
  1847  	b.Run("Lookup", func(b *testing.B) {
  1848  		var key, value uint32
  1849  
  1850  		b.ReportAllocs()
  1851  
  1852  		for i := 0; i < b.N; i++ {
  1853  			err := m.Lookup(unsafe.Pointer(&key), unsafe.Pointer(&value))
  1854  			if err != nil {
  1855  				b.Fatal(err)
  1856  			}
  1857  		}
  1858  	})
  1859  
  1860  	b.Run("Update", func(b *testing.B) {
  1861  		var key, value uint32
  1862  
  1863  		b.ReportAllocs()
  1864  
  1865  		for i := 0; i < b.N; i++ {
  1866  			err := m.Update(unsafe.Pointer(&key), unsafe.Pointer(&value), UpdateAny)
  1867  			if err != nil {
  1868  				b.Fatal(err)
  1869  			}
  1870  		}
  1871  	})
  1872  
  1873  	b.Run("NextKey", func(b *testing.B) {
  1874  		var key uint32
  1875  
  1876  		b.ReportAllocs()
  1877  
  1878  		for i := 0; i < b.N; i++ {
  1879  			err := m.NextKey(nil, unsafe.Pointer(&key))
  1880  			if err != nil {
  1881  				b.Fatal(err)
  1882  			}
  1883  		}
  1884  	})
  1885  
  1886  	b.Run("Delete", func(b *testing.B) {
  1887  		var key uint32
  1888  
  1889  		b.ReportAllocs()
  1890  
  1891  		for i := 0; i < b.N; i++ {
  1892  			err := m.Delete(unsafe.Pointer(&key))
  1893  			if err != nil && !errors.Is(err, ErrKeyNotExist) {
  1894  				b.Fatal(err)
  1895  			}
  1896  		}
  1897  	})
  1898  }
  1899  
  1900  // Per CPU maps store a distinct value for each CPU. They are useful
  1901  // to collect metrics.
  1902  func ExampleMap_perCPU() {
  1903  	arr, err := NewMap(&MapSpec{
  1904  		Type:       PerCPUArray,
  1905  		KeySize:    4,
  1906  		ValueSize:  4,
  1907  		MaxEntries: 2,
  1908  	})
  1909  	if err != nil {
  1910  		panic(err)
  1911  	}
  1912  	defer arr.Close()
  1913  
  1914  	first := []uint32{4, 5}
  1915  	if err := arr.Put(uint32(0), first); err != nil {
  1916  		panic(err)
  1917  	}
  1918  
  1919  	second := []uint32{2, 8}
  1920  	if err := arr.Put(uint32(1), second); err != nil {
  1921  		panic(err)
  1922  	}
  1923  
  1924  	var values []uint32
  1925  	if err := arr.Lookup(uint32(0), &values); err != nil {
  1926  		panic(err)
  1927  	}
  1928  	fmt.Println("First two values:", values[:2])
  1929  
  1930  	var (
  1931  		key     uint32
  1932  		entries = arr.Iterate()
  1933  	)
  1934  
  1935  	for entries.Next(&key, &values) {
  1936  		// NB: sum can overflow, real code should check for this
  1937  		var sum uint32
  1938  		for _, n := range values {
  1939  			sum += n
  1940  		}
  1941  		fmt.Printf("Sum of %d: %d\n", key, sum)
  1942  	}
  1943  
  1944  	if err := entries.Err(); err != nil {
  1945  		panic(err)
  1946  	}
  1947  }
  1948  
  1949  // It is possible to use unsafe.Pointer to avoid marshalling
  1950  // and copy overhead. It is the resposibility of the caller to ensure
  1951  // the correct size of unsafe.Pointers.
  1952  //
  1953  // Note that using unsafe.Pointer is only marginally faster than
  1954  // implementing Marshaler on the type.
  1955  func ExampleMap_zeroCopy() {
  1956  	hash := createHash()
  1957  	defer hash.Close()
  1958  
  1959  	key := [5]byte{'h', 'e', 'l', 'l', 'o'}
  1960  	value := uint32(23)
  1961  
  1962  	if err := hash.Put(unsafe.Pointer(&key), unsafe.Pointer(&value)); err != nil {
  1963  		panic(err)
  1964  	}
  1965  
  1966  	value = 0
  1967  	if err := hash.Lookup(unsafe.Pointer(&key), unsafe.Pointer(&value)); err != nil {
  1968  		panic("can't get value:" + err.Error())
  1969  	}
  1970  
  1971  	fmt.Printf("The value is: %d\n", value)
  1972  	// Output: The value is: 23
  1973  }
  1974  
  1975  func createHash() *Map {
  1976  	hash, err := NewMap(&MapSpec{
  1977  		Type:       Hash,
  1978  		KeySize:    5,
  1979  		ValueSize:  4,
  1980  		MaxEntries: 10,
  1981  	})
  1982  	if err != nil {
  1983  		panic(err)
  1984  	}
  1985  	return hash
  1986  }
  1987  
  1988  func ExampleMap_NextKey() {
  1989  	hash := createHash()
  1990  	defer hash.Close()
  1991  
  1992  	if err := hash.Put("hello", uint32(21)); err != nil {
  1993  		panic(err)
  1994  	}
  1995  
  1996  	if err := hash.Put("world", uint32(42)); err != nil {
  1997  		panic(err)
  1998  	}
  1999  
  2000  	var firstKey string
  2001  	if err := hash.NextKey(nil, &firstKey); err != nil {
  2002  		panic(err)
  2003  	}
  2004  
  2005  	var nextKey string
  2006  	if err := hash.NextKey(firstKey, &nextKey); err != nil {
  2007  		panic(err)
  2008  	}
  2009  
  2010  	// Order of keys is non-deterministic due to randomized map seed
  2011  }
  2012  
  2013  // ExampleMap_Iterate demonstrates how to iterate over all entries
  2014  // in a map.
  2015  func ExampleMap_Iterate() {
  2016  	hash := createHash()
  2017  	defer hash.Close()
  2018  
  2019  	if err := hash.Put("hello", uint32(21)); err != nil {
  2020  		panic(err)
  2021  	}
  2022  
  2023  	if err := hash.Put("world", uint32(42)); err != nil {
  2024  		panic(err)
  2025  	}
  2026  
  2027  	var (
  2028  		key     string
  2029  		value   uint32
  2030  		entries = hash.Iterate()
  2031  	)
  2032  
  2033  	for entries.Next(&key, &value) {
  2034  		// Order of keys is non-deterministic due to randomized map seed
  2035  		fmt.Printf("key: %s, value: %d\n", key, value)
  2036  	}
  2037  
  2038  	if err := entries.Err(); err != nil {
  2039  		panic(fmt.Sprint("Iterator encountered an error:", err))
  2040  	}
  2041  }
  2042  
  2043  // It is possible to iterate nested maps and program arrays by
  2044  // unmarshaling into a *Map or *Program.
  2045  func ExampleMap_Iterate_nestedMapsAndProgramArrays() {
  2046  	var arrayOfMaps *Map // Set this up somehow
  2047  
  2048  	var (
  2049  		key     uint32
  2050  		m       *Map
  2051  		entries = arrayOfMaps.Iterate()
  2052  	)
  2053  
  2054  	// Make sure that the iterated map is closed after
  2055  	// we are done.
  2056  	defer m.Close()
  2057  
  2058  	for entries.Next(&key, &m) {
  2059  		// Order of keys is non-deterministic due to randomized map seed
  2060  		fmt.Printf("key: %v, map: %v\n", key, m)
  2061  	}
  2062  
  2063  	if err := entries.Err(); err != nil {
  2064  		panic(fmt.Sprint("Iterator encountered an error:", err))
  2065  	}
  2066  }