github.com/elfadel/cilium@v1.6.12/pkg/bpf/map_linux_test.go (about)

     1  // Copyright 2018-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build privileged_tests
    16  
    17  package bpf
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"testing"
    23  	"unsafe"
    24  
    25  	. "gopkg.in/check.v1"
    26  
    27  	"github.com/cilium/cilium/pkg/checker"
    28  )
    29  
    30  // Hook up gocheck into the "go test" runner.
    31  func Test(t *testing.T) { TestingT(t) }
    32  
    33  type BPFPrivilegedTestSuite struct{}
    34  
    35  type TestKey struct {
    36  	Key uint32
    37  }
    38  type TestValue struct {
    39  	Value uint32
    40  }
    41  
    42  func (k *TestKey) String() string            { return fmt.Sprintf("key=%d", k.Key) }
    43  func (k *TestKey) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
    44  func (k *TestKey) NewValue() MapValue        { return &TestValue{} }
    45  func (k *TestKey) DeepCopyMapKey() MapKey    { return &TestKey{k.Key} }
    46  
    47  func (v *TestValue) String() string              { return fmt.Sprintf("value=%d", v.Value) }
    48  func (v *TestValue) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) }
    49  func (v *TestValue) DeepCopyMapValue() MapValue  { return &TestValue{v.Value} }
    50  
    51  var _ = Suite(&BPFPrivilegedTestSuite{})
    52  
    53  var (
    54  	maxEntries = 16
    55  
    56  	testMap = NewMap("cilium_test",
    57  		MapTypeHash,
    58  		&TestKey{},
    59  		int(unsafe.Sizeof(TestKey{})),
    60  		&TestValue{},
    61  		int(unsafe.Sizeof(TestValue{})),
    62  		maxEntries,
    63  		BPF_F_NO_PREALLOC,
    64  		0,
    65  		ConvertKeyValue,
    66  	).WithCache()
    67  )
    68  
    69  func runTests(m *testing.M) (int, error) {
    70  	CheckOrMountFS("")
    71  	if err := ConfigureResourceLimits(); err != nil {
    72  		return 1, fmt.Errorf("Failed to configure rlimit")
    73  	}
    74  
    75  	_, err := testMap.OpenOrCreate()
    76  	if err != nil {
    77  		return 1, fmt.Errorf("Failed to create map")
    78  	}
    79  	defer func() {
    80  		path, _ := testMap.Path()
    81  		os.Remove(path)
    82  	}()
    83  	defer testMap.Close()
    84  
    85  	return m.Run(), nil
    86  }
    87  
    88  func TestMain(m *testing.M) {
    89  	exitCode, err := runTests(m)
    90  	if err != nil {
    91  		log.Fatal(err)
    92  	}
    93  	os.Exit(exitCode)
    94  }
    95  
    96  func (s *BPFPrivilegedTestSuite) TestGetMapInfo(c *C) {
    97  	mi, err := GetMapInfo(os.Getpid(), testMap.GetFd())
    98  	c.Assert(err, IsNil)
    99  
   100  	// Check OpenMap warning section
   101  	testMap.MapKey = nil
   102  	testMap.MapValue = nil
   103  	defer func() {
   104  		testMap.MapKey = &TestKey{}
   105  		testMap.MapValue = &TestValue{}
   106  	}()
   107  	c.Assert(&testMap.MapInfo, checker.DeepEquals, mi)
   108  }
   109  
   110  func (s *BPFPrivilegedTestSuite) TestOpen(c *C) {
   111  	// Ensure that os.IsNotExist() can be used with Map.Open()
   112  	noSuchMap := NewMap("cilium_test_no_exist",
   113  		MapTypeHash, &TestKey{}, 4, &TestValue{}, 4, maxEntries, 0, 0, nil)
   114  	err := noSuchMap.Open()
   115  	c.Assert(os.IsNotExist(err), Equals, true)
   116  	c.Assert(err, ErrorMatches, ".*cilium_test_no_exist.*")
   117  
   118  	// existingMap is the same as testMap. Opening should succeed.
   119  	existingMap := NewMap("cilium_test",
   120  		MapTypeHash,
   121  		&TestKey{},
   122  		int(unsafe.Sizeof(TestKey{})),
   123  		&TestValue{},
   124  		int(unsafe.Sizeof(TestValue{})),
   125  		maxEntries,
   126  		BPF_F_NO_PREALLOC,
   127  		0,
   128  		ConvertKeyValue).WithCache()
   129  	err = existingMap.Open()
   130  	c.Check(err, IsNil)      // Avoid assert to ensure Close() is called below.
   131  	err = existingMap.Open() // Reopen should be no-op.
   132  	c.Check(err, IsNil)
   133  	err = existingMap.Close()
   134  	c.Assert(err, IsNil)
   135  }
   136  
   137  func (s *BPFPrivilegedTestSuite) TestOpenMap(c *C) {
   138  	openedMap, err := OpenMap("cilium_test_no_exist")
   139  	c.Assert(err, Not(IsNil))
   140  	c.Assert(openedMap, IsNil)
   141  
   142  	openedMap, err = OpenMap("cilium_test")
   143  	c.Assert(err, IsNil)
   144  
   145  	// Check OpenMap warning section
   146  	testMap.MapKey = nil
   147  	testMap.MapValue = nil
   148  	defer func() {
   149  		testMap.MapKey = &TestKey{}
   150  		testMap.MapValue = &TestValue{}
   151  	}()
   152  	noDiff := openedMap.DeepEquals(testMap)
   153  	c.Assert(noDiff, Equals, true)
   154  }
   155  
   156  func (s *BPFPrivilegedTestSuite) TestOpenOrCreate(c *C) {
   157  	// existingMap is the same as testMap. OpenOrCreate should skip recreation.
   158  	existingMap := NewMap("cilium_test",
   159  		MapTypeHash,
   160  		&TestKey{},
   161  		int(unsafe.Sizeof(TestKey{})),
   162  		&TestValue{},
   163  		int(unsafe.Sizeof(TestValue{})),
   164  		maxEntries,
   165  		BPF_F_NO_PREALLOC,
   166  		0,
   167  		ConvertKeyValue).WithCache()
   168  	isNew, err := existingMap.OpenOrCreate()
   169  	c.Assert(err, IsNil)
   170  	c.Assert(isNew, Equals, false)
   171  
   172  	// preallocMap unsets BPF_F_NO_PREALLOC. OpenOrCreate should recreate map.
   173  	EnableMapPreAllocation() // prealloc on/off is controllable in HASH map case.
   174  	preallocMap := NewMap("cilium_test",
   175  		MapTypeHash,
   176  		&TestKey{},
   177  		int(unsafe.Sizeof(TestKey{})),
   178  		&TestValue{},
   179  		int(unsafe.Sizeof(TestValue{})),
   180  		maxEntries,
   181  		0,
   182  		0,
   183  		ConvertKeyValue).WithCache()
   184  	isNew, err = preallocMap.OpenOrCreate()
   185  	defer preallocMap.Close()
   186  	c.Assert(err, IsNil)
   187  	c.Assert(isNew, Equals, true)
   188  	DisableMapPreAllocation()
   189  
   190  	// preallocMap is already open. OpenOrCreate does nothing.
   191  	isNew, err = preallocMap.OpenOrCreate()
   192  	c.Assert(err, IsNil)
   193  	c.Assert(isNew, Equals, false)
   194  }
   195  
   196  func (s *BPFPrivilegedTestSuite) TestOpenParallel(c *C) {
   197  	parallelMap := NewMap("cilium_test",
   198  		MapTypeHash,
   199  		&TestKey{},
   200  		int(unsafe.Sizeof(TestKey{})),
   201  		&TestValue{},
   202  		int(unsafe.Sizeof(TestValue{})),
   203  		maxEntries,
   204  		BPF_F_NO_PREALLOC,
   205  		0,
   206  		ConvertKeyValue).WithCache()
   207  	isNew, err := parallelMap.OpenParallel()
   208  	defer parallelMap.Close()
   209  	c.Assert(err, IsNil)
   210  	c.Assert(isNew, Equals, true)
   211  
   212  	isNew, err = parallelMap.OpenParallel()
   213  	c.Assert(isNew, Equals, false)
   214  	c.Assert(err, Not(IsNil))
   215  
   216  	// Check OpenMap warning section
   217  	noDiff := parallelMap.DeepEquals(testMap)
   218  	c.Assert(noDiff, Equals, true)
   219  
   220  	key1 := &TestKey{Key: 101}
   221  	value1 := &TestValue{Value: 201}
   222  	key2 := &TestKey{Key: 102}
   223  	value2 := &TestValue{Value: 202}
   224  
   225  	err = testMap.Update(key1, value1)
   226  	c.Assert(err, IsNil)
   227  	err = parallelMap.Update(key2, value2)
   228  	c.Assert(err, IsNil)
   229  
   230  	value, err := testMap.Lookup(key1)
   231  	c.Assert(err, IsNil)
   232  	c.Assert(value, checker.DeepEquals, value1)
   233  	value, err = testMap.Lookup(key2)
   234  	c.Assert(err, Not(IsNil))
   235  	c.Assert(value, IsNil)
   236  
   237  	value, err = parallelMap.Lookup(key1)
   238  	c.Assert(err, Not(IsNil))
   239  	c.Assert(value, IsNil)
   240  	value, err = parallelMap.Lookup(key2)
   241  	c.Assert(err, IsNil)
   242  	c.Assert(value, checker.DeepEquals, value2)
   243  
   244  	parallelMap.EndParallelMode()
   245  }
   246  
   247  func (s *BPFPrivilegedTestSuite) TestBasicManipulation(c *C) {
   248  	// existingMap is the same as testMap. Opening should succeed.
   249  	existingMap := NewMap("cilium_test",
   250  		MapTypeHash,
   251  		&TestKey{},
   252  		int(unsafe.Sizeof(TestKey{})),
   253  		&TestValue{},
   254  		int(unsafe.Sizeof(TestValue{})),
   255  		maxEntries,
   256  		BPF_F_NO_PREALLOC,
   257  		0,
   258  		ConvertKeyValue).WithCache()
   259  	err := existingMap.Open()
   260  	defer existingMap.Close()
   261  	c.Assert(err, IsNil)
   262  
   263  	key1 := &TestKey{Key: 103}
   264  	value1 := &TestValue{Value: 203}
   265  	key2 := &TestKey{Key: 104}
   266  	value2 := &TestValue{Value: 204}
   267  
   268  	err = existingMap.Update(key1, value1)
   269  	c.Assert(err, IsNil)
   270  	// key    val
   271  	// 103    203
   272  	value, err := existingMap.Lookup(key1)
   273  	c.Assert(err, IsNil)
   274  	c.Assert(value, checker.DeepEquals, value1)
   275  	value, err = existingMap.Lookup(key2)
   276  	c.Assert(err, Not(IsNil))
   277  	c.Assert(value, Equals, nil)
   278  
   279  	err = existingMap.Update(key1, value2)
   280  	c.Assert(err, IsNil)
   281  	// key    val
   282  	// 103    204
   283  	value, err = existingMap.Lookup(key1)
   284  	c.Assert(err, IsNil)
   285  	c.Assert(value, checker.DeepEquals, value2)
   286  
   287  	err = existingMap.Update(key2, value2)
   288  	c.Assert(err, IsNil)
   289  	// key    val
   290  	// 103    204
   291  	// 104    204
   292  	value, err = existingMap.Lookup(key1)
   293  	c.Assert(err, IsNil)
   294  	c.Assert(value, checker.DeepEquals, value2)
   295  	value, err = existingMap.Lookup(key2)
   296  	c.Assert(err, IsNil)
   297  	c.Assert(value, checker.DeepEquals, value2)
   298  
   299  	err = existingMap.Delete(key1)
   300  	c.Assert(err, IsNil)
   301  	// key    val
   302  	// 104    204
   303  	value, err = existingMap.Lookup(key1)
   304  	c.Assert(err, Not(IsNil))
   305  	c.Assert(value, Equals, nil)
   306  
   307  	err = existingMap.DeleteAll()
   308  	c.Assert(err, IsNil)
   309  	value, err = existingMap.Lookup(key1)
   310  	c.Assert(err, Not(IsNil))
   311  	c.Assert(value, Equals, nil)
   312  	err = existingMap.DeleteAll()
   313  	c.Assert(err, IsNil)
   314  }
   315  
   316  func (s *BPFPrivilegedTestSuite) TestDump(c *C) {
   317  	key1 := &TestKey{Key: 105}
   318  	value1 := &TestValue{Value: 205}
   319  	key2 := &TestKey{Key: 106}
   320  	value2 := &TestValue{Value: 206}
   321  
   322  	err := testMap.Update(key1, value1)
   323  	c.Assert(err, IsNil)
   324  	err = testMap.Update(key2, value1)
   325  	c.Assert(err, IsNil)
   326  	err = testMap.Update(key2, value2)
   327  	c.Assert(err, IsNil)
   328  
   329  	dump1 := map[string][]string{}
   330  	testMap.Dump(dump1)
   331  	c.Assert(dump1, checker.DeepEquals, map[string][]string{
   332  		"key=105": {"value=205"},
   333  		"key=106": {"value=206"},
   334  	})
   335  
   336  	dump2 := map[string][]string{}
   337  	customCb := func(key MapKey, value MapValue) {
   338  		dump2[key.String()] = append(dump2[key.String()], "custom-"+value.String())
   339  	}
   340  	testMap.DumpWithCallback(customCb)
   341  	c.Assert(dump2, checker.DeepEquals, map[string][]string{
   342  		"key=105": {"custom-value=205"},
   343  		"key=106": {"custom-value=206"},
   344  	})
   345  
   346  	dump3 := map[string][]string{}
   347  	noSuchMap := NewMap("cilium_test_no_exist",
   348  		MapTypeHash, &TestKey{}, 4, &TestValue{}, 4, maxEntries, 0, 0, nil)
   349  	err = noSuchMap.DumpIfExists(dump3)
   350  	c.Assert(err, IsNil)
   351  	c.Assert(len(dump3), Equals, 0)
   352  
   353  	dump2 = map[string][]string{}
   354  	err = noSuchMap.DumpWithCallbackIfExists(customCb)
   355  	c.Assert(err, IsNil)
   356  	c.Assert(len(dump2), Equals, 0)
   357  
   358  	// Validate that if the key is zero, it shows up in dump output.
   359  	keyZero := &TestKey{Key: 0}
   360  	valueZero := &TestValue{Value: 0}
   361  	err = testMap.Update(keyZero, valueZero)
   362  	c.Assert(err, IsNil)
   363  
   364  	dump4 := map[string][]string{}
   365  	customCb = func(key MapKey, value MapValue) {
   366  		dump4[key.String()] = append(dump4[key.String()], "custom-"+value.String())
   367  	}
   368  	ds := NewDumpStats(testMap)
   369  	err = testMap.DumpReliablyWithCallback(customCb, ds)
   370  	c.Assert(err, IsNil)
   371  	c.Assert(dump4, checker.DeepEquals, map[string][]string{
   372  		"key=0":   {"custom-value=0"},
   373  		"key=105": {"custom-value=205"},
   374  		"key=106": {"custom-value=206"},
   375  	})
   376  
   377  	dump5 := map[string][]string{}
   378  	err = testMap.Dump(dump5)
   379  	c.Assert(err, IsNil)
   380  	c.Assert(dump5, checker.DeepEquals, map[string][]string{
   381  		"key=0":   {"value=0"},
   382  		"key=105": {"value=205"},
   383  		"key=106": {"value=206"},
   384  	})
   385  }
   386  
   387  func (s *BPFPrivilegedTestSuite) TestDeleteAll(c *C) {
   388  	key1 := &TestKey{Key: 105}
   389  	value1 := &TestValue{Value: 205}
   390  	key2 := &TestKey{Key: 106}
   391  	value2 := &TestValue{Value: 206}
   392  
   393  	err := testMap.Update(key1, value1)
   394  	c.Assert(err, IsNil)
   395  	err = testMap.Update(key2, value1)
   396  	c.Assert(err, IsNil)
   397  	err = testMap.Update(key2, value2)
   398  	c.Assert(err, IsNil)
   399  
   400  	keyZero := &TestKey{Key: 0}
   401  	valueZero := &TestValue{Value: 0}
   402  	err = testMap.Update(keyZero, valueZero)
   403  	c.Assert(err, IsNil)
   404  
   405  	dump1 := map[string][]string{}
   406  	err = testMap.Dump(dump1)
   407  	c.Assert(err, IsNil)
   408  	c.Assert(dump1, checker.DeepEquals, map[string][]string{
   409  		"key=0":   {"value=0"},
   410  		"key=105": {"value=205"},
   411  		"key=106": {"value=206"},
   412  	})
   413  
   414  	err = testMap.DeleteAll()
   415  	c.Assert(err, IsNil)
   416  
   417  	dump2 := map[string][]string{}
   418  	err = testMap.Dump(dump2)
   419  	c.Assert(err, IsNil)
   420  }
   421  
   422  func (s *BPFPrivilegedTestSuite) TestGetModel(c *C) {
   423  	model := testMap.GetModel()
   424  	c.Assert(model, Not(IsNil))
   425  }
   426  
   427  func (s *BPFPrivilegedTestSuite) TestCheckAndUpgrade(c *C) {
   428  	// CheckAndUpgrade removes map file if upgrade is needed
   429  	// so we setup and use another map.
   430  	upgradeMap := NewMap("cilium_test_upgrade",
   431  		MapTypeHash,
   432  		&TestKey{},
   433  		int(unsafe.Sizeof(TestKey{})),
   434  		&TestValue{},
   435  		int(unsafe.Sizeof(TestValue{})),
   436  		maxEntries,
   437  		BPF_F_NO_PREALLOC,
   438  		0,
   439  		ConvertKeyValue).WithCache()
   440  	_, err := upgradeMap.OpenOrCreate()
   441  	c.Assert(err, IsNil)
   442  	defer func() {
   443  		path, _ := upgradeMap.Path()
   444  		os.Remove(path)
   445  	}()
   446  	defer upgradeMap.Close()
   447  
   448  	// Exactly the same MapInfo so it won't be upgraded.
   449  	upgrade := upgradeMap.CheckAndUpgrade(&upgradeMap.MapInfo)
   450  	c.Assert(upgrade, Equals, false)
   451  
   452  	// preallocMap unsets BPF_F_NO_PREALLOC so upgrade is needed.
   453  	EnableMapPreAllocation()
   454  	preallocMap := NewMap("cilium_test_upgrade",
   455  		MapTypeHash,
   456  		&TestKey{},
   457  		int(unsafe.Sizeof(TestKey{})),
   458  		&TestValue{},
   459  		int(unsafe.Sizeof(TestValue{})),
   460  		maxEntries,
   461  		0,
   462  		0,
   463  		ConvertKeyValue).WithCache()
   464  	upgrade = upgradeMap.CheckAndUpgrade(&preallocMap.MapInfo)
   465  	c.Assert(upgrade, Equals, true)
   466  	DisableMapPreAllocation()
   467  }
   468  
   469  func (s *BPFPrivilegedTestSuite) TestUnpin(c *C) {
   470  	var exist bool
   471  	unpinMap := NewMap("cilium_test_unpin",
   472  		MapTypeHash,
   473  		&TestKey{},
   474  		int(unsafe.Sizeof(TestKey{})),
   475  		&TestValue{},
   476  		int(unsafe.Sizeof(TestValue{})),
   477  		maxEntries,
   478  		BPF_F_NO_PREALLOC,
   479  		0,
   480  		ConvertKeyValue).WithCache()
   481  	_, err := unpinMap.OpenOrCreate()
   482  	c.Assert(err, IsNil)
   483  	exist, err = unpinMap.exist()
   484  	c.Assert(err, IsNil)
   485  	c.Assert(exist, Equals, true)
   486  
   487  	err = unpinMap.Unpin()
   488  	c.Assert(err, IsNil)
   489  	exist, err = unpinMap.exist()
   490  	c.Assert(err, IsNil)
   491  	c.Assert(exist, Equals, false)
   492  
   493  	err = unpinMap.UnpinIfExists()
   494  	c.Assert(err, IsNil)
   495  	exist, err = unpinMap.exist()
   496  	c.Assert(err, IsNil)
   497  	c.Assert(exist, Equals, false)
   498  }