github.com/imran-kn/cilium-fork@v1.6.9/pkg/bpf/map_linux.go (about) 1 // Copyright 2016-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 linux 16 17 package bpf 18 19 import ( 20 "bufio" 21 "context" 22 "fmt" 23 "os" 24 "path" 25 "reflect" 26 "sync" 27 "syscall" 28 "time" 29 "unsafe" 30 31 "github.com/cilium/cilium/api/v1/models" 32 "github.com/cilium/cilium/pkg/bpf/binary" 33 "github.com/cilium/cilium/pkg/byteorder" 34 "github.com/cilium/cilium/pkg/controller" 35 "github.com/cilium/cilium/pkg/lock" 36 "github.com/cilium/cilium/pkg/logging/logfields" 37 "github.com/cilium/cilium/pkg/metrics" 38 "github.com/cilium/cilium/pkg/option" 39 40 "github.com/sirupsen/logrus" 41 "golang.org/x/sys/unix" 42 ) 43 44 type MapKey interface { 45 fmt.Stringer 46 47 // Returns pointer to start of key 48 GetKeyPtr() unsafe.Pointer 49 50 // Allocates a new value matching the key type 51 NewValue() MapValue 52 53 // DeepCopyMapKey returns a deep copy of the map key 54 DeepCopyMapKey() MapKey 55 } 56 57 type MapValue interface { 58 fmt.Stringer 59 60 // Returns pointer to start of value 61 GetValuePtr() unsafe.Pointer 62 63 // DeepCopyMapValue returns a deep copy of the map value 64 DeepCopyMapValue() MapValue 65 } 66 67 type MapInfo struct { 68 MapType MapType 69 MapKey MapKey 70 KeySize uint32 71 MapValue MapValue 72 // ReadValueSize is the value size that is used to read from the BPF maps 73 // this value an the ValueSize values can be different for BPF_MAP_TYPE_PERCPU_HASH 74 // for example. 75 ReadValueSize uint32 76 ValueSize uint32 77 MaxEntries uint32 78 Flags uint32 79 InnerID uint32 80 OwnerProgType ProgType 81 } 82 83 type cacheEntry struct { 84 Key MapKey 85 Value MapValue 86 87 DesiredAction DesiredAction 88 LastError error 89 } 90 91 type Map struct { 92 MapInfo 93 fd int 94 name string 95 path string 96 once sync.Once 97 lock lock.RWMutex 98 99 // inParallelMode is true when the Map is currently being run in 100 // parallel and all modifications are performed on both maps until 101 // EndParallelMode() is called. 102 inParallelMode bool 103 104 // cachedCommonName is the common portion of the name excluding any 105 // endpoint ID 106 cachedCommonName string 107 108 // enableSync is true when synchronization retries have been enabled. 109 enableSync bool 110 111 // openLock serializes calls to Map.Open() 112 openLock lock.Mutex 113 114 // NonPersistent is true if the map does not contain persistent data 115 // and should be removed on startup. 116 NonPersistent bool 117 118 // DumpParser is a function for parsing keys and values from BPF maps 119 dumpParser DumpParser 120 121 cache map[string]*cacheEntry 122 123 // errorResolverLastScheduled is the timestamp when the error resolver 124 // was last scheduled 125 errorResolverLastScheduled time.Time 126 127 // outstandingErrors is the number of outsanding errors syncing with 128 // the kernel 129 outstandingErrors int 130 } 131 132 // NewMap creates a new Map instance - object representing a BPF map 133 func NewMap(name string, mapType MapType, mapKey MapKey, keySize int, mapValue MapValue, valueSize, maxEntries int, flags uint32, innerID uint32, dumpParser DumpParser) *Map { 134 m := &Map{ 135 MapInfo: MapInfo{ 136 MapType: mapType, 137 MapKey: mapKey, 138 KeySize: uint32(keySize), 139 MapValue: mapValue, 140 ReadValueSize: uint32(valueSize), 141 ValueSize: uint32(valueSize), 142 MaxEntries: uint32(maxEntries), 143 Flags: flags, 144 InnerID: innerID, 145 OwnerProgType: ProgTypeUnspec, 146 }, 147 name: path.Base(name), 148 dumpParser: dumpParser, 149 } 150 return m 151 } 152 153 // NewPerCPUHashMap creates a new Map type of "per CPU hash" - object representing a BPF map 154 // The number of cpus is used to have the size representation of a value when 155 // a lookup is made on this map types. 156 func NewPerCPUHashMap(name string, mapKey MapKey, keySize int, mapValue MapValue, valueSize, cpus, maxEntries int, flags uint32, innerID uint32, dumpParser DumpParser) *Map { 157 m := &Map{ 158 MapInfo: MapInfo{ 159 MapType: BPF_MAP_TYPE_PERCPU_HASH, 160 MapKey: mapKey, 161 KeySize: uint32(keySize), 162 MapValue: mapValue, 163 ReadValueSize: uint32(valueSize * cpus), 164 ValueSize: uint32(valueSize), 165 MaxEntries: uint32(maxEntries), 166 Flags: flags, 167 InnerID: innerID, 168 OwnerProgType: ProgTypeUnspec, 169 }, 170 name: path.Base(name), 171 dumpParser: dumpParser, 172 } 173 return m 174 } 175 176 // WithNonPersistent turns the map non-persistent and returns the map 177 func (m *Map) WithNonPersistent() *Map { 178 m.NonPersistent = true 179 return m 180 } 181 182 func (m *Map) commonName() string { 183 if m.cachedCommonName != "" { 184 return m.cachedCommonName 185 } 186 187 m.cachedCommonName = extractCommonName(m.name) 188 return m.cachedCommonName 189 } 190 191 // scheduleErrorResolver schedules a periodic resolver controller that scans 192 // all BPF map caches for unresolved errors and attempts to resolve them. On 193 // error of resolution, the controller is-rescheduled in an expedited manner 194 // with an exponential back-off. 195 // 196 // m.lock must be held for writing 197 func (m *Map) scheduleErrorResolver() { 198 m.outstandingErrors++ 199 200 if time.Since(m.errorResolverLastScheduled) <= errorResolverSchedulerMinInterval { 201 return 202 } 203 204 m.errorResolverLastScheduled = time.Now() 205 206 go func() { 207 time.Sleep(errorResolverSchedulerDelay) 208 mapControllers.UpdateController(m.controllerName(), 209 controller.ControllerParams{ 210 DoFunc: m.resolveErrors, 211 RunInterval: errorResolverSchedulerMinInterval, 212 }, 213 ) 214 }() 215 216 } 217 218 // WithCache enables use of a cache. This will store all entries inserted from 219 // user space in a local cache (map) and will indicate the status of each 220 // individual entry. 221 func (m *Map) WithCache() *Map { 222 m.cache = map[string]*cacheEntry{} 223 m.enableSync = true 224 return m 225 } 226 227 func (m *Map) GetFd() int { 228 return m.fd 229 } 230 231 // Name returns the basename of this map. 232 func (m *Map) Name() string { 233 return m.name 234 } 235 236 // Path returns the path to this map on the filesystem. 237 func (m *Map) Path() (string, error) { 238 if err := m.setPathIfUnset(); err != nil { 239 return "", err 240 } 241 242 return m.path, nil 243 } 244 245 // Unpin attempts to unpin (remove) the map from the filesystem. 246 func (m *Map) Unpin() error { 247 path, err := m.Path() 248 if err != nil { 249 return err 250 } 251 252 return os.RemoveAll(path) 253 } 254 255 // UnpinIfExists tries to unpin (remove) the map only if it exists. 256 func (m *Map) UnpinIfExists() error { 257 found, err := m.exist() 258 if err != nil { 259 return err 260 } 261 262 if !found { 263 return nil 264 } 265 266 return m.Unpin() 267 } 268 269 // DeepEquals compares the current map against another map to see that the 270 // attributes of the two maps are the same. 271 func (m *Map) DeepEquals(other *Map) bool { 272 return m.name == other.name && 273 m.path == other.path && 274 m.NonPersistent == other.NonPersistent && 275 reflect.DeepEqual(m.MapInfo, other.MapInfo) 276 } 277 278 func (m *Map) controllerName() string { 279 return fmt.Sprintf("bpf-map-sync-%s", m.name) 280 } 281 282 func GetMapInfo(pid int, fd int) (*MapInfo, error) { 283 284 fdinfoFile := fmt.Sprintf("/proc/%d/fdinfo/%d", pid, fd) 285 286 file, err := os.Open(fdinfoFile) 287 if err != nil { 288 return nil, err 289 } 290 defer file.Close() 291 292 info := &MapInfo{} 293 294 scanner := bufio.NewScanner(file) 295 scanner.Split(bufio.ScanLines) 296 for scanner.Scan() { 297 var value int 298 299 line := scanner.Text() 300 if n, err := fmt.Sscanf(line, "map_type:\t%d", &value); n == 1 && err == nil { 301 info.MapType = MapType(value) 302 } else if n, err := fmt.Sscanf(line, "key_size:\t%d", &value); n == 1 && err == nil { 303 info.KeySize = uint32(value) 304 } else if n, err := fmt.Sscanf(line, "value_size:\t%d", &value); n == 1 && err == nil { 305 info.ValueSize = uint32(value) 306 info.ReadValueSize = uint32(value) 307 } else if n, err := fmt.Sscanf(line, "max_entries:\t%d", &value); n == 1 && err == nil { 308 info.MaxEntries = uint32(value) 309 } else if n, err := fmt.Sscanf(line, "map_flags:\t0x%x", &value); n == 1 && err == nil { 310 info.Flags = uint32(value) 311 } else if n, err := fmt.Sscanf(line, "owner_prog_type:\t%d", &value); n == 1 && err == nil { 312 info.OwnerProgType = ProgType(value) 313 } 314 } 315 316 if scanner.Err() != nil { 317 return nil, scanner.Err() 318 } 319 320 return info, nil 321 } 322 323 // OpenMap opens the given bpf map and generates the Map info based in the 324 // information stored in the bpf map. 325 // *Warning*: Calling this function requires the caller to properly setup 326 // the MapInfo.MapKey and MapInfo.MapValues fields as those structures are not 327 // stored in the bpf map. 328 func OpenMap(name string) (*Map, error) { 329 // Expand path if needed 330 if !path.IsAbs(name) { 331 name = MapPath(name) 332 } 333 334 fd, err := ObjGet(name) 335 if err != nil { 336 return nil, err 337 } 338 339 info, err := GetMapInfo(os.Getpid(), fd) 340 if err != nil { 341 return nil, err 342 } 343 344 if info.MapType == 0 { 345 return nil, fmt.Errorf("Unable to determine map type") 346 } 347 348 if info.KeySize == 0 { 349 return nil, fmt.Errorf("Unable to determine map key size") 350 } 351 352 m := &Map{ 353 MapInfo: *info, 354 fd: fd, 355 name: path.Base(name), 356 path: name, 357 } 358 359 registerMap(name, m) 360 361 return m, nil 362 } 363 364 func (m *Map) setPathIfUnset() error { 365 if m.path == "" { 366 if m.name == "" { 367 return fmt.Errorf("either path or name must be set") 368 } 369 370 m.path = MapPath(m.name) 371 } 372 373 return nil 374 } 375 376 // EndParallelMode ends the parallel mode of a map 377 func (m *Map) EndParallelMode() { 378 m.lock.Lock() 379 defer m.lock.Unlock() 380 381 if m.inParallelMode { 382 m.inParallelMode = false 383 m.scopedLogger().Debug("End of parallel mode") 384 } 385 } 386 387 // OpenParallel is similar to OpenOrCreate() but prepares the existing map to 388 // be faded out while a new map is taking over. This can be used if a map is 389 // shared between multiple consumers and the context of the shared map is 390 // changing. Any update to the shared map would impact all consumers and 391 // consumers can only be updated one by one. Parallel mode allows for consumers 392 // to continue using the old version of the map until the consumer is updated 393 // to use the new version. 394 func (m *Map) OpenParallel() (bool, error) { 395 m.lock.Lock() 396 defer m.lock.Unlock() 397 398 if m.fd != 0 { 399 return false, fmt.Errorf("OpenParallel() called on already open map") 400 } 401 402 if err := m.setPathIfUnset(); err != nil { 403 return false, err 404 } 405 406 if _, err := os.Stat(m.path); err == nil { 407 err := os.Remove(m.path) 408 if err != nil { 409 log.WithError(err).Warning("Unable to remove BPF map for parallel operation") 410 // Fall back to non-parallel mode 411 } else { 412 m.scopedLogger().Debug("Opening map in parallel mode") 413 m.inParallelMode = true 414 } 415 } 416 417 return m.openOrCreate(true) 418 } 419 420 // OpenOrCreate attempts to open the Map, or if it does not yet exist, create 421 // the Map. If the existing map's attributes such as map type, key/value size, 422 // capacity, etc. do not match the Map's attributes, then the map will be 423 // deleted and reopened without any attempt to retain its previous contents. 424 // If the map is marked as non-persistent, it will always be recreated. 425 // 426 // If the map type is MapTypeLRUHash or MapTypeLPMTrie and the kernel lacks 427 // support for this map type, then the map will be opened as MapTypeHash 428 // instead. Note that the BPF code that interacts with this map *MUST* be 429 // structured in such a way that the map is declared as the same type based on 430 // the same probe logic (eg HAVE_LRU_MAP_TYPE, HAVE_LPM_MAP_TYPE). 431 // 432 // For code that uses an LPMTrie, the BPF code must also use macros to retain 433 // the "longest prefix match" behaviour on top of the hash maps, for example 434 // via LPM_LOOKUP_FN() (see bpf/lib/maps.h). 435 // 436 // To detect map type support properly, this function must be called after 437 // a call to ReadFeatureProbes(); failure to do so will result in LPM or LRU 438 // map types being unconditionally opened as hash maps. 439 // 440 // Returns whether the map was deleted and recreated, or an optional error. 441 func (m *Map) OpenOrCreate() (bool, error) { 442 m.lock.Lock() 443 defer m.lock.Unlock() 444 445 return m.openOrCreate(true) 446 } 447 448 // OpenOrCreateUnpinned is similar to OpenOrCreate (see above) but without 449 // pinning the map to the file system if it had to be created. 450 func (m *Map) OpenOrCreateUnpinned() (bool, error) { 451 m.lock.Lock() 452 defer m.lock.Unlock() 453 454 return m.openOrCreate(false) 455 } 456 457 func (m *Map) openOrCreate(pin bool) (bool, error) { 458 if m.fd != 0 { 459 return false, nil 460 } 461 462 if err := m.setPathIfUnset(); err != nil { 463 return false, err 464 } 465 466 // If the map represents non-persistent data, always remove the map 467 // before opening or creating. 468 if m.NonPersistent { 469 os.Remove(m.path) 470 } 471 472 mapType := GetMapType(m.MapType) 473 flags := m.Flags | GetPreAllocateMapFlags(mapType) 474 fd, isNew, err := OpenOrCreateMap(m.path, int(mapType), m.KeySize, m.ValueSize, m.MaxEntries, flags, m.InnerID, pin) 475 if err != nil { 476 return false, err 477 } 478 479 registerMap(m.path, m) 480 481 m.fd = fd 482 m.MapType = mapType 483 m.Flags = flags 484 return isNew, nil 485 } 486 487 func (m *Map) Open() error { 488 m.openLock.Lock() 489 defer m.openLock.Unlock() 490 491 if m.fd != 0 { 492 return nil 493 } 494 495 if err := m.setPathIfUnset(); err != nil { 496 return err 497 } 498 499 fd, err := ObjGet(m.path) 500 if err != nil { 501 return err 502 } 503 504 registerMap(m.path, m) 505 506 m.fd = fd 507 m.MapType = GetMapType(m.MapType) 508 return nil 509 } 510 511 func (m *Map) Close() error { 512 m.lock.Lock() 513 defer m.lock.Unlock() 514 515 if m.enableSync { 516 mapControllers.RemoveController(m.controllerName()) 517 } 518 519 if m.fd != 0 { 520 unix.Close(m.fd) 521 m.fd = 0 522 } 523 524 unregisterMap(m.path, m) 525 526 return nil 527 } 528 529 // Reopen attempts to close and re-open the received map. 530 func (m *Map) Reopen() error { 531 m.Close() 532 return m.Open() 533 } 534 535 type DumpParser func(key []byte, value []byte, mapKey MapKey, mapValue MapValue) (MapKey, MapValue, error) 536 type DumpCallback func(key MapKey, value MapValue) 537 type MapValidator func(path string) (bool, error) 538 539 // DumpWithCallback iterates over the Map and calls the given callback 540 // function on each iteration. That callback function is receiving the 541 // actual key and value. The callback function should consider creating a 542 // deepcopy of the key and value on between each iterations to avoid memory 543 // corruption. 544 func (m *Map) DumpWithCallback(cb DumpCallback) error { 545 m.lock.RLock() 546 defer m.lock.RUnlock() 547 548 key := make([]byte, m.KeySize) 549 nextKey := make([]byte, m.KeySize) 550 value := make([]byte, m.ReadValueSize) 551 552 if err := m.Open(); err != nil { 553 return err 554 } 555 556 if err := GetFirstKey(m.fd, unsafe.Pointer(&nextKey[0])); err != nil { 557 return nil 558 } 559 560 mk := m.MapKey.DeepCopyMapKey() 561 mv := m.MapValue.DeepCopyMapValue() 562 563 bpfCurrentKey := bpfAttrMapOpElem{ 564 mapFd: uint32(m.fd), 565 key: uint64(uintptr(unsafe.Pointer(&key[0]))), 566 value: uint64(uintptr(unsafe.Pointer(&nextKey[0]))), 567 } 568 bpfCurrentKeyPtr := unsafe.Pointer(&bpfCurrentKey) 569 bpfCurrentKeySize := unsafe.Sizeof(bpfCurrentKey) 570 571 bpfNextKey := bpfAttrMapOpElem{ 572 mapFd: uint32(m.fd), 573 key: uint64(uintptr(unsafe.Pointer(&nextKey[0]))), 574 value: uint64(uintptr(unsafe.Pointer(&value[0]))), 575 } 576 577 bpfNextKeyPtr := unsafe.Pointer(&bpfNextKey) 578 bpfNextKeySize := unsafe.Sizeof(bpfNextKey) 579 580 for { 581 err := LookupElementFromPointers(m.fd, bpfNextKeyPtr, bpfNextKeySize) 582 if err != nil { 583 return err 584 } 585 586 mk, mv, err = m.dumpParser(nextKey, value, mk, mv) 587 if err != nil { 588 return err 589 } 590 591 if cb != nil { 592 cb(mk, mv) 593 } 594 595 copy(key, nextKey) 596 597 err = GetNextKeyFromPointers(m.fd, bpfCurrentKeyPtr, bpfCurrentKeySize) 598 if err != nil { 599 break 600 } 601 } 602 return nil 603 } 604 605 // DumpWithCallbackIfExists is similar to DumpWithCallback, but returns earlier 606 // if the given map does not exist. 607 func (m *Map) DumpWithCallbackIfExists(cb DumpCallback) error { 608 found, err := m.exist() 609 if err != nil { 610 return err 611 } 612 613 if found { 614 return m.DumpWithCallback(cb) 615 } 616 617 return nil 618 } 619 620 // DumpReliablyWithCallback is similar to DumpWithCallback, but performs 621 // additional tracking of the current and recently seen keys, so that if an 622 // element is removed from the underlying kernel map during the dump, the dump 623 // can continue from a recently seen key rather than restarting from scratch. 624 // In addition, it caps the maximum number of map entry iterations by the 625 // maximum size of the map. 626 // 627 // The caller must provide a callback for handling each entry, and a stats 628 // object initialized via a call to NewDumpStats(). 629 func (m *Map) DumpReliablyWithCallback(cb DumpCallback, stats *DumpStats) error { 630 var ( 631 prevKey = make([]byte, m.KeySize) 632 currentKey = make([]byte, m.KeySize) 633 nextKey = make([]byte, m.KeySize) 634 value = make([]byte, m.ReadValueSize) 635 636 prevKeyValid = false 637 ) 638 stats.start() 639 defer stats.finish() 640 641 if err := m.Open(); err != nil { 642 return err 643 } 644 645 err := GetFirstKey(m.fd, unsafe.Pointer(¤tKey[0])) 646 if err != nil { 647 // Map is empty, nothing to clean up. 648 stats.Lookup = 1 649 stats.Completed = true 650 return nil 651 } 652 653 mk := m.MapKey.DeepCopyMapKey() 654 mv := m.MapValue.DeepCopyMapValue() 655 656 bpfCurrentKey := bpfAttrMapOpElem{ 657 mapFd: uint32(m.fd), 658 key: uint64(uintptr(unsafe.Pointer(¤tKey[0]))), 659 value: uint64(uintptr(unsafe.Pointer(&value[0]))), 660 } 661 bpfCurrentKeyPtr := unsafe.Pointer(&bpfCurrentKey) 662 bpfCurrentKeySize := unsafe.Sizeof(bpfCurrentKey) 663 664 bpfNextKey := bpfAttrMapOpElem{ 665 mapFd: uint32(m.fd), 666 key: uint64(uintptr(unsafe.Pointer(¤tKey[0]))), 667 value: uint64(uintptr(unsafe.Pointer(&nextKey[0]))), 668 } 669 670 bpfNextKeyPtr := unsafe.Pointer(&bpfNextKey) 671 bpfNextKeySize := unsafe.Sizeof(bpfNextKey) 672 673 for stats.Lookup = 1; stats.Lookup <= stats.MaxEntries; stats.Lookup++ { 674 // currentKey was returned by GetNextKey() so we know it existed in the map, but it may have been 675 // deleted by a concurrent map operation. If currentKey is no longer in the map, nextKey will be 676 // the first key in the map again. Use the nextKey only if we still find currentKey in the Lookup() 677 // after the GetNextKey() call, this way we know nextKey is NOT the first key in the map. 678 nextKeyValid := GetNextKeyFromPointers(m.fd, bpfNextKeyPtr, bpfNextKeySize) 679 err := LookupElementFromPointers(m.fd, bpfCurrentKeyPtr, bpfCurrentKeySize) 680 if err != nil { 681 stats.LookupFailed++ 682 683 // Restarting from a invalid key starts the iteration again from the beginning. 684 // If we have a previously found key, try to restart from there instead 685 if prevKeyValid { 686 copy(currentKey, prevKey) 687 // Restart from a given previous key only once, otherwise if the prevKey is 688 // concurrently deleted we might loop forever trying to look it up. 689 prevKeyValid = false 690 stats.KeyFallback++ 691 } else { 692 // Depending on exactly when currentKey was deleted from the map, nextKey may be the actual 693 // keyelement after the deleted one, or the first element in the map. 694 copy(currentKey, nextKey) 695 stats.Interrupted++ 696 } 697 continue 698 } 699 700 mk, mv, err = m.dumpParser(currentKey, value, mk, mv) 701 if err != nil { 702 stats.Interrupted++ 703 return err 704 } 705 706 if cb != nil { 707 cb(mk, mv) 708 } 709 710 if nextKeyValid != nil { 711 stats.Completed = true 712 break 713 } 714 // remember the last found key 715 copy(prevKey, currentKey) 716 prevKeyValid = true 717 // continue from the next key 718 copy(currentKey, nextKey) 719 } 720 721 return nil 722 } 723 724 // Dump returns the map (type map[string][]string) which contains all 725 // data stored in BPF map. 726 func (m *Map) Dump(hash map[string][]string) error { 727 callback := func(key MapKey, value MapValue) { 728 // No need to deep copy since we are creating strings. 729 hash[key.String()] = append(hash[key.String()], value.String()) 730 } 731 732 if err := m.DumpWithCallback(callback); err != nil { 733 return err 734 } 735 736 return nil 737 } 738 739 // DumpIfExists dumps the contents of the map into hash via Dump() if the map 740 // file exists 741 func (m *Map) DumpIfExists(hash map[string][]string) error { 742 found, err := m.exist() 743 if err != nil { 744 return err 745 } 746 747 if found { 748 return m.Dump(hash) 749 } 750 751 return nil 752 } 753 754 func (m *Map) Lookup(key MapKey) (MapValue, error) { 755 m.lock.RLock() 756 defer m.lock.RUnlock() 757 758 value := key.NewValue() 759 760 if err := m.Open(); err != nil { 761 return nil, err 762 } 763 764 err := LookupElement(m.fd, key.GetKeyPtr(), value.GetValuePtr()) 765 if err != nil { 766 return nil, err 767 } 768 return value, nil 769 } 770 771 func (m *Map) Update(key MapKey, value MapValue) error { 772 var err error 773 774 m.lock.Lock() 775 defer m.lock.Unlock() 776 777 defer func() { 778 if m.cache == nil { 779 return 780 } 781 782 desiredAction := OK 783 if err != nil { 784 desiredAction = Insert 785 m.scheduleErrorResolver() 786 } 787 788 m.cache[key.String()] = &cacheEntry{ 789 Key: key, 790 Value: value, 791 DesiredAction: desiredAction, 792 LastError: err, 793 } 794 }() 795 796 if err = m.Open(); err != nil { 797 return err 798 } 799 800 err = UpdateElement(m.fd, key.GetKeyPtr(), value.GetValuePtr(), 0) 801 if option.Config.MetricsConfig.BPFMapOps { 802 metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpUpdate, metrics.Error2Outcome(err)).Inc() 803 } 804 return err 805 } 806 807 // deleteCacheEntry evaluates the specified error, if nil the map key is 808 // removed from the cache to indicate successful deletion. If non-nil, the map 809 // key entry in the cache is updated to indicate deletion failure with the 810 // specified error. 811 // 812 // Caller must hold m.lock for writing 813 func (m *Map) deleteCacheEntry(key MapKey, err error) { 814 if m.cache == nil { 815 return 816 } 817 818 k := key.String() 819 if err == nil { 820 delete(m.cache, k) 821 } else { 822 entry, ok := m.cache[k] 823 if !ok { 824 m.cache[k] = &cacheEntry{ 825 Key: key, 826 } 827 entry = m.cache[k] 828 } 829 830 entry.DesiredAction = Delete 831 entry.LastError = err 832 m.scheduleErrorResolver() 833 } 834 } 835 836 func (m *Map) DeleteWithErrno(key MapKey) (error, syscall.Errno) { 837 var ( 838 err error 839 errno syscall.Errno 840 ) 841 842 m.lock.Lock() 843 defer m.lock.Unlock() 844 845 defer m.deleteCacheEntry(key, err) 846 847 if err = m.Open(); err != nil { 848 return err, 0 849 } 850 851 _, errno = deleteElement(m.fd, key.GetKeyPtr()) 852 if option.Config.MetricsConfig.BPFMapOps { 853 metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpDelete, metrics.Errno2Outcome(errno)).Inc() 854 } 855 if errno != 0 { 856 err = fmt.Errorf("Unable to delete element from map %s: %s", m.name, errno.Error()) 857 } 858 859 return err, errno 860 } 861 862 func (m *Map) Delete(key MapKey) error { 863 err, _ := m.DeleteWithErrno(key) 864 return err 865 } 866 867 // scopedLogger returns a logger scoped for the map. m.lock must be held. 868 func (m *Map) scopedLogger() *logrus.Entry { 869 return log.WithFields(logrus.Fields{logfields.Path: m.path, "name": m.name}) 870 } 871 872 // DeleteAll deletes all entries of a map by traversing the map and deleting individual 873 // entries. Note that if entries are added while the taversal is in progress, 874 // such entries may survive the deletion process. 875 func (m *Map) DeleteAll() error { 876 m.lock.Lock() 877 defer m.lock.Unlock() 878 879 scopedLog := m.scopedLogger() 880 scopedLog.Debug("deleting all entries in map") 881 882 nextKey := make([]byte, m.KeySize) 883 884 if m.cache != nil { 885 // Mark all entries for deletion, upon successful deletion, 886 // entries will be removed or the LastError will be updated 887 for _, entry := range m.cache { 888 entry.DesiredAction = Delete 889 entry.LastError = fmt.Errorf("deletion pending") 890 } 891 } 892 893 if err := m.Open(); err != nil { 894 return err 895 } 896 897 mk := m.MapKey.DeepCopyMapKey() 898 mv := m.MapValue.DeepCopyMapValue() 899 900 for { 901 if err := GetFirstKey(m.fd, unsafe.Pointer(&nextKey[0])); err != nil { 902 break 903 } 904 905 err := DeleteElement(m.fd, unsafe.Pointer(&nextKey[0])) 906 907 mk, _, err2 := m.dumpParser(nextKey, []byte{}, mk, mv) 908 if err2 == nil { 909 m.deleteCacheEntry(mk, err) 910 } else { 911 log.WithError(err2).Warningf("Unable to correlate iteration key %v with cache entry. Inconsistent cache.", nextKey) 912 } 913 914 if err != nil { 915 return err 916 } 917 } 918 919 return nil 920 } 921 922 // GetNextKey returns the next key in the Map after key. 923 func (m *Map) GetNextKey(key MapKey, nextKey MapKey) error { 924 if err := m.Open(); err != nil { 925 return err 926 } 927 928 err := GetNextKey(m.fd, key.GetKeyPtr(), nextKey.GetKeyPtr()) 929 if option.Config.MetricsConfig.BPFMapOps { 930 metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpGetNextKey, metrics.Error2Outcome(err)).Inc() 931 } 932 return err 933 } 934 935 // ConvertKeyValue converts key and value from bytes to given Golang struct pointers. 936 func ConvertKeyValue(bKey []byte, bValue []byte, key MapKey, value MapValue) (MapKey, MapValue, error) { 937 938 if len(bKey) > 0 { 939 if err := binary.Read(bKey, byteorder.Native, key); err != nil { 940 return nil, nil, fmt.Errorf("Unable to convert key: %s", err) 941 } 942 } 943 944 if len(bValue) > 0 { 945 if err := binary.Read(bValue, byteorder.Native, value); err != nil { 946 return nil, nil, fmt.Errorf("Unable to convert value: %s", err) 947 } 948 } 949 950 return key, value, nil 951 } 952 953 // GetModel returns a BPF map in the representation served via the API 954 func (m *Map) GetModel() *models.BPFMap { 955 m.lock.RLock() 956 defer m.lock.RUnlock() 957 958 mapModel := &models.BPFMap{ 959 Path: m.path, 960 } 961 962 if m.cache != nil { 963 mapModel.Cache = make([]*models.BPFMapEntry, len(m.cache)) 964 i := 0 965 for k, entry := range m.cache { 966 model := &models.BPFMapEntry{ 967 Key: k, 968 DesiredAction: entry.DesiredAction.String(), 969 } 970 971 if entry.LastError != nil { 972 model.LastError = entry.LastError.Error() 973 } 974 975 if entry.Value != nil { 976 model.Value = entry.Value.String() 977 } 978 mapModel.Cache[i] = model 979 i++ 980 } 981 } 982 983 return mapModel 984 } 985 986 // resolveErrors is schedule by scheduleErrorResolver() and runs periodically. 987 // It resolves up to maxSyncErrors discrepancies between cache and BPF map in 988 // the kernel. 989 func (m *Map) resolveErrors(ctx context.Context) error { 990 started := time.Now() 991 992 m.lock.Lock() 993 defer m.lock.Unlock() 994 995 if m.cache == nil { 996 return nil 997 } 998 999 if m.outstandingErrors == 0 { 1000 return nil 1001 } 1002 1003 scopedLogger := m.scopedLogger() 1004 scopedLogger.WithField("remaining", m.outstandingErrors). 1005 Debug("Starting periodic BPF map error resolver") 1006 1007 resolved := 0 1008 scanned := 0 1009 errors := 0 1010 for k, e := range m.cache { 1011 scanned++ 1012 1013 switch e.DesiredAction { 1014 case OK: 1015 case Insert: 1016 err := UpdateElement(m.fd, e.Key.GetKeyPtr(), e.Value.GetValuePtr(), 0) 1017 if option.Config.MetricsConfig.BPFMapOps { 1018 metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpUpdate, metrics.Error2Outcome(err)).Inc() 1019 } 1020 if err == nil { 1021 e.DesiredAction = OK 1022 e.LastError = nil 1023 resolved++ 1024 m.outstandingErrors-- 1025 } else { 1026 e.LastError = err 1027 errors++ 1028 } 1029 1030 case Delete: 1031 _, err := deleteElement(m.fd, e.Key.GetKeyPtr()) 1032 if option.Config.MetricsConfig.BPFMapOps { 1033 metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpDelete, metrics.Error2Outcome(err)).Inc() 1034 } 1035 if err == 0 || err == unix.ENOENT { 1036 delete(m.cache, k) 1037 resolved++ 1038 m.outstandingErrors-- 1039 } else { 1040 e.LastError = err 1041 errors++ 1042 } 1043 } 1044 1045 m.cache[k] = e 1046 1047 // bail out if maximum errors are reached to relax the map lock 1048 if errors > maxSyncErrors { 1049 break 1050 } 1051 } 1052 1053 scopedLogger.WithFields(logrus.Fields{ 1054 "remaining": m.outstandingErrors, 1055 "resolved": resolved, 1056 "scanned": scanned, 1057 "duration": time.Since(started), 1058 }).Debug("BPF map error resolver completed") 1059 1060 if m.outstandingErrors > 0 { 1061 return fmt.Errorf("%d map sync errors", m.outstandingErrors) 1062 } 1063 1064 return nil 1065 } 1066 1067 // CheckAndUpgrade checks the received map's properties (for the map currently 1068 // loaded into the kernel) against the desired properties, and if they do not 1069 // match, deletes the map. 1070 // 1071 // Returns true if the map was upgraded. 1072 func (m *Map) CheckAndUpgrade(desired *MapInfo) bool { 1073 desiredMapType := GetMapType(desired.MapType) 1074 desired.Flags |= GetPreAllocateMapFlags(desired.MapType) 1075 1076 return objCheck( 1077 m.fd, 1078 m.path, 1079 int(desiredMapType), 1080 desired.KeySize, 1081 desired.ValueSize, 1082 desired.MaxEntries, 1083 desired.Flags, 1084 ) 1085 } 1086 1087 func (m *Map) exist() (bool, error) { 1088 path, err := m.Path() 1089 if err != nil { 1090 return false, err 1091 } 1092 1093 if _, err := os.Stat(path); err == nil { 1094 return true, nil 1095 } 1096 1097 return false, nil 1098 }