github.com/jayanthvn/pure-gobpf@v0.0.0-20230623131354-8d1d959d9e0b/pkg/elfparser/elf.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 elfparser 16 17 import ( 18 "bytes" 19 "debug/elf" 20 "encoding/binary" 21 "fmt" 22 "io" 23 "os" 24 "path" 25 "path/filepath" 26 "strings" 27 "syscall" 28 29 "golang.org/x/sys/unix" 30 31 "github.com/jayanthvn/pure-gobpf/pkg/ebpf_maps" 32 "github.com/jayanthvn/pure-gobpf/pkg/ebpf_progs" 33 "github.com/jayanthvn/pure-gobpf/pkg/logger" 34 "github.com/jayanthvn/pure-gobpf/pkg/utils" 35 ) 36 37 var ( 38 bpfInsDefSize = (binary.Size(utils.BPFInsn{}) - 1) 39 bpfMapDefSize = binary.Size(ebpf_maps.BpfMapDef{}) 40 ) 41 42 var log = logger.Get() 43 44 type BPFdata struct { 45 Program ebpf_progs.BPFProgram // Return the program 46 Maps map[string]ebpf_maps.BPFMap // List of associated maps 47 } 48 49 type relocationEntry struct { 50 relOffset int 51 symbol elf.Symbol 52 } 53 54 // This is not needed 5.11 kernel onwards because per-cgroup mem limits 55 // https://lore.kernel.org/bpf/20201201215900.3569844-1-guro@fb.com/ 56 func IncreaseRlimit() error { 57 //var log = logger.Get() 58 err := unix.Setrlimit(unix.RLIMIT_MEMLOCK, &unix.Rlimit{Cur: unix.RLIM_INFINITY, Max: unix.RLIM_INFINITY}) 59 if err != nil { 60 log.Infof("Failed to bump up the rlimit") 61 return err 62 } 63 return nil 64 } 65 66 func LoadBpfFile(path, customizedPinPath string) (map[string]BPFdata, map[string]ebpf_maps.BPFMap, error) { 67 //var log = logger.Get() 68 f, err := os.Open(path) 69 if err != nil { 70 log.Infof("LoadBpfFile failed to open") 71 return nil, nil, err 72 } 73 defer f.Close() 74 75 bpfMap := &ebpf_maps.BPFMap{} 76 bpfProg := &ebpf_progs.BPFProgram{} 77 78 BPFloadedprog, BPFloadedmaps, err := doLoadELF(f, bpfMap, bpfProg, customizedPinPath) 79 if err != nil { 80 return nil, nil, err 81 } 82 return BPFloadedprog, BPFloadedmaps, nil 83 } 84 85 func loadElfMapsSection(mapsShndx int, dataMaps *elf.Section, elfFile *elf.File, bpfMapApi ebpf_maps.BpfMapAPIs, customizedPinPath string) (map[string]ebpf_maps.BPFMap, error) { 86 //var log = logger.Get() 87 //Replace this TODO 88 mapDefinitionSize := bpfMapDefSize 89 GlobalMapData := []ebpf_maps.BpfMapData{} 90 foundMaps := make(map[string]ebpf_maps.BPFMap) 91 92 data, err := dataMaps.Data() 93 if err != nil { 94 log.Infof("Error while loading section") 95 return nil, fmt.Errorf("error while loading section': %w", err) 96 } 97 98 symbols, err := elfFile.Symbols() 99 if err != nil { 100 log.Infof("Get symbol failed") 101 return nil, fmt.Errorf("get symbols: %w", err) 102 } 103 104 log.Infof("Dumping MAP %v and size %d", data, mapDefinitionSize) 105 106 for offset := 0; offset < len(data); offset += mapDefinitionSize { 107 log.Infof("Offset %d", offset) 108 mapData := ebpf_maps.BpfMapData{} 109 mapDef := ebpf_maps.BpfMapDef{ 110 Type: uint32(binary.LittleEndian.Uint32(data[offset : offset+4])), 111 KeySize: uint32(binary.LittleEndian.Uint32(data[offset+4 : offset+8])), 112 ValueSize: uint32(binary.LittleEndian.Uint32(data[offset+8 : offset+12])), 113 MaxEntries: uint32(binary.LittleEndian.Uint32(data[offset+12 : offset+16])), 114 Flags: uint32(binary.LittleEndian.Uint32(data[offset+16 : offset+20])), 115 Pinning: uint32(binary.LittleEndian.Uint32(data[offset+20 : offset+24])), 116 } 117 118 log.Infof("DUMP Type %d KeySize %d ValueSize %d MaxEntries %d Flags %d Pinning %d", uint32(binary.LittleEndian.Uint32(data[offset:offset+4])), 119 uint32(binary.LittleEndian.Uint32(data[offset+4:offset+8])), uint32(binary.LittleEndian.Uint32(data[offset+8:offset+12])), 120 uint32(binary.LittleEndian.Uint32(data[offset+12:offset+16])), uint32(binary.LittleEndian.Uint32(data[offset+16:offset+20])), 121 uint32(binary.LittleEndian.Uint32(data[offset+20:offset+24]))) 122 123 for _, sym := range symbols { 124 if int(sym.Section) == mapsShndx && int(sym.Value) == offset { 125 mapName := path.Base(sym.Name) 126 mapData.Name = mapName 127 } 128 } 129 log.Infof("Found map name %s", mapData.Name) 130 mapData.Def = mapDef 131 GlobalMapData = append(GlobalMapData, mapData) 132 } 133 134 log.Infof("Total maps found - %d", len(GlobalMapData)) 135 136 for index := 0; index < len(GlobalMapData); index++ { 137 log.Infof("Loading maps") 138 loadedMaps := GlobalMapData[index] 139 140 /* 141 bpfMap := &ebpf_maps.BPFMap{ 142 MapMetaData: loadedMaps, 143 }*/ 144 bpfMap, err := (bpfMapApi).CreateMap(loadedMaps) 145 if err != nil { 146 //Even if one map fails, we error out 147 log.Infof("Failed to create map, continue to next map..just for debugging") 148 continue 149 } 150 151 mapNameStr := loadedMaps.Name 152 if len(customizedPinPath) != 0 { 153 mapNameStr = customizedPinPath + "_" + mapNameStr 154 } 155 156 pinPath := utils.MAP_BPF_FS + mapNameStr 157 158 log.Infof("Pinpath ", pinPath) 159 bpfMap.PinMap(pinPath) 160 161 //Fill ID 162 mapInfo, err := (bpfMapApi).BpfGetMapFromPinPath(pinPath) 163 if err != nil { 164 return nil, fmt.Errorf("map '%s' doesn't exist", mapNameStr) 165 } 166 map_id := uint32(mapInfo.Id) 167 bpfMap.MapID = map_id 168 169 foundMaps[loadedMaps.Name] = bpfMap 170 } 171 return foundMaps, nil 172 } 173 174 func parseRelocationSection(reloSection *elf.Section, elfFile *elf.File) ([]relocationEntry, error) { 175 //var log = logger.Get() 176 var result []relocationEntry 177 178 symbols, err := elfFile.Symbols() 179 if err != nil { 180 return nil, fmt.Errorf("unable to load symbols(): %v", err) 181 } 182 // Read section data 183 data, err := reloSection.Data() 184 if err != nil { 185 return nil, fmt.Errorf("unable to read data from section '%s': %v", reloSection.Name, err) 186 } 187 188 reader := bytes.NewReader(data) 189 for { 190 var err error 191 var offset, index int 192 193 switch elfFile.Class { 194 case elf.ELFCLASS64: 195 var relocEntry elf.Rel64 196 err = binary.Read(reader, elfFile.ByteOrder, &relocEntry) 197 index = int(elf.R_SYM64(relocEntry.Info)) - 1 198 offset = int(relocEntry.Off) 199 case elf.ELFCLASS32: 200 var relocEntry elf.Rel32 201 err = binary.Read(reader, elfFile.ByteOrder, &relocEntry) 202 index = int(elf.R_SYM32(relocEntry.Info)) - 1 203 offset = int(relocEntry.Off) 204 default: 205 return nil, fmt.Errorf("Unsupported arch %v", elfFile.Class) 206 } 207 208 if err != nil { 209 // EOF. Nothing more to do. 210 if err == io.EOF { 211 return result, nil 212 } 213 return nil, err 214 } 215 216 // Validate the derived index value 217 if index >= len(symbols) { 218 return nil, fmt.Errorf("Invalid Relocation section entry'%v': index %v does not exist", 219 reloSection, index) 220 } 221 log.Infof("Relocation section entry: %s @ %v", symbols[index].Name, offset) 222 result = append(result, relocationEntry{ 223 relOffset: offset, 224 symbol: symbols[index], 225 }) 226 } 227 } 228 229 func loadElfProgSection(dataProg *elf.Section, reloSection *elf.Section, license string, progType string, subSystem string, subProgType string, sectionIndex int, elfFile *elf.File, bpfProgApi ebpf_progs.BpfProgAPIs, bpfMap ebpf_maps.BpfMapAPIs, customizedPinPath string, loadedMaps map[string]ebpf_maps.BPFMap) (BPFdata, error) { 230 //var log = logger.Get() 231 232 isRelocationNeeded := true 233 insDefSize := bpfInsDefSize 234 235 data, err := dataProg.Data() 236 if err != nil { 237 return BPFdata{}, err 238 } 239 240 if reloSection == nil { 241 log.Infof("Relocation is not needed") 242 isRelocationNeeded = false 243 } 244 245 //Single section might have multiple programs. So we retrieve one prog at a time and load. 246 symbolTable, err := elfFile.Symbols() 247 if err != nil { 248 log.Infof("Get symbol failed") 249 return BPFdata{}, fmt.Errorf("get symbols: %w", err) 250 } 251 252 mapIDToFD := make(map[int]string) 253 254 if isRelocationNeeded { 255 log.Infof("Loading Program with relocation section; Info:%v; Name: %s, Type: %s; Size: %v", reloSection.Info, 256 reloSection.Name, reloSection.Type, reloSection.Size) 257 258 relocationEntries, err := parseRelocationSection(reloSection, elfFile) 259 if err != nil || len(relocationEntries) == 0 { 260 return BPFdata{}, fmt.Errorf("Unable to parse relocation entries....") 261 } 262 263 log.Infof("Applying Relocations..") 264 // TODO create a map array 265 for _, relocationEntry := range relocationEntries { 266 if relocationEntry.relOffset >= len(data) { 267 return BPFdata{}, fmt.Errorf("Invalid offset for the relocation entry %d", relocationEntry.relOffset) 268 } 269 270 //eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM which consists 271 //of two consecutive 'struct bpf_insn' 8-byte blocks and interpreted as single 272 //instruction that loads 64-bit immediate value into a dst_reg. 273 ebpfInstruction := &utils.BPFInsn{ 274 Code: data[relocationEntry.relOffset], 275 DstReg: data[relocationEntry.relOffset+1] & 0xf, 276 SrcReg: data[relocationEntry.relOffset+1] >> 4, 277 Off: int16(binary.LittleEndian.Uint16(data[relocationEntry.relOffset+2:])), 278 Imm: int32(binary.LittleEndian.Uint32(data[relocationEntry.relOffset+4:])), 279 } 280 281 log.Infof("BPF Instruction code: %s; offset: %d; imm: %d", ebpfInstruction.Code, ebpfInstruction.Off, ebpfInstruction.Imm) 282 283 //Validate for Invalid BPF instructions 284 if ebpfInstruction.Code != (unix.BPF_LD | unix.BPF_IMM | unix.BPF_DW) { 285 return BPFdata{}, fmt.Errorf("Invalid BPF instruction (at %d): %d", 286 relocationEntry.relOffset, ebpfInstruction.Code) 287 } 288 289 // Point BPF instruction to the FD of the map referenced. Update the last 4 bytes of 290 // instruction (immediate constant) with the map's FD. 291 // BPF_MEM | <size> | BPF_STX: *(size *) (dst_reg + off) = src_reg 292 // BPF_MEM | <size> | BPF_ST: *(size *) (dst_reg + off) = imm32 293 mapName := relocationEntry.symbol.Name 294 log.Infof("Map to be relocated; Name: %s", mapName) 295 var mapFD int 296 var map_id int 297 if progMap, ok := loadedMaps[mapName]; ok { 298 map_id = int(progMap.MapID) 299 mapIDToFD[map_id] = mapName 300 mapFD = int(progMap.MapFD) 301 302 } else { 303 //This might be a shared global map so get from pinpath 304 pinLocation := "global_" + mapName 305 globalPinPath := utils.MAP_BPF_FS + pinLocation 306 mapInfo, err := (bpfMap).BpfGetMapFromPinPath(globalPinPath) 307 if err != nil { 308 return BPFdata{}, fmt.Errorf("map '%s' doesn't exist", mapName) 309 } 310 map_id = int(mapInfo.Id) 311 mapIDToFD[map_id] = mapName 312 mapFD, err = utils.GetMapFDFromID(map_id) 313 if err != nil { 314 return BPFdata{}, fmt.Errorf("Failed to get map FD '%s' doesn't exist", mapName) 315 } 316 } 317 318 log.Infof("Map found. Replace the offset with corresponding Map FD: %v", mapFD) 319 ebpfInstruction.SrcReg = 1 //dummy value for now 320 ebpfInstruction.Imm = int32(mapFD) 321 copy(data[relocationEntry.relOffset:relocationEntry.relOffset+8], ebpfInstruction.ConvertBPFInstructionToByteStream()) 322 log.Infof("From data: BPF Instruction code: %d; offset: %d; imm: %d", 323 uint8(data[relocationEntry.relOffset]), 324 uint16(binary.LittleEndian.Uint16(data[relocationEntry.relOffset+2:relocationEntry.relOffset+4])), 325 uint32(binary.LittleEndian.Uint32(data[relocationEntry.relOffset+4:relocationEntry.relOffset+8]))) 326 } 327 } 328 329 var pgmList = make(map[string]ebpf_progs.BPFProgram) 330 bpfData := BPFdata{} 331 // Iterate over the symbols in the symbol table 332 for _, symbol := range symbolTable { 333 // Check if the symbol is a function 334 if elf.ST_TYPE(symbol.Info) == elf.STT_FUNC { 335 // Check if sectionIndex matches 336 if int(symbol.Section) == sectionIndex && elf.ST_BIND(symbol.Info) == elf.STB_GLOBAL { 337 // Check if the symbol's value (offset) is within the range of the section data 338 339 progSize := symbol.Size 340 secOff := symbol.Value 341 ProgName := symbol.Name 342 343 if secOff+progSize > dataProg.Size { 344 log.Infof("Section out of bound secOff %d - progSize %d for name %s and data size %d", progSize, secOff, ProgName, dataProg.Size) 345 return BPFdata{}, fmt.Errorf("Failed to Load the prog") 346 } 347 348 log.Infof("Sec '%s': found program '%s' at insn offset %d (%d bytes), code size %d insns (%d bytes)\n", progType, ProgName, secOff/uint64(insDefSize), secOff, progSize/uint64(insDefSize), progSize) 349 if symbol.Value >= dataProg.Addr && symbol.Value < dataProg.Addr+dataProg.Size { 350 // Extract the BPF program data from the section data 351 log.Infof("Data offset - %d", symbol.Value-dataProg.Addr) 352 log.Infof("Data len - %d", len(data)) 353 354 dataStart := (symbol.Value - dataProg.Addr) 355 dataEnd := dataStart + progSize 356 programData := make([]byte, progSize) 357 copy(programData, data[dataStart:dataEnd]) 358 359 log.Infof("Program Data size - %d", len(programData)) 360 361 pinLocation := ProgName 362 if len(customizedPinPath) != 0 { 363 pinLocation = customizedPinPath + "_" + ProgName 364 } 365 pinPath := utils.PROG_BPF_FS + pinLocation 366 progFD, _ := bpfProgApi.LoadProg(progType, programData, license, pinPath, bpfInsDefSize) 367 if progFD == -1 { 368 log.Infof("Failed to load prog") 369 return BPFdata{}, fmt.Errorf("Failed to Load the prog") 370 } 371 log.Infof("loaded prog with %d", progFD) 372 373 //Fill ID 374 progInfo, newProgFD, err := bpfProgApi.BpfGetProgFromPinPath(pinPath) 375 if err != nil { 376 return BPFdata{}, fmt.Errorf("Failed to get ProgID") 377 } 378 //TODO : need to refactor this 379 unix.Close(int(newProgFD)) 380 381 progID := int(progInfo.ID) 382 pgmList[ProgName] = ebpf_progs.BPFProgram{ 383 ProgID: progID, 384 ProgFD: progFD, 385 PinPath: pinPath, 386 ProgType: progType, 387 SubSystem: subSystem, 388 SubProgType: subProgType, 389 } 390 391 progMaps := make(map[string]ebpf_maps.BPFMap) 392 393 if isRelocationNeeded { 394 // TODO get prog info by FD and get list of maps..to fill 395 associatedMaps, err := bpfProgApi.GetBPFProgAssociatedMapsIDs(progFD) 396 if err != nil { 397 log.Infof("Failed to load prog") 398 return BPFdata{}, fmt.Errorf("Failed to Load the prog, get associatedmapIDs failed") 399 } 400 //walk thru all mapIDs and get loaded FDs and fill BPFData 401 for mapInfoIdx := 0; mapInfoIdx < len(associatedMaps); mapInfoIdx++ { 402 mapID := associatedMaps[mapInfoIdx] 403 //TODO - Need an error check for unkown map ID 404 if mapName, ok := mapIDToFD[int(mapID)]; ok { 405 progMaps[mapName] = loadedMaps[mapName] 406 } 407 } 408 } 409 410 bpfData.Program = ebpf_progs.BPFProgram{ 411 ProgID: progID, 412 ProgFD: progFD, 413 PinPath: pinPath, 414 ProgType: progType, 415 SubSystem: subSystem, 416 SubProgType: subProgType, 417 } 418 bpfData.Maps = progMaps 419 420 } else { 421 log.Infof("Invalid ELF file\n") 422 return BPFdata{}, fmt.Errorf("Failed to Load the prog") 423 } 424 } 425 } 426 } 427 428 return bpfData, nil 429 } 430 431 func doLoadELF(r io.ReaderAt, bpfMap ebpf_maps.BpfMapAPIs, bpfProg ebpf_progs.BpfProgAPIs, customizedPinPath string) (map[string]BPFdata, map[string]ebpf_maps.BPFMap, error) { 432 //var log = logger.Get() 433 var err error 434 elfFile, err := elf.NewFile(r) 435 if err != nil { 436 return nil, nil, err 437 } 438 439 BPFloadedprog := make(map[string]BPFdata) 440 reloSectionMap := make(map[uint32]*elf.Section) 441 442 var dataMaps *elf.Section 443 var mapsShndx int 444 var strtabidx uint32 445 license := "" 446 for index, section := range elfFile.Sections { 447 if section.Name == "license" { 448 data, _ := section.Data() 449 if err != nil { 450 return nil, nil, fmt.Errorf("Failed to read data for section %s", section.Name) 451 } 452 license = string(data) 453 log.Infof("License %s", license) 454 break 455 } else if section.Name == "maps" { 456 dataMaps = section 457 mapsShndx = index 458 } 459 } 460 461 log.Infof("strtabidx %d", strtabidx) 462 463 var loadedMaps map[string]ebpf_maps.BPFMap 464 if dataMaps != nil { 465 loadedMaps, err = loadElfMapsSection(mapsShndx, dataMaps, elfFile, bpfMap, customizedPinPath) 466 if err != nil { 467 log.Infof("Failed to load map section") 468 return nil, nil, err 469 } 470 } 471 472 //Gather relocation section info 473 for _, reloSection := range elfFile.Sections { 474 if reloSection.Type == elf.SHT_REL { 475 log.Infof("Found a relocation section; Info:%v; Name: %s, Type: %s; Size: %v", reloSection.Info, 476 reloSection.Name, reloSection.Type, reloSection.Size) 477 reloSectionMap[reloSection.Info] = reloSection 478 } 479 } 480 481 //Load prog 482 for sectionIndex, section := range elfFile.Sections { 483 if section.Type != elf.SHT_PROGBITS { 484 continue 485 } 486 487 //TODO Create BPF Data -> 488 489 log.Infof("Found PROG Section at Index %v", sectionIndex) 490 splitProgType := strings.Split(section.Name, "/") 491 progType := strings.ToLower(splitProgType[0]) 492 var subProgType string 493 retrievedProgParams := len(splitProgType) 494 // Kprobe <kprobe/<prog name>> 495 if retrievedProgParams == 2 { 496 subProgType = strings.ToLower(splitProgType[1]) 497 log.Infof("Found subprog type %s", subProgType) 498 } 499 //Tracepoint <tracepoint/sched/<prog_name>> 500 var subSystem string 501 if retrievedProgParams == 3 { 502 subSystem = strings.ToLower(splitProgType[1]) 503 subProgType = strings.ToLower(splitProgType[2]) 504 log.Infof("Found subprog type %s", subSystem) 505 } 506 log.Infof("Found the progType %s", progType) 507 if progType != "xdp" && progType != "tc_cls" && progType != "tc_act" && progType != "kprobe" && progType != "tracepoint" && progType != "kretprobe" { 508 log.Infof("Not supported program %s", progType) 509 continue 510 } 511 dataProg := section 512 bpfData, err := loadElfProgSection(dataProg, reloSectionMap[uint32(sectionIndex)], license, progType, subSystem, subProgType, sectionIndex, elfFile, bpfProg, bpfMap, customizedPinPath, loadedMaps) 513 if err != nil { 514 log.Infof("Failed to load the prog") 515 return nil, nil, fmt.Errorf("Failed to load prog %q - %v", dataProg.Name, err) 516 } 517 BPFloadedprog[bpfData.Program.PinPath] = bpfData 518 } 519 520 return BPFloadedprog, loadedMaps, nil 521 } 522 523 func GetMapNameFromBPFPinPath(pinPath string) (string, string) { 524 //var log = logger.Get() 525 526 replicaNamespaceNameIdentifier := strings.Split(pinPath, "/") 527 podIdentifier := strings.SplitN(replicaNamespaceNameIdentifier[7], "_", 2) 528 log.Infof("Found Identified - %s : %s", podIdentifier[0], podIdentifier[1]) 529 530 replicaNamespace := podIdentifier[0] 531 mapName := podIdentifier[1] 532 533 log.Infof("Found -> ", replicaNamespace, mapName) 534 535 directionIdentifier := strings.Split(replicaNamespaceNameIdentifier[7], "_") 536 direction := directionIdentifier[1] 537 538 if direction == "ingress" { 539 log.Infof("Adding ingress_map -> ", replicaNamespace) 540 return "ingress_map", replicaNamespace 541 } else if direction == "egress" { 542 log.Infof("Adding egress_map -> ", replicaNamespace) 543 return "egress_map", replicaNamespace 544 } 545 546 //This is global map, we cannot use global since there are multiple maps 547 log.Infof("Adding GLOBAL %s -> %s", mapName, mapName) 548 return mapName, mapName 549 } 550 551 func IsMapGlobal(pinPath string) bool { 552 //var log = logger.Get() 553 554 replicaNamespaceNameIdentifier := strings.Split(pinPath, "/") 555 podIdentifier := strings.SplitN(replicaNamespaceNameIdentifier[7], "_", 2) 556 log.Infof("Found Identified - %s : %s", podIdentifier[0], podIdentifier[1]) 557 558 replicaNamespace := podIdentifier[0] 559 mapName := podIdentifier[1] 560 561 log.Infof("Found -> ", replicaNamespace, mapName) 562 563 directionIdentifier := strings.Split(replicaNamespaceNameIdentifier[7], "_") 564 direction := directionIdentifier[1] 565 566 if direction == "ingress" { 567 log.Infof("Found ingress_map -> ", replicaNamespace) 568 return false 569 } else if direction == "egress" { 570 log.Infof("Found egress_map -> ", replicaNamespace) 571 return false 572 } 573 574 //This is global map, we cannot use global since there are multiple maps 575 log.Infof("Found GLOBAL %s -> %s", mapName, mapName) 576 return true 577 578 } 579 580 func RecoverGlobalMaps() (map[string]ebpf_maps.BPFMap, error) { 581 //var log = logger.Get() 582 _, err := os.Stat(utils.BPF_DIR_MNT) 583 if err != nil { 584 log.Infof("BPF FS director is not present") 585 return nil, fmt.Errorf("BPF directory is not present %v", err) 586 } 587 loadedGlobalMaps := make(map[string]ebpf_maps.BPFMap) 588 mapsApi := &ebpf_maps.BPFMap{} 589 var statfs syscall.Statfs_t 590 if err := syscall.Statfs(utils.BPF_DIR_MNT, &statfs); err == nil && statfs.Type == unix.BPF_FS_MAGIC { 591 if err := filepath.Walk(utils.MAP_BPF_FS, func(pinPath string, fsinfo os.FileInfo, err error) error { 592 if err != nil { 593 return err 594 } 595 if !fsinfo.IsDir() { 596 log.Infof("Dumping pinpaths - ", pinPath) 597 if IsMapGlobal(pinPath) { 598 log.Infof("Found global pinpaths - ", pinPath) 599 bpfMapInfo, err := mapsApi.BpfGetMapFromPinPath(pinPath) 600 if err != nil { 601 log.Infof("Error getting mapInfo for Global pin path, this shouldn't happen") 602 return err 603 } 604 mapID := bpfMapInfo.Id 605 log.Infof("Got ID %d", mapID) 606 607 //Get map name 608 mapName, replicaNamespace := GetMapNameFromBPFPinPath(pinPath) 609 610 log.Infof("Adding ID %d to name %s and NS %s", mapID, mapName, replicaNamespace) 611 612 recoveredBpfMap := ebpf_maps.BPFMap{} 613 614 //Fill BPF map 615 recoveredBpfMap.MapID = uint32(mapID) 616 //Fill New FD since old FDs will be deleted on recovery 617 mapFD, err := utils.GetMapFDFromID(int(mapID)) 618 if err != nil { 619 log.Infof("Unable to GetFDfromID and ret %d and err %s", int(mapFD), err) 620 return fmt.Errorf("Unable to get FD: %s", err) 621 } 622 recoveredBpfMap.MapFD = uint32(mapFD) 623 log.Infof("Recovered FD %d", mapFD) 624 //Fill BPF map metadata 625 recoveredBpfMapMetaData := ebpf_maps.BpfMapData{ 626 Def: ebpf_maps.BpfMapDef{ 627 Type: bpfMapInfo.Type, 628 KeySize: bpfMapInfo.KeySize, 629 ValueSize: bpfMapInfo.ValueSize, 630 MaxEntries: bpfMapInfo.MaxEntries, 631 Flags: bpfMapInfo.MapFlags, 632 }, 633 Name: mapName, 634 } 635 recoveredBpfMap.MapMetaData = recoveredBpfMapMetaData 636 loadedGlobalMaps[pinPath] = recoveredBpfMap 637 } 638 } 639 return nil 640 }); err != nil { 641 log.Infof("Error walking bpfdirectory:", err) 642 return nil, fmt.Errorf("Error walking the bpfdirectory %v", err) 643 } 644 } else { 645 log.Infof("error checking BPF FS, might not be mounted %v", err) 646 return nil, fmt.Errorf("error checking BPF FS might not be mounted %v", err) 647 } 648 return loadedGlobalMaps, nil 649 } 650 651 func RecoverAllBpfProgramsAndMaps() (map[string]BPFdata, error) { 652 //var log = logger.Get() 653 _, err := os.Stat(utils.BPF_DIR_MNT) 654 if err != nil { 655 log.Infof("BPF FS directory is not present") 656 return nil, fmt.Errorf("BPF directory is not present %v", err) 657 } 658 659 var statfs syscall.Statfs_t 660 661 mapsApi := &ebpf_maps.BPFMap{} 662 showProgApi := &ebpf_progs.BPFProgram{} 663 664 //Pass DS here 665 loadedPrograms := make(map[string]BPFdata) 666 mapIDsToNames := make(map[int]string) 667 mapPodSelector := make(map[string]map[int]string) 668 mapIDsToFDs := make(map[int]int) 669 670 mapsDirExists := true 671 progsDirExists := true 672 _, err = os.Stat(utils.MAP_BPF_FS) 673 if err != nil { 674 mapsDirExists = false 675 } 676 677 _, err = os.Stat(utils.PROG_BPF_FS) 678 if err != nil { 679 progsDirExists = false 680 } 681 682 if err := syscall.Statfs(utils.BPF_DIR_MNT, &statfs); err == nil && statfs.Type == unix.BPF_FS_MAGIC { 683 log.Infof("BPF FS is mounted") 684 if mapsDirExists { 685 if err := filepath.Walk(utils.MAP_BPF_FS, func(pinPath string, fsinfo os.FileInfo, err error) error { 686 if err != nil { 687 return err 688 } 689 if !fsinfo.IsDir() { 690 log.Infof("Dumping pinpaths - ", pinPath) 691 bpfMapInfo, err := mapsApi.BpfGetMapFromPinPath(pinPath) 692 if err != nil { 693 log.Infof("Error getting mapInfo for pin path, this shouldn't happen") 694 return err 695 } 696 mapID := bpfMapInfo.Id 697 log.Infof("Got ID %d", mapID) 698 //Fill New FD since old FDs will be deleted on recovery 699 mapFD, err := utils.GetMapFDFromID(int(mapID)) 700 if err != nil { 701 log.Infof("Unable to GetFDfromID and ret %d and err %s", int(mapFD), err) 702 return fmt.Errorf("Unable to get FD: %s", err) 703 } 704 log.Infof("Got FD %d", mapFD) 705 mapIDsToFDs[int(mapID)] = mapFD 706 707 //Get map name 708 mapName, replicaNamespace := GetMapNameFromBPFPinPath(pinPath) 709 710 log.Infof("Adding ID %d to name %s and NS %s", mapID, mapName, replicaNamespace) 711 mapIDsToNames[int(mapID)] = mapName 712 mapPodSelector[replicaNamespace] = mapIDsToNames 713 } 714 return nil 715 }); err != nil { 716 log.Infof("Error walking bpfdirectory:", err) 717 return nil, fmt.Errorf("Error walking the bpfdirectory %v", err) 718 } 719 } 720 721 if progsDirExists { 722 if err := filepath.Walk(utils.PROG_BPF_FS, func(pinPath string, fsinfo os.FileInfo, err error) error { 723 if err != nil { 724 return err 725 } 726 if !fsinfo.IsDir() { 727 log.Infof("Dumping pinpaths - ", pinPath) 728 pgmData := ebpf_progs.BPFProgram{ 729 PinPath: pinPath, 730 } 731 replicaNamespaceNameIdentifier := strings.Split(pinPath, "/") 732 podIdentifier := strings.SplitN(replicaNamespaceNameIdentifier[7], "_", 2) 733 log.Infof("Found Identified - %s : %s", podIdentifier[0], podIdentifier[1]) 734 735 replicaNamespace := podIdentifier[0] 736 if replicaNamespace == "global" { 737 log.Infof("Skipping global progs") 738 return nil 739 } 740 741 //mapData := [string]ebpf_maps.BPFMap{} 742 bpfProgInfo, progFD, err := (showProgApi).BpfGetProgFromPinPath(pinPath) 743 if err != nil { 744 log.Infof("Failed to progInfo for pinPath %s", pinPath) 745 return err 746 } 747 pgmData.ProgFD = progFD 748 //Conv type to string here 749 750 recoveredMapData := make(map[string]ebpf_maps.BPFMap) 751 if bpfProgInfo.NrMapIDs > 0 { 752 log.Infof("Have associated maps to link") 753 _, associatedBpfMapList, _, associatedBPFMapIDs, err := ebpf_progs.BpfGetMapInfoFromProgInfo(progFD, bpfProgInfo.NrMapIDs) 754 if err != nil { 755 log.Infof("Failed to get associated maps") 756 return err 757 } 758 for mapInfoIdx := 0; mapInfoIdx < len(associatedBpfMapList); mapInfoIdx++ { 759 bpfMapInfo := associatedBpfMapList[mapInfoIdx] 760 newMapID := associatedBPFMapIDs[mapInfoIdx] 761 recoveredBpfMap := ebpf_maps.BPFMap{} 762 763 //Fill BPF map 764 recoveredBpfMap.MapID = uint32(newMapID) 765 //Fill New FD since old FDs will be deleted on recovery 766 mapFD, ok := mapIDsToFDs[int(newMapID)] 767 if !ok { 768 log.Infof("Unable to Get FD from ID %d", int(newMapID)) 769 return fmt.Errorf("Unable to get FD") 770 } 771 recoveredBpfMap.MapFD = uint32(mapFD) 772 773 mapIds, ok := mapPodSelector[replicaNamespace] 774 if !ok { 775 log.Infof("Failed to ID for %s", replicaNamespace) 776 return fmt.Errorf("Failed to get err") 777 } 778 mapName := mapIds[int(recoveredBpfMap.MapID)] 779 780 log.Infof("Mapinfo MapName - %v", bpfMapInfo.Name) 781 //Fill BPF map metadata 782 recoveredBpfMapMetaData := ebpf_maps.BpfMapData{ 783 Def: ebpf_maps.BpfMapDef{ 784 Type: bpfMapInfo.Type, 785 KeySize: bpfMapInfo.KeySize, 786 ValueSize: bpfMapInfo.ValueSize, 787 MaxEntries: bpfMapInfo.MaxEntries, 788 Flags: bpfMapInfo.MapFlags, 789 }, 790 Name: mapName, 791 } 792 recoveredBpfMap.MapMetaData = recoveredBpfMapMetaData 793 recoveredMapData[mapName] = recoveredBpfMap 794 } 795 796 } 797 recoveredBPFdata := BPFdata{ 798 Program: pgmData, 799 Maps: recoveredMapData, 800 } 801 loadedPrograms[pinPath] = recoveredBPFdata 802 } 803 return nil 804 }); err != nil { 805 log.Infof("Error walking bpfdirectory:", err) 806 return nil, fmt.Errorf("Error walking the bpfdirectory %v", err) 807 } 808 } 809 } else { 810 log.Infof("error checking BPF FS, might not be mounted %v", err) 811 return nil, fmt.Errorf("error checking BPF FS might not be mounted %v", err) 812 } 813 //Return DS here 814 return loadedPrograms, nil 815 }