inspektor-gadget

Форк
0
123 строки · 3.8 Кб
1
// Copyright 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
	"context"
21
	"errors"
22
	"fmt"
23
	"time"
24

25
	"github.com/cilium/ebpf"
26

27
	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
28
	"github.com/inspektor-gadget/inspektor-gadget/pkg/logger"
29
	"github.com/inspektor-gadget/inspektor-gadget/pkg/types"
30
)
31

32
// Delay between each garbage collection run.
33
const garbageCollectorInterval = 1 * time.Second
34

35
// Maximum size of a batch to lookup and delete.
36
// Setting this higher reduces the number of syscalls to GC a full map, but uses more memory.
37
const garbageCollectorBatchSize = 256
38

39
// startGarbageCollector runs a background goroutine to delete old query timestamps
40
// from the DNS query_map. This ensures that queries that never receive a response
41
// are deleted from the map.
42
//
43
// The garbage collector goroutine terminates when the context is done.
44
func startGarbageCollector(ctx context.Context, logger logger.Logger, dnsTimeout time.Duration, queryMap *ebpf.Map) {
45
	if !gadgets.HasBpfKtimeGetBootNs() {
46
		logger.Warnf("DNS latency will not be reported (requires Linux kernel 5.8 or later)")
47
		return
48
	}
49

50
	logger.Debugf("starting garbage collection for DNS tracer with dnsTimeout %s", dnsTimeout)
51
	go func() {
52
		// Allocate the keys/values arrays once and reuse for each iteration.
53
		var (
54
			keysBatch   [garbageCollectorBatchSize]dnsQueryKeyT
55
			valuesBatch [garbageCollectorBatchSize]uint64
56
		)
57

58
		ticker := time.NewTicker(garbageCollectorInterval)
59
		defer ticker.Stop()
60

61
		for {
62
			select {
63
			case <-ctx.Done():
64
				logger.Debugf("stopping garbage collection for DNS tracer")
65
				return
66

67
			case <-ticker.C:
68
				logger.Debugf("executing DNS query map garbage collection")
69
				numDeleted, err := collectGarbage(dnsTimeout, queryMap, keysBatch[:], valuesBatch[:])
70
				if err != nil {
71
					logger.Errorf("collecting garbage: %w", err)
72
				} else if numDeleted > 0 {
73
					logger.Debugf("deleted %d entries from DNS query map", numDeleted)
74
				}
75
			}
76
		}
77
	}()
78
}
79

80
func collectGarbage(dnsTimeout time.Duration, queryMap *ebpf.Map, keysBatch []dnsQueryKeyT, valuesBatch []uint64) (int, error) {
81
	var (
82
		keysToDelete []dnsQueryKeyT
83
		prevKeyOut   interface{}
84
		nextKeyOut   dnsQueryKeyT
85
	)
86

87
	// Nil means start from the beginning.
88
	// Type of prevKeyOut is interface{}, not dnsQueryKeyT, to ensure that the first call
89
	// to BatchLookup sees an untyped nil (not an interface with value nil); otherwise it crashes.
90
	prevKeyOut = nil
91

92
	for {
93
		n, err := queryMap.BatchLookup(prevKeyOut, &nextKeyOut, keysBatch, valuesBatch, nil)
94
		if err != nil && !errors.Is(err, ebpf.ErrKeyNotExist) {
95
			return 0, fmt.Errorf("looking up keys in query map: %w", err)
96
		}
97

98
		cutoffTs := types.Time(time.Now().Add(-1 * dnsTimeout).UnixNano())
99
		for i := 0; i < n; i++ {
100
			ts := gadgets.WallTimeFromBootTime(valuesBatch[i])
101
			if ts < cutoffTs {
102
				keysToDelete = append(keysToDelete, keysBatch[i])
103
			}
104
		}
105

106
		if errors.Is(err, ebpf.ErrKeyNotExist) {
107
			// This error means there are no more keys after the ones we just read.
108
			break
109
		}
110

111
		prevKeyOut = nextKeyOut
112
	}
113

114
	if len(keysToDelete) == 0 {
115
		return 0, nil
116
	}
117

118
	n, err := queryMap.BatchDelete(keysToDelete, nil)
119
	if err != nil {
120
		return 0, fmt.Errorf("deleting keys from query map: %w", err)
121
	}
122
	return n, nil
123
}
124

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

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

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

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