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