github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/pin.go (about)

     1  package gobpfld
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path"
     8  	"strings"
     9  	"unsafe"
    10  
    11  	"github.com/dylandreimerink/gobpfld/bpfsys"
    12  	"github.com/dylandreimerink/gobpfld/internal/cstr"
    13  )
    14  
    15  // BPFSysPath is the path to the bpf FS used to pin objects to
    16  const BPFSysPath = "/sys/fs/bpf/"
    17  
    18  // PinFD pins an eBPF object(map, program, link) identified by the given `fd` to the given `relativePath`
    19  // relative to the `BPFSysPath` on the BPF FS.
    20  //
    21  // This function is exposed so custom program or map implementations can use outside of this library.
    22  // However, it is recommendd to use the BPFProgram.Pin and AbstractMap.Pin functions if gobpfld types are used.
    23  func PinFD(relativePath string, fd bpfsys.BPFfd) error {
    24  	sysPath := fmt.Sprint(BPFSysPath, relativePath)
    25  
    26  	// Create directories if any are missing
    27  	err := os.MkdirAll(path.Dir(sysPath), 0644)
    28  	if err != nil {
    29  		return fmt.Errorf("error while making directories: %w, make sure bpffs is mounted at '%s'", err, BPFSysPath)
    30  	}
    31  
    32  	cPath := cstr.StringToCStrBytes(sysPath)
    33  
    34  	err = bpfsys.ObjectPin(&bpfsys.BPFAttrObj{
    35  		BPFfd:    fd,
    36  		Pathname: uintptr(unsafe.Pointer(&cPath[0])),
    37  	})
    38  	if err != nil {
    39  		return fmt.Errorf("bpf syscall error: %w", err)
    40  	}
    41  
    42  	return nil
    43  }
    44  
    45  // UnpinFD gets the fd of an eBPF object(map, program, link) which is pinned at the given `relativePath`
    46  // relative to the `BPFSysPath` on the BPF FS.
    47  // If `deletePin` is true, this function will remove the pin from the BPF FS after successfully getting it.
    48  //
    49  // This function is exposed so custom program or map implementations can use outside of this library.
    50  // However, it is recommend to use the BPFProgram.Unpin and AbstractMap.Unpin functions if gobpfld types are used.
    51  //
    52  // TODO make this function unexported and create an UnpinMap and UnpinProgram function which will automatically recreate
    53  //  the proper maps. (also necessary to handle map registration properly)
    54  func UnpinFD(relativePath string, deletePin bool) (bpfsys.BPFfd, error) {
    55  	sysPath := fmt.Sprint(BPFSysPath, relativePath)
    56  	cpath := cstr.StringToCStrBytes(sysPath)
    57  
    58  	fd, err := bpfsys.ObjectGet(&bpfsys.BPFAttrObj{
    59  		Pathname: uintptr(unsafe.Pointer(&cpath[0])),
    60  	})
    61  	if err != nil {
    62  		return fd, fmt.Errorf("bpf obj get syscall error: %w", err)
    63  	}
    64  
    65  	if deletePin {
    66  		err = os.Remove(sysPath)
    67  		if err != nil {
    68  			return fd, fmt.Errorf("error while deleting pin: %w", err)
    69  		}
    70  
    71  		// Get the directories in the relative path
    72  		dirs := path.Dir(relativePath)
    73  		if dirs == "." || dirs == "/" {
    74  			dirs = ""
    75  		}
    76  
    77  		// get array of dirs
    78  		relDirs := strings.Split(dirs, string(os.PathSeparator))
    79  		// If there is at least one directory
    80  		if relDirs[0] != "" {
    81  			// Loop over all directories
    82  			for _, dir := range relDirs {
    83  				dirPath := fmt.Sprint(BPFSysPath, dir)
    84  				files, err := ioutil.ReadDir(dirPath)
    85  				if err != nil {
    86  					return fd, fmt.Errorf("error while reading dir: %w", err)
    87  				}
    88  
    89  				// If the dir is empty, remove it
    90  				if len(files) == 0 {
    91  					err = os.Remove(dirPath)
    92  					if err != nil {
    93  						return fd, fmt.Errorf("error while deleting empty dir: %w", err)
    94  					}
    95  				}
    96  			}
    97  		}
    98  	}
    99  
   100  	return fd, nil
   101  }