cubefs

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

14
package procfs
15

16
import (
17
	"bufio"
18
	"bytes"
19
	"encoding/hex"
20
	"errors"
21
	"fmt"
22
	"io"
23
	"net"
24
	"os"
25
	"strconv"
26
	"strings"
27

28
	"github.com/prometheus/procfs/internal/util"
29
)
30

31
// IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`.
32
type IPVSStats struct {
33
	// Total count of connections.
34
	Connections uint64
35
	// Total incoming packages processed.
36
	IncomingPackets uint64
37
	// Total outgoing packages processed.
38
	OutgoingPackets uint64
39
	// Total incoming traffic.
40
	IncomingBytes uint64
41
	// Total outgoing traffic.
42
	OutgoingBytes uint64
43
}
44

45
// IPVSBackendStatus holds current metrics of one virtual / real address pair.
46
type IPVSBackendStatus struct {
47
	// The local (virtual) IP address.
48
	LocalAddress net.IP
49
	// The remote (real) IP address.
50
	RemoteAddress net.IP
51
	// The local (virtual) port.
52
	LocalPort uint16
53
	// The remote (real) port.
54
	RemotePort uint16
55
	// The local firewall mark
56
	LocalMark string
57
	// The transport protocol (TCP, UDP).
58
	Proto string
59
	// The current number of active connections for this virtual/real address pair.
60
	ActiveConn uint64
61
	// The current number of inactive connections for this virtual/real address pair.
62
	InactConn uint64
63
	// The current weight of this virtual/real address pair.
64
	Weight uint64
65
}
66

67
// IPVSStats reads the IPVS statistics from the specified `proc` filesystem.
68
func (fs FS) IPVSStats() (IPVSStats, error) {
69
	data, err := util.ReadFileNoStat(fs.proc.Path("net/ip_vs_stats"))
70
	if err != nil {
71
		return IPVSStats{}, err
72
	}
73

74
	return parseIPVSStats(bytes.NewReader(data))
75
}
76

77
// parseIPVSStats performs the actual parsing of `ip_vs_stats`.
78
func parseIPVSStats(r io.Reader) (IPVSStats, error) {
79
	var (
80
		statContent []byte
81
		statLines   []string
82
		statFields  []string
83
		stats       IPVSStats
84
	)
85

86
	statContent, err := io.ReadAll(r)
87
	if err != nil {
88
		return IPVSStats{}, err
89
	}
90

91
	statLines = strings.SplitN(string(statContent), "\n", 4)
92
	if len(statLines) != 4 {
93
		return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short")
94
	}
95

96
	statFields = strings.Fields(statLines[2])
97
	if len(statFields) != 5 {
98
		return IPVSStats{}, errors.New("ip_vs_stats corrupt: unexpected number of fields")
99
	}
100

101
	stats.Connections, err = strconv.ParseUint(statFields[0], 16, 64)
102
	if err != nil {
103
		return IPVSStats{}, err
104
	}
105
	stats.IncomingPackets, err = strconv.ParseUint(statFields[1], 16, 64)
106
	if err != nil {
107
		return IPVSStats{}, err
108
	}
109
	stats.OutgoingPackets, err = strconv.ParseUint(statFields[2], 16, 64)
110
	if err != nil {
111
		return IPVSStats{}, err
112
	}
113
	stats.IncomingBytes, err = strconv.ParseUint(statFields[3], 16, 64)
114
	if err != nil {
115
		return IPVSStats{}, err
116
	}
117
	stats.OutgoingBytes, err = strconv.ParseUint(statFields[4], 16, 64)
118
	if err != nil {
119
		return IPVSStats{}, err
120
	}
121

122
	return stats, nil
123
}
124

125
// IPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem.
126
func (fs FS) IPVSBackendStatus() ([]IPVSBackendStatus, error) {
127
	file, err := os.Open(fs.proc.Path("net/ip_vs"))
128
	if err != nil {
129
		return nil, err
130
	}
131
	defer file.Close()
132

133
	return parseIPVSBackendStatus(file)
134
}
135

136
func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
137
	var (
138
		status       []IPVSBackendStatus
139
		scanner      = bufio.NewScanner(file)
140
		proto        string
141
		localMark    string
142
		localAddress net.IP
143
		localPort    uint16
144
		err          error
145
	)
146

147
	for scanner.Scan() {
148
		fields := strings.Fields(scanner.Text())
149
		if len(fields) == 0 {
150
			continue
151
		}
152
		switch {
153
		case fields[0] == "IP" || fields[0] == "Prot" || fields[1] == "RemoteAddress:Port":
154
			continue
155
		case fields[0] == "TCP" || fields[0] == "UDP":
156
			if len(fields) < 2 {
157
				continue
158
			}
159
			proto = fields[0]
160
			localMark = ""
161
			localAddress, localPort, err = parseIPPort(fields[1])
162
			if err != nil {
163
				return nil, err
164
			}
165
		case fields[0] == "FWM":
166
			if len(fields) < 2 {
167
				continue
168
			}
169
			proto = fields[0]
170
			localMark = fields[1]
171
			localAddress = nil
172
			localPort = 0
173
		case fields[0] == "->":
174
			if len(fields) < 6 {
175
				continue
176
			}
177
			remoteAddress, remotePort, err := parseIPPort(fields[1])
178
			if err != nil {
179
				return nil, err
180
			}
181
			weight, err := strconv.ParseUint(fields[3], 10, 64)
182
			if err != nil {
183
				return nil, err
184
			}
185
			activeConn, err := strconv.ParseUint(fields[4], 10, 64)
186
			if err != nil {
187
				return nil, err
188
			}
189
			inactConn, err := strconv.ParseUint(fields[5], 10, 64)
190
			if err != nil {
191
				return nil, err
192
			}
193
			status = append(status, IPVSBackendStatus{
194
				LocalAddress:  localAddress,
195
				LocalPort:     localPort,
196
				LocalMark:     localMark,
197
				RemoteAddress: remoteAddress,
198
				RemotePort:    remotePort,
199
				Proto:         proto,
200
				Weight:        weight,
201
				ActiveConn:    activeConn,
202
				InactConn:     inactConn,
203
			})
204
		}
205
	}
206
	return status, nil
207
}
208

209
func parseIPPort(s string) (net.IP, uint16, error) {
210
	var (
211
		ip  net.IP
212
		err error
213
	)
214

215
	switch len(s) {
216
	case 13:
217
		ip, err = hex.DecodeString(s[0:8])
218
		if err != nil {
219
			return nil, 0, err
220
		}
221
	case 46:
222
		ip = net.ParseIP(s[1:40])
223
		if ip == nil {
224
			return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40])
225
		}
226
	default:
227
		return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s)
228
	}
229

230
	portString := s[len(s)-4:]
231
	if len(portString) != 4 {
232
		return nil, 0, fmt.Errorf("unexpected port string format: %s", portString)
233
	}
234
	port, err := strconv.ParseUint(portString, 16, 16)
235
	if err != nil {
236
		return nil, 0, err
237
	}
238

239
	return ip, uint16(port), nil
240
}
241

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

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

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

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