-
Notifications
You must be signed in to change notification settings - Fork 360
/
coll.go
170 lines (154 loc) · 3.78 KB
/
coll.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Tetragon
package program
import (
"errors"
"fmt"
"os"
"github.com/cilium/ebpf"
"github.com/cilium/tetragon/pkg/logger"
)
// The idea of LoadedCollection is to keep loaded programs and maps
// from ebpf.Collection to be used later for 'TestLoad*' tests to
// verify loaded programs and maps.
//
// We can't just iterate all existing programs and maps for 2 reasons:
// - we could race with others loading bpf programs
// - we get limited name (16 bytes), which we usually cross with
// our names for maps and programs
//
// The process of loading LoadedCollection is following:
//
// - ebpf collection is loaded
//
// coll := NewCollectionWithOptions
//
// - copy all programs/maps from ebpf collection
//
// copyLoadedCollection(lc, coll)
//
// - collection is removed and only 'used' programs and maps stay loaded
// so we filter out unused programs/maps with (based on their IDs)
//
// load.LC = filterLoadedCollection(lc)
//
// This way we have only programs/maps realted to our test and with
// original long names.
//
// All this is happening only when program.KeepCollection is set true,
// so it's enabled only for testing code.
var (
KeepCollection bool
)
type LoadedMap struct {
ID ebpf.MapID
}
type LoadedProgram struct {
ID ebpf.ProgramID
MapIDs []ebpf.MapID
Type ebpf.ProgramType
}
type LoadedCollection struct {
Programs map[string]*LoadedProgram
Maps map[string]*LoadedMap
}
func newLoadedCollection() *LoadedCollection {
lc := &LoadedCollection{}
lc.Maps = map[string]*LoadedMap{}
lc.Programs = map[string]*LoadedProgram{}
return lc
}
func printLoadedCollection(str string, lc *LoadedCollection) {
logger.GetLogger().Debugf("Programs (%s):", str)
for name, lp := range lc.Programs {
logger.GetLogger().Debugf(" - %d: %s - %v", lp.ID, name, lp.MapIDs)
}
logger.GetLogger().Debugf("Maps (%s):", str)
for name, lm := range lc.Maps {
logger.GetLogger().Debugf(" - %d: %s", lm.ID, name)
}
}
func copyLoadedCollection(coll *ebpf.Collection) (*LoadedCollection, error) {
if coll == nil {
return nil, fmt.Errorf("failed to get collection")
}
lc := newLoadedCollection()
// copy all loaded maps
for name, m := range coll.Maps {
info, err := m.Info()
if err != nil {
return nil, err
}
id, ok := info.ID()
if !ok {
return nil, fmt.Errorf("failed to get id")
}
lm := &LoadedMap{id}
lc.Maps[name] = lm
}
// copy all loaded programs with assigned map ids
for name, p := range coll.Programs {
info, err := p.Info()
if err != nil {
return nil, err
}
id, ok := info.ID()
if !ok {
return nil, fmt.Errorf("failed to get id")
}
mapIDs, ok := info.MapIDs()
lp := &LoadedProgram{ID: id}
if ok {
lp.MapIDs = mapIDs
}
lp.Type = p.Type()
lc.Programs[name] = lp
}
return lc, nil
}
// Gets all the programs/maps and removes any non existent ones
// from passed collection
func filterLoadedCollection(lc *LoadedCollection) *LoadedCollection {
ret := newLoadedCollection()
// filter out non existing programs
lastProg := ebpf.ProgramID(0)
for {
next, err := ebpf.ProgramGetNextID(lastProg)
if errors.Is(err, os.ErrNotExist) {
break
}
for name, lp := range lc.Programs {
if lp.ID == next {
ret.Programs[name] = lp
}
}
lastProg = next
}
// filter out non existing maps
lastMap := ebpf.MapID(0)
for {
next, err := ebpf.MapGetNextID(lastMap)
if errors.Is(err, os.ErrNotExist) {
break
}
for name, lm := range lc.Maps {
if lm.ID == next {
ret.Maps[name] = lm
}
}
lastMap = next
}
for _, lp := range lc.Programs {
var mapIDs []ebpf.MapID
for _, mi := range lp.MapIDs {
for _, lm := range lc.Maps {
if lm.ID == mi {
mapIDs = append(mapIDs, mi)
break
}
}
}
lp.MapIDs = mapIDs
}
return ret
}