...

Source file src/github.com/cilium/ebpf/map_test.go

Documentation: github.com/cilium/ebpf

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

View as plain text