github.com/openshift/dpu-operator@v0.0.0-20240502153209-3af840d137c2/dpu-cni/pkgs/sriovutils/pci_allocator.go (about) 1 package sriovutils 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 8 "github.com/containernetworking/plugins/pkg/ns" 9 ) 10 11 type PCIAllocation interface { 12 SaveAllocatedPCI(string, string) error 13 DeleteAllocatedPCI(string) error 14 IsAllocated(string) error 15 } 16 17 type PCIAllocator struct { 18 dataDir string 19 } 20 21 // NewPCIAllocator returns a new PCI allocator 22 // it will use the <dataDir>/pci folder to store the information about allocated PCI addresses 23 func NewPCIAllocator(dataDir string) *PCIAllocator { 24 return &PCIAllocator{dataDir: filepath.Join(dataDir, "pci")} 25 } 26 27 // SaveAllocatedPCI creates a file with the pci address as a name and the network namespace as the content 28 // return error if the file was not created 29 func (p *PCIAllocator) SaveAllocatedPCI(pciAddress, ns string) error { 30 if err := os.MkdirAll(p.dataDir, 0600); err != nil { 31 return fmt.Errorf("failed to create the sriov data directory(%q): %v", p.dataDir, err) 32 } 33 34 path := filepath.Join(p.dataDir, pciAddress) 35 err := os.WriteFile(path, []byte(ns), 0600) 36 if err != nil { 37 return fmt.Errorf("failed to write used PCI address lock file in the path(%q): %v", path, err) 38 } 39 40 return err 41 } 42 43 // DeleteAllocatedPCI Remove the allocated PCI file 44 // return error if the file doesn't exist 45 func (p *PCIAllocator) DeleteAllocatedPCI(pciAddress string) error { 46 path := filepath.Join(p.dataDir, pciAddress) 47 if err := os.Remove(path); err != nil { 48 return fmt.Errorf("error removing PCI address lock file %s: %v", path, err) 49 } 50 return nil 51 } 52 53 // IsAllocated checks if the PCI address file exist 54 // if it exists we also check the network namespace still exist if not we delete the allocation 55 // The function will return an error if the pci is still allocated to a running pod 56 func (p *PCIAllocator) IsAllocated(pciAddress string) (bool, error) { 57 path := filepath.Join(p.dataDir, pciAddress) 58 _, err := os.Stat(path) 59 if err != nil { 60 if os.IsNotExist(err) { 61 return false, nil 62 } 63 64 return false, fmt.Errorf("failed to check for pci address file for %s: %v", path, err) 65 } 66 67 dat, err := os.ReadFile(path) 68 if err != nil { 69 return false, fmt.Errorf("failed to read for pci address file for %s: %v", path, err) 70 } 71 72 // To prevent a locking of a PCI address for every pciAddress file we also add the netns path where it's been used 73 // This way if for some reason the cmdDel command was not called but the pod namespace doesn't exist anymore 74 // we release the PCI address 75 networkNamespace, err := ns.GetNS(string(dat)) 76 if err != nil { 77 // FIXME: Fix Logging 78 //logging.Debug("Mark the PCI address as released", 79 // "func", "IsAllocated", 80 // "pciAddress", pciAddress) 81 err = p.DeleteAllocatedPCI(pciAddress) 82 if err != nil { 83 return false, fmt.Errorf("error deleting the pci allocation for vf pci address %s: %v", pciAddress, err) 84 } 85 86 return false, nil 87 } 88 89 // Close the network namespace 90 networkNamespace.Close() 91 return true, nil 92 }