github.com/fafucoder/cilium@v1.6.11/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 }