-
Notifications
You must be signed in to change notification settings - Fork 10
/
map.go
133 lines (114 loc) · 3.23 KB
/
map.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package manager
import (
"errors"
"fmt"
"sync"
"github.com/cilium/ebpf"
)
// MapCleanupType - The map clean up type defines how the maps of a manager should be cleaned up on exit.
//
// A map can only be in one of the following categories
//
// ----------------------
// | Internally loaded |
// ----------------------
// Categories: | Pinned | Not Pinned |
// ----------------------
type MapCleanupType int
const (
CleanInternalPinned MapCleanupType = 1 << 1
CleanInternalNotPinned MapCleanupType = 1 << 2
CleanInternal = CleanInternalPinned | CleanInternalNotPinned
CleanAll = CleanInternal
)
// MapOptions - Generic Map options that are not shared with the MapSpec definition
type MapOptions struct {
// PinPath - Once loaded, the eBPF map will be pinned to this path. If the map has already been pinned and is
// already present in the kernel, then it will be loaded from this path.
PinPath string
// AlwaysCleanup - Overrides the cleanup type given to the manager. See CleanupType for more.
AlwaysCleanup bool
}
type Map struct {
array *ebpf.Map
arraySpec *ebpf.MapSpec
state state
stateLock sync.Mutex
// Name - Name of the map as defined in its section SEC("maps/[name]")
Name string
// Contents - The initial contents of the map. May be nil.
Contents []ebpf.MapKV
// Freeze - Whether to freeze a map after setting its initial contents.
Freeze bool
// Other options
MapOptions
}
// loadNewMap - Creates a new map instance, loads it and returns a pointer to the Map structure
func loadNewMap(spec *ebpf.MapSpec, options MapOptions) (*Map, error) {
// Create new map
managerMap := Map{
arraySpec: spec,
Name: spec.Name,
Contents: spec.Contents,
Freeze: spec.Freeze,
MapOptions: options,
}
// Load map
var err error
if managerMap.array, err = ebpf.NewMap(spec); err != nil {
return nil, err
}
// Pin map if need be
if managerMap.PinPath != "" {
if err = managerMap.array.Pin(managerMap.PinPath); err != nil {
return nil, fmt.Errorf("couldn't pin map %s at %s: %w", managerMap.Name, managerMap.PinPath, err)
}
}
return &managerMap, nil
}
// init - Initialize a map
func (m *Map) init() error {
m.stateLock.Lock()
defer m.stateLock.Unlock()
if m.state >= initialized {
return ErrMapInitialized
}
m.state = initialized
return nil
}
// Close - Close underlying eBPF map.
func (m *Map) Close(cleanup MapCleanupType) error {
m.stateLock.Lock()
defer m.stateLock.Unlock()
if m.state < initialized {
return ErrMapInitialized
}
return m.close(cleanup)
}
// close - (not thread safe) close
func (m *Map) close(cleanup MapCleanupType) error {
shouldClose := false
if m.AlwaysCleanup {
shouldClose = true
}
if cleanup&CleanInternalPinned == CleanInternalPinned && m.array.IsPinned() {
shouldClose = true
}
if cleanup&CleanInternalNotPinned == CleanInternalNotPinned && !m.array.IsPinned() {
shouldClose = true
}
if shouldClose {
err := errors.Join(m.array.Unpin(), m.array.Close())
if err != nil {
return err
}
m.reset()
}
return nil
}
// reset - Cleans up the internal fields of the map
func (m *Map) reset() {
m.array = nil
m.arraySpec = nil
m.state = reset
}