inspektor-gadget

Форк
0
247 строк · 6.5 Кб
1
// Copyright 2022-2023 The Inspektor Gadget authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
//go:build !withoutebpf
16

17
package tracer
18

19
import (
20
	"errors"
21
	"fmt"
22
	"os"
23
	"time"
24
	"unsafe"
25

26
	"github.com/cilium/ebpf"
27
	"github.com/cilium/ebpf/link"
28
	"github.com/cilium/ebpf/perf"
29

30
	gadgetcontext "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-context"
31
	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
32
	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/tcpconnect/types"
33
	eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
34
)
35

36
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags ${CFLAGS} -type event tcpconnect ./bpf/tcpconnect.bpf.c -- -I./bpf/
37

38
type Config struct {
39
	MountnsMap       *ebpf.Map
40
	CalculateLatency bool
41
	MinLatency       time.Duration
42
}
43

44
type Tracer struct {
45
	config        *Config
46
	enricher      gadgets.DataEnricherByMntNs
47
	eventCallback func(*types.Event)
48

49
	objs                   tcpconnectObjects
50
	v4EnterLink            link.Link
51
	v4ExitLink             link.Link
52
	v6EnterLink            link.Link
53
	v6ExitLink             link.Link
54
	tcpDestroySockLink     link.Link
55
	tcpRvcStateProcessLink link.Link
56
	reader                 *perf.Reader
57
}
58

59
func NewTracer(config *Config, enricher gadgets.DataEnricherByMntNs,
60
	eventCallback func(*types.Event),
61
) (*Tracer, error) {
62
	t := &Tracer{
63
		config:        config,
64
		enricher:      enricher,
65
		eventCallback: eventCallback,
66
	}
67

68
	if err := t.install(); err != nil {
69
		t.close()
70
		return nil, err
71
	}
72

73
	go t.run()
74

75
	return t, nil
76
}
77

78
// Stop stops the tracer
79
// TODO: Remove after refactoring
80
func (t *Tracer) Stop() {
81
	t.close()
82
}
83

84
func (t *Tracer) close() {
85
	t.v4EnterLink = gadgets.CloseLink(t.v4EnterLink)
86
	t.v4ExitLink = gadgets.CloseLink(t.v4ExitLink)
87
	t.v6EnterLink = gadgets.CloseLink(t.v6EnterLink)
88
	t.v6ExitLink = gadgets.CloseLink(t.v6ExitLink)
89
	t.tcpDestroySockLink = gadgets.CloseLink(t.tcpDestroySockLink)
90
	t.tcpRvcStateProcessLink = gadgets.CloseLink(t.tcpRvcStateProcessLink)
91

92
	t.objs.Close()
93
}
94

95
func (t *Tracer) install() error {
96
	var err error
97
	spec, err := loadTcpconnect()
98
	if err != nil {
99
		return fmt.Errorf("loading ebpf program: %w", err)
100
	}
101

102
	consts := map[string]interface{}{
103
		"targ_min_latency_ns": t.config.MinLatency,
104
		"calculate_latency":   t.config.CalculateLatency,
105
	}
106

107
	if err := gadgets.LoadeBPFSpec(t.config.MountnsMap, spec, consts, &t.objs); err != nil {
108
		return fmt.Errorf("loading ebpf spec: %w", err)
109
	}
110

111
	t.v4EnterLink, err = link.Kprobe("tcp_v4_connect", t.objs.IgTcpcV4CoE, nil)
112
	if err != nil {
113
		return fmt.Errorf("attaching kprobe: %w", err)
114
	}
115

116
	t.v6EnterLink, err = link.Kprobe("tcp_v6_connect", t.objs.IgTcpcV6CoE, nil)
117
	if err != nil {
118
		return fmt.Errorf("attaching kprobe: %w", err)
119
	}
120

121
	if !t.config.CalculateLatency {
122
		t.v4ExitLink, err = link.Kretprobe("tcp_v4_connect", t.objs.IgTcpcV4CoX, nil)
123
		if err != nil {
124
			return fmt.Errorf("attaching kretprobe: %w", err)
125
		}
126

127
		t.v6ExitLink, err = link.Kretprobe("tcp_v6_connect", t.objs.IgTcpcV6CoX, nil)
128
		if err != nil {
129
			return fmt.Errorf("attaching kretprobe: %w", err)
130
		}
131
	} else {
132
		t.tcpDestroySockLink, err = link.Tracepoint("tcp", "tcp_destroy_sock", t.objs.IgTcpDestroy, nil)
133
		if err != nil {
134
			return fmt.Errorf("attaching tracepoint: %w", err)
135
		}
136

137
		t.tcpRvcStateProcessLink, err = link.Kprobe("tcp_rcv_state_process", t.objs.IgTcpRsp, nil)
138
		if err != nil {
139
			return fmt.Errorf("attaching kprobe: %w", err)
140
		}
141
	}
142

143
	reader, err := perf.NewReader(t.objs.tcpconnectMaps.Events, gadgets.PerfBufferPages*os.Getpagesize())
144
	if err != nil {
145
		return fmt.Errorf("creating perf ring buffer: %w", err)
146
	}
147
	t.reader = reader
148

149
	return nil
150
}
151

152
func (t *Tracer) run() {
153
	for {
154
		record, err := t.reader.Read()
155
		if err != nil {
156
			if errors.Is(err, perf.ErrClosed) {
157
				// nothing to do, we're done
158
				return
159
			}
160

161
			msg := fmt.Sprintf("Error reading perf ring buffer: %s", err)
162
			t.eventCallback(types.Base(eventtypes.Err(msg)))
163
			return
164
		}
165

166
		if record.LostSamples > 0 {
167
			msg := fmt.Sprintf("lost %d samples", record.LostSamples)
168
			t.eventCallback(types.Base(eventtypes.Warn(msg)))
169
			continue
170
		}
171

172
		bpfEvent := (*tcpconnectEvent)(unsafe.Pointer(&record.RawSample[0]))
173

174
		ipversion := gadgets.IPVerFromAF(bpfEvent.Af)
175

176
		event := types.Event{
177
			Event: eventtypes.Event{
178
				Type:      eventtypes.NORMAL,
179
				Timestamp: gadgets.WallTimeFromBootTime(bpfEvent.Timestamp),
180
			},
181
			WithMountNsID: eventtypes.WithMountNsID{MountNsID: bpfEvent.MntnsId},
182
			Pid:           bpfEvent.Pid,
183
			Uid:           bpfEvent.Uid,
184
			Gid:           bpfEvent.Gid,
185
			Comm:          gadgets.FromCString(bpfEvent.Task[:]),
186
			SrcEndpoint: eventtypes.L4Endpoint{
187
				L3Endpoint: eventtypes.L3Endpoint{
188
					Addr:    gadgets.IPStringFromBytes(bpfEvent.SaddrV6, ipversion),
189
					Version: uint8(ipversion),
190
				},
191
				Port: gadgets.Htons(bpfEvent.Sport),
192
			},
193
			DstEndpoint: eventtypes.L4Endpoint{
194
				L3Endpoint: eventtypes.L3Endpoint{
195
					Addr:    gadgets.IPStringFromBytes(bpfEvent.DaddrV6, ipversion),
196
					Version: uint8(ipversion),
197
				},
198
				Port: gadgets.Htons(bpfEvent.Dport),
199
			},
200
			IPVersion: ipversion,
201
			Latency:   time.Duration(int64(bpfEvent.Latency)),
202
		}
203

204
		if t.enricher != nil {
205
			t.enricher.EnrichByMntNs(&event.CommonData, event.MountNsID)
206
		}
207

208
		t.eventCallback(&event)
209
	}
210
}
211

212
// --- Registry changes
213

214
func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error {
215
	params := gadgetCtx.GadgetParams()
216
	t.config.CalculateLatency = params.Get(ParamLatency).AsBool()
217
	t.config.MinLatency = params.Get(ParamMin).AsDuration()
218

219
	defer t.close()
220
	if err := t.install(); err != nil {
221
		return fmt.Errorf("installing tracer: %w", err)
222
	}
223

224
	go t.run()
225
	gadgetcontext.WaitForTimeoutOrDone(gadgetCtx)
226

227
	return nil
228
}
229

230
func (t *Tracer) SetMountNsMap(mountnsMap *ebpf.Map) {
231
	t.config.MountnsMap = mountnsMap
232
}
233

234
func (t *Tracer) SetEventHandler(handler any) {
235
	nh, ok := handler.(func(ev *types.Event))
236
	if !ok {
237
		panic("event handler invalid")
238
	}
239
	t.eventCallback = nh
240
}
241

242
func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) {
243
	tracer := &Tracer{
244
		config: &Config{},
245
	}
246
	return tracer, nil
247
}
248

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.