github.com/jayanthvn/pure-gobpf@v0.0.0-20230623131354-8d1d959d9e0b/pkg/ebpf_maps/map_loader.go (about) 1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 package ebpf_maps 16 17 import ( 18 "errors" 19 "fmt" 20 "os" 21 "path/filepath" 22 "runtime" 23 "unsafe" 24 25 "github.com/jayanthvn/pure-gobpf/pkg/logger" 26 "github.com/jayanthvn/pure-gobpf/pkg/utils" 27 "golang.org/x/sys/unix" 28 ) 29 30 var log = logger.Get() 31 32 type BPFMap struct { 33 MapFD uint32 34 MapID uint32 35 MapMetaData BpfMapData 36 } 37 38 type BpfMapDef struct { 39 Type uint32 40 KeySize uint32 41 ValueSize uint32 42 MaxEntries uint32 43 Flags uint32 44 InnerMapFd uint32 45 Pinning uint32 46 } 47 48 type BpfMapData struct { 49 Def BpfMapDef 50 numaNode uint32 51 Name string 52 } 53 54 type BpfMapInfo struct { 55 Type uint32 56 Id uint32 57 KeySize uint32 58 ValueSize uint32 59 MaxEntries uint32 60 MapFlags uint32 61 Name [utils.BPFObjNameLen]byte 62 IfIndex uint32 63 BtfVmLinuxValueTypeId uint32 64 NetnsDev uint64 65 NetnsIno uint64 66 BTFID uint32 67 BTFKeyTypeID uint32 68 BTFValueTypeId uint32 69 Pad uint32 70 MapExtra uint64 71 } 72 73 /* 74 * 75 * struct { anonymous struct used by BPF_*_GET_*_ID 76 * union { 77 * __u32 start_id; 78 * __u32 prog_id; 79 * __u32 map_id; 80 * __u32 btf_id; 81 * __u32 link_id; 82 * }; 83 * __u32 next_id; 84 * __u32 open_flags; 85 * }; 86 */ 87 88 type BpfMapShowAttr struct { 89 Map_id uint32 90 next_id uint32 91 open_flags uint32 92 } 93 94 /* 95 * struct { anonymous struct used by BPF_OBJ_GET_INFO_BY_FD 96 * __u32 bpf_fd; 97 * __u32 info_len; 98 * __aligned_u64 info; 99 * } info; 100 * 101 */ 102 type BpfObjGetInfo struct { 103 bpf_fd uint32 104 info_len uint32 105 info uintptr 106 } 107 108 /* 109 * struct { anonymous struct used by BPF_OBJ_* commands 110 * __aligned_u64 pathname; 111 * __u32 bpf_fd; 112 * __u32 file_flags; 113 * }; 114 */ 115 type BpfObjGet struct { 116 pathname uintptr 117 bpf_fd uint32 118 file_flags uint32 119 } 120 121 type BpfMapAPIs interface { 122 CreateMap(MapMetaData BpfMapData) (BPFMap, error) 123 PinMap(pinPath string) error 124 UnPinMap(pinPath string) error 125 CreateMapEntry(key, value uintptr) error 126 UpdateMapEntry(key, value uintptr) error 127 CreateUpdateMap(key, value uintptr, updateFlags uint64) error 128 DeleteMapEntry(key uintptr) error 129 GetFirstMapEntry(nextKey uintptr) error 130 GetNextMapEntry(key, nextKey uintptr) error 131 GetMapEntry(key, value uintptr) error 132 BulkUpdateMapEntry(keyvalue map[uintptr]uintptr) error 133 BulkDeleteMapEntry(keyvalue map[uintptr]uintptr) error 134 BulkRefreshMapEntries(newMapContents map[string]uintptr) error 135 BpfGetMapFromPinPath(pinPath string) (BpfMapInfo, error) 136 } 137 138 func (m *BPFMap) CreateMap(MapMetaData BpfMapData) (BPFMap, error) { 139 140 mapCont := BpfMapData{ 141 Def: BpfMapDef{ 142 Type: uint32(MapMetaData.Def.Type), 143 KeySize: MapMetaData.Def.KeySize, 144 ValueSize: MapMetaData.Def.ValueSize, 145 MaxEntries: MapMetaData.Def.MaxEntries, 146 Flags: MapMetaData.Def.Flags, 147 InnerMapFd: 0, 148 }, 149 Name: MapMetaData.Name, 150 } 151 mapData := unsafe.Pointer(&mapCont) 152 mapDataSize := unsafe.Sizeof(mapCont) 153 154 log.Infof("Calling BPFsys for name %s mapType %d keysize %d valuesize %d max entries %d and flags %d", string(MapMetaData.Name[:]), MapMetaData.Def.Type, MapMetaData.Def.KeySize, MapMetaData.Def.ValueSize, MapMetaData.Def.MaxEntries, MapMetaData.Def.Flags) 155 156 ret, _, errno := unix.Syscall( 157 unix.SYS_BPF, 158 utils.BPF_MAP_CREATE, 159 uintptr(mapData), 160 mapDataSize, 161 ) 162 163 if (errno < 0) || (int(ret) == -1) { 164 log.Infof("Unable to create map and ret %d and err %s", int(ret), errno) 165 return BPFMap{}, fmt.Errorf("Unable to create map: %s", errno) 166 } 167 168 log.Infof("Create map done with fd : %d", int(ret)) 169 170 bpfMap := BPFMap{ 171 MapFD: uint32(ret), 172 MapMetaData: MapMetaData, 173 } 174 return bpfMap, nil 175 } 176 177 func (m *BPFMap) PinMap(pinPath string) error { 178 if m.MapMetaData.Def.Pinning == utils.PIN_NONE { 179 return nil 180 } 181 182 if m.MapMetaData.Def.Pinning == utils.PIN_GLOBAL_NS { 183 184 //If pinPath is already present lets delete and create a new one 185 if utils.IsfileExists(pinPath) { 186 log.Infof("Found file %s so deleting the path", pinPath) 187 err := utils.UnPinObject(pinPath) 188 if err != nil { 189 log.Infof("Failed to UnPinObject %v", err) 190 return err 191 } 192 } 193 err := os.MkdirAll(filepath.Dir(pinPath), 0755) 194 if err != nil { 195 log.Infof("error creating directory %s: %v", filepath.Dir(pinPath), err) 196 return fmt.Errorf("error creating directory %s: %v", filepath.Dir(pinPath), err) 197 } 198 _, err = os.Stat(pinPath) 199 if err == nil { 200 log.Infof("aborting, found file at %s", pinPath) 201 return fmt.Errorf("aborting, found file at %s", pinPath) 202 } 203 if err != nil && !os.IsNotExist(err) { 204 log.Infof("failed to stat %s: %v", pinPath, err) 205 return fmt.Errorf("failed to stat %s: %v", pinPath, err) 206 } 207 208 return utils.PinObject(m.MapFD, pinPath) 209 210 } 211 return nil 212 213 } 214 215 func (m *BPFMap) UnPinMap(pinPath string) error { 216 err := utils.UnPinObject(pinPath) 217 if err != nil { 218 log.Infof("Failed to unpin map") 219 return err 220 } 221 if m.MapFD <= 0 { 222 log.Infof("FD is invalid or closed %d", m.MapFD) 223 return nil 224 } 225 return unix.Close(int(m.MapFD)) 226 } 227 228 func (m *BPFMap) CreateMapEntry(key, value uintptr) error { 229 return m.CreateUpdateMap(key, value, uint64(utils.BPF_NOEXIST)) 230 } 231 232 //TODO : This should be updated to behave like update 233 func (m *BPFMap) UpdateMapEntry(key, value uintptr) error { 234 return m.CreateUpdateMap(key, value, uint64(utils.BPF_ANY)) 235 } 236 237 func (m *BPFMap) CreateUpdateMap(key, value uintptr, updateFlags uint64) error { 238 239 mapFD, err := utils.GetMapFDFromID(int(m.MapID)) 240 if err != nil { 241 log.Infof("Unable to GetMapFDfromID and ret %d and err %s", int(mapFD), err) 242 return fmt.Errorf("Unable to get FD: %s", err) 243 } 244 245 attr := utils.BpfMapAttr{ 246 MapFD: uint32(mapFD), 247 Flags: updateFlags, 248 Key: uint64(key), 249 Value: uint64(value), 250 } 251 ret, _, errno := unix.Syscall( 252 unix.SYS_BPF, 253 utils.BPF_MAP_UPDATE_ELEM, 254 uintptr(unsafe.Pointer(&attr)), 255 unsafe.Sizeof(attr), 256 ) 257 runtime.KeepAlive(key) 258 runtime.KeepAlive(value) 259 260 if errno != 0 { 261 log.Infof("Unable to create/update map entry and ret %d and err %s", int(ret), errno) 262 return fmt.Errorf("Unable to update map: %s", errno) 263 } 264 265 log.Infof("Create/Update map entry done with fd : %d and err %s", int(ret), errno) 266 unix.Close(mapFD) 267 return nil 268 } 269 270 func (m *BPFMap) DeleteMapEntry(key uintptr) error { 271 272 mapFD, err := utils.GetMapFDFromID(int(m.MapID)) 273 if err != nil { 274 log.Infof("Unable to GetMapFDfromID and ret %d and err %s", int(mapFD), err) 275 return fmt.Errorf("Unable to get FD: %s", err) 276 } 277 attr := utils.BpfMapAttr{ 278 MapFD: uint32(mapFD), 279 Key: uint64(key), 280 } 281 ret, _, errno := unix.Syscall( 282 unix.SYS_BPF, 283 utils.BPF_MAP_DELETE_ELEM, 284 uintptr(unsafe.Pointer(&attr)), 285 unsafe.Sizeof(attr), 286 ) 287 if errno != 0 { 288 log.Infof("Unable to delete map entry and ret %d and err %s", int(ret), errno) 289 return fmt.Errorf("Unable to update map: %s", errno) 290 } 291 292 log.Infof("Delete map entry done with fd : %d and err %s", int(ret), errno) 293 unix.Close(mapFD) 294 return nil 295 } 296 297 // To get the first entry pass key as `nil` 298 func (m *BPFMap) GetFirstMapEntry(nextKey uintptr) error { 299 return m.GetNextMapEntry(uintptr(unsafe.Pointer(nil)), nextKey) 300 } 301 302 func (m *BPFMap) GetNextMapEntry(key, nextKey uintptr) error { 303 304 mapFD, err := utils.GetMapFDFromID(int(m.MapID)) 305 if err != nil { 306 log.Infof("Unable to GetMapFDfromID and ret %d and err %s", int(mapFD), err) 307 return fmt.Errorf("Unable to get FD: %s", err) 308 } 309 attr := utils.BpfMapAttr{ 310 MapFD: uint32(mapFD), 311 Key: uint64(key), 312 Value: uint64(nextKey), 313 } 314 ret, _, errno := unix.Syscall( 315 unix.SYS_BPF, 316 utils.BPF_MAP_GET_NEXT_KEY, 317 uintptr(unsafe.Pointer(&attr)), 318 unsafe.Sizeof(attr), 319 ) 320 if errors.Is(errno, unix.ENOENT) { 321 log.Infof("Last entry read done") 322 unix.Close(mapFD) 323 return errno 324 } 325 if errno != 0 { 326 log.Infof("Unable to get next map entry and ret %d and err %s", int(ret), errno) 327 unix.Close(mapFD) 328 return fmt.Errorf("Unable to get next map entry: %s", errno) 329 } 330 331 log.Infof("Got next map entry with fd : %d and err %s", int(ret), errno) 332 unix.Close(mapFD) 333 return nil 334 } 335 336 func (m *BPFMap) GetAllMapKeys() ([]string, error) { 337 var keyList []string 338 keySize := m.MapMetaData.Def.KeySize 339 340 curKey := make([]byte, keySize) 341 nextKey := make([]byte, keySize) 342 343 err := m.GetFirstMapEntry(uintptr(unsafe.Pointer(&curKey[0]))) 344 if err != nil { 345 log.Infof("Unable to get first key %s", err) 346 return nil, fmt.Errorf("Unable to get first key entry: %s", err) 347 } else { 348 for { 349 err = m.GetNextMapEntry(uintptr(unsafe.Pointer(&curKey[0])), uintptr(unsafe.Pointer(&nextKey[0]))) 350 log.Infof("Adding to key list %v", curKey) 351 keyList = append(keyList, string(curKey)) 352 if errors.Is(err, unix.ENOENT) { 353 log.Infof("Done reading all entries") 354 return keyList, nil 355 } 356 if err != nil { 357 log.Infof("Unable to get next key %s", err) 358 break 359 } 360 //curKey = nextKey 361 copy(curKey, nextKey) 362 } 363 } 364 log.Infof("Done get all keys") 365 return keyList, err 366 } 367 368 func (m *BPFMap) GetMapEntry(key, value uintptr) error { 369 370 mapFD, err := utils.GetMapFDFromID(int(m.MapID)) 371 if err != nil { 372 log.Infof("Unable to GetMapFDfromID and ret %d and err %s", int(mapFD), err) 373 return fmt.Errorf("Unable to get FD: %s", err) 374 } 375 attr := utils.BpfMapAttr{ 376 MapFD: uint32(mapFD), 377 Key: uint64(key), 378 Value: uint64(value), 379 } 380 ret, _, errno := unix.Syscall( 381 unix.SYS_BPF, 382 utils.BPF_MAP_LOOKUP_ELEM, 383 uintptr(unsafe.Pointer(&attr)), 384 unsafe.Sizeof(attr), 385 ) 386 if errno != 0 { 387 log.Infof("Unable to get map entry and ret %d and err %s", int(ret), errno) 388 unix.Close(mapFD) 389 return fmt.Errorf("Unable to get next map entry: %s", errno) 390 } 391 392 log.Infof("Got map entry with fd : %d and err %s", int(ret), errno) 393 unix.Close(mapFD) 394 return nil 395 } 396 397 func (m *BPFMap) BulkDeleteMapEntry(keyvalue map[uintptr]uintptr) error { 398 for k, _ := range keyvalue { 399 err := m.DeleteMapEntry(k) 400 if err != nil { 401 log.Infof("One of the element delete failed hence returning from bulk update") 402 return err 403 } 404 } 405 log.Infof("Bulk delete is successful for mapID: %d", int(m.MapID)) 406 return nil 407 } 408 409 func (m *BPFMap) BulkUpdateMapEntry(keyvalue map[uintptr]uintptr) error { 410 for k, v := range keyvalue { 411 log.Infof("Key being programmed - in bytearray ", *((*uint64)(unsafe.Pointer(k)))) 412 err := m.UpdateMapEntry(k, v) 413 if err != nil { 414 log.Infof("One of the element update failed hence returning from bulk update") 415 return err 416 } 417 } 418 log.Infof("Bulk update is successful for mapID: %d", int(m.MapID)) 419 return nil 420 } 421 422 func (m *BPFMap) BulkRefreshMapEntries(newMapContents map[string]uintptr) error { 423 424 // 1. Construct i/p to bulkMap 425 keyvaluePtr := make(map[uintptr]uintptr) 426 427 for k, v := range newMapContents { 428 keyByte := []byte(k) 429 log.Infof("Converted string to bytearray %v", keyByte) 430 keyPtr := uintptr(unsafe.Pointer(&keyByte[0])) 431 keyvaluePtr[keyPtr] = v 432 } 433 434 // 2. Update all map entries 435 err := m.BulkUpdateMapEntry(keyvaluePtr) 436 if err != nil { 437 log.Infof("Refresh map failed: during update %v", err) 438 return err 439 } 440 441 // 3. Read all map entries 442 retrievedMapKeyList, err := m.GetAllMapKeys() 443 if err != nil { 444 log.Infof("Get all map keys failed: during Refresh %v", err) 445 return err 446 } 447 448 // 4. Delete stale Keys 449 log.Infof("Check for stale entries and got %d entries from BPF map", len(retrievedMapKeyList)) 450 for _, key := range retrievedMapKeyList { 451 log.Infof("Checking if key %s is deltable", key) 452 if _, ok := newMapContents[key]; !ok { 453 log.Infof("This can be deleted, not needed anymore...") 454 deletableKeyByte := []byte(key) 455 deletableKeyBytePtr := uintptr(unsafe.Pointer(&deletableKeyByte[0])) 456 err = m.DeleteMapEntry(deletableKeyBytePtr) 457 if err != nil { 458 log.Infof("Unable to delete entry %s but will continue and err %v", key, err) 459 } 460 } 461 } 462 return nil 463 } 464 465 func (attr *BpfMapShowAttr) isBpfMapGetNextID() bool { 466 ret, _, errno := unix.Syscall( 467 unix.SYS_BPF, 468 utils.BPF_MAP_GET_NEXT_ID, 469 uintptr(unsafe.Pointer(attr)), 470 unsafe.Sizeof(*attr), 471 ) 472 if errno != 0 { 473 log.Infof("Done get_next_id for Map - ret %d and err %s", int(ret), errno) 474 return false 475 } 476 477 attr.Map_id = attr.next_id 478 return true 479 } 480 481 func (objattr *BpfObjGetInfo) BpfGetMapInfoForFD() error { 482 ret, _, errno := unix.Syscall( 483 unix.SYS_BPF, 484 utils.BPF_OBJ_GET_INFO_BY_FD, 485 uintptr(unsafe.Pointer(objattr)), 486 unsafe.Sizeof(*objattr), 487 ) 488 if errno != 0 { 489 log.Infof("Failed to get object info by FD - ret %d and err %s", int(ret), errno) 490 return errno 491 } 492 //TODO maybe get info here itself 493 return nil 494 } 495 496 func GetIDFromFD(mapFD int) (int, error) { 497 mapInfo, err := GetBPFmapInfo(mapFD) 498 if err != nil { 499 return -1, err 500 } 501 return int(mapInfo.Id), nil 502 } 503 504 func GetBPFmapInfo(mapFD int) (BpfMapInfo, error) { 505 var bpfMapInfo BpfMapInfo 506 objInfo := BpfObjGetInfo{ 507 bpf_fd: uint32(mapFD), 508 info_len: uint32(unsafe.Sizeof(bpfMapInfo)), 509 info: uintptr(unsafe.Pointer(&bpfMapInfo)), 510 } 511 512 err := objInfo.BpfGetMapInfoForFD() 513 if err != nil { 514 log.Infof("Failed to get map Info for FD - ", mapFD) 515 return BpfMapInfo{}, err 516 } 517 518 return bpfMapInfo, nil 519 } 520 521 func BpfGetAllMapInfo() ([]BpfMapInfo, error) { 522 loadedMaps := []BpfMapInfo{} 523 attr := BpfMapShowAttr{} 524 log.Infof("In get all prog info") 525 for attr.isBpfMapGetNextID() { 526 log.Infof("Got ID - %d", attr.next_id) 527 528 mapfd, err := utils.GetMapFDFromID(int(attr.next_id)) 529 if err != nil { 530 log.Infof("Failed to get map Info") 531 return nil, err 532 } 533 log.Infof("Found map FD - %d", mapfd) 534 bpfMapInfo, err := GetBPFmapInfo(mapfd) 535 if err != nil { 536 log.Infof("Failed to get map Info for FD", mapfd) 537 return nil, err 538 } 539 unix.Close(mapfd) 540 541 loadedMaps = append(loadedMaps, bpfMapInfo) 542 } 543 log.Infof("Done all map info!!!") 544 return loadedMaps, nil 545 } 546 547 func (attr *BpfObjGet) BpfGetObject() (int, error) { 548 ret, _, errno := unix.Syscall( 549 unix.SYS_BPF, 550 utils.BPF_OBJ_GET, 551 uintptr(unsafe.Pointer(attr)), 552 unsafe.Sizeof(*attr), 553 ) 554 if errno != 0 { 555 log.Infof("Failed to get Map FD - ret %d and err %s", int(ret), errno) 556 return 0, errno 557 } 558 return int(ret), nil 559 } 560 561 func (m *BPFMap) BpfGetMapFromPinPath(pinPath string) (BpfMapInfo, error) { 562 if len(pinPath) == 0 { 563 return BpfMapInfo{}, fmt.Errorf("Invalid pinPath") 564 } 565 566 cPath := []byte(pinPath + "\x00") 567 objInfo := BpfObjGet{ 568 pathname: uintptr(unsafe.Pointer(&cPath[0])), 569 } 570 571 mapFD, err := objInfo.BpfGetObject() 572 if err != nil { 573 log.Infof("Failed to get object") 574 return BpfMapInfo{}, err 575 576 } 577 578 bpfMapInfo, err := GetBPFmapInfo(mapFD) 579 if err != nil { 580 log.Infof("Failed to get map Info for FD - %d", mapFD) 581 return bpfMapInfo, err 582 } 583 err = unix.Close(int(mapFD)) 584 if err != nil { 585 log.Infof("Failed to close but return the mapinfo") 586 } 587 588 return bpfMapInfo, nil 589 } 590 591 func GetFirstMapEntryByID(nextKey uintptr, mapID int) error { 592 return GetNextMapEntryByID(uintptr(unsafe.Pointer(nil)), nextKey, mapID) 593 } 594 595 func GetNextMapEntryByID(key, nextKey uintptr, mapID int) error { 596 597 mapFD, err := utils.GetMapFDFromID(mapID) 598 if err != nil { 599 log.Infof("Unable to GetMapFDfromID and ret %d and err %s", int(mapFD), err) 600 return fmt.Errorf("Unable to get FD: %s", err) 601 } 602 attr := utils.BpfMapAttr{ 603 MapFD: uint32(mapFD), 604 Key: uint64(key), 605 Value: uint64(nextKey), 606 } 607 ret, _, errno := unix.Syscall( 608 unix.SYS_BPF, 609 utils.BPF_MAP_GET_NEXT_KEY, 610 uintptr(unsafe.Pointer(&attr)), 611 unsafe.Sizeof(attr), 612 ) 613 if errors.Is(errno, unix.ENOENT) { 614 unix.Close(mapFD) 615 return errno 616 } 617 if errno != 0 { 618 log.Infof("Unable to get next map entry and ret %d and err %s", int(ret), errno) 619 unix.Close(mapFD) 620 return fmt.Errorf("Unable to get next map entry: %s", errno) 621 } 622 623 log.Infof("Got next map entry with fd : %d and err %s", int(ret), errno) 624 unix.Close(mapFD) 625 return nil 626 } 627 628 type BPFTrieKeyV6 struct { 629 PrefixLen uint32 630 IP [16]uint8 631 } 632 633 func GetMapEntryByID(key, value uintptr, mapID int) error { 634 635 mapFD, err := utils.GetMapFDFromID(mapID) 636 if err != nil { 637 log.Infof("Unable to GetMapFDfromID and ret %d and err %s", int(mapFD), err) 638 return fmt.Errorf("Unable to get FD: %s", err) 639 } 640 log.Infof("Got FD %d", mapFD) 641 642 var keyval BPFTrieKeyV6 643 structPointer := (*BPFTrieKeyV6)(unsafe.Pointer(key)) 644 keyval = *structPointer 645 646 log.Infof("IP %v", keyval.IP) 647 log.Infof("Prefix Len %v", keyval.PrefixLen) 648 649 attr := utils.BpfMapAttr{ 650 MapFD: uint32(mapFD), 651 Key: uint64(key), 652 Value: uint64(value), 653 } 654 ret, _, errno := unix.Syscall( 655 unix.SYS_BPF, 656 utils.BPF_MAP_LOOKUP_ELEM, 657 uintptr(unsafe.Pointer(&attr)), 658 unsafe.Sizeof(attr), 659 ) 660 var tempkeyval BPFTrieKeyV6 661 structPointer = (*BPFTrieKeyV6)(unsafe.Pointer(key)) 662 tempkeyval = *structPointer 663 664 log.Infof("iAfter IP %v", tempkeyval.IP) 665 log.Infof("After Prefix Len %v", tempkeyval.PrefixLen) 666 if errno != 0 { 667 log.Infof("Unable to get map entry and ret %d and err %s", int(ret), errno) 668 unix.Close(mapFD) 669 return fmt.Errorf("Unable to get next map entry: %s", errno) 670 } 671 runtime.KeepAlive(key) 672 runtime.KeepAlive(value) 673 674 log.Infof("Got map entry with ret : %d and err %s", int(ret), errno) 675 unix.Close(mapFD) 676 return nil 677 }