cubefs

Форк
0
163 строки · 4.3 Кб
1
// Copyright 2019 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
	"errors"
20
	"fmt"
21
	"io"
22
	"strings"
23

24
	"github.com/prometheus/procfs/internal/util"
25
)
26

27
// A NetSockstat contains the output of /proc/net/sockstat{,6} for IPv4 or IPv6,
28
// respectively.
29
type NetSockstat struct {
30
	// Used is non-nil for IPv4 sockstat results, but nil for IPv6.
31
	Used      *int
32
	Protocols []NetSockstatProtocol
33
}
34

35
// A NetSockstatProtocol contains statistics about a given socket protocol.
36
// Pointer fields indicate that the value may or may not be present on any
37
// given protocol.
38
type NetSockstatProtocol struct {
39
	Protocol string
40
	InUse    int
41
	Orphan   *int
42
	TW       *int
43
	Alloc    *int
44
	Mem      *int
45
	Memory   *int
46
}
47

48
// NetSockstat retrieves IPv4 socket statistics.
49
func (fs FS) NetSockstat() (*NetSockstat, error) {
50
	return readSockstat(fs.proc.Path("net", "sockstat"))
51
}
52

53
// NetSockstat6 retrieves IPv6 socket statistics.
54
//
55
// If IPv6 is disabled on this kernel, the returned error can be checked with
56
// os.IsNotExist.
57
func (fs FS) NetSockstat6() (*NetSockstat, error) {
58
	return readSockstat(fs.proc.Path("net", "sockstat6"))
59
}
60

61
// readSockstat opens and parses a NetSockstat from the input file.
62
func readSockstat(name string) (*NetSockstat, error) {
63
	// This file is small and can be read with one syscall.
64
	b, err := util.ReadFileNoStat(name)
65
	if err != nil {
66
		// Do not wrap this error so the caller can detect os.IsNotExist and
67
		// similar conditions.
68
		return nil, err
69
	}
70

71
	stat, err := parseSockstat(bytes.NewReader(b))
72
	if err != nil {
73
		return nil, fmt.Errorf("failed to read sockstats from %q: %w", name, err)
74
	}
75

76
	return stat, nil
77
}
78

79
// parseSockstat reads the contents of a sockstat file and parses a NetSockstat.
80
func parseSockstat(r io.Reader) (*NetSockstat, error) {
81
	var stat NetSockstat
82
	s := bufio.NewScanner(r)
83
	for s.Scan() {
84
		// Expect a minimum of a protocol and one key/value pair.
85
		fields := strings.Split(s.Text(), " ")
86
		if len(fields) < 3 {
87
			return nil, fmt.Errorf("malformed sockstat line: %q", s.Text())
88
		}
89

90
		// The remaining fields are key/value pairs.
91
		kvs, err := parseSockstatKVs(fields[1:])
92
		if err != nil {
93
			return nil, fmt.Errorf("error parsing sockstat key/value pairs from %q: %w", s.Text(), err)
94
		}
95

96
		// The first field is the protocol. We must trim its colon suffix.
97
		proto := strings.TrimSuffix(fields[0], ":")
98
		switch proto {
99
		case "sockets":
100
			// Special case: IPv4 has a sockets "used" key/value pair that we
101
			// embed at the top level of the structure.
102
			used := kvs["used"]
103
			stat.Used = &used
104
		default:
105
			// Parse all other lines as individual protocols.
106
			nsp := parseSockstatProtocol(kvs)
107
			nsp.Protocol = proto
108
			stat.Protocols = append(stat.Protocols, nsp)
109
		}
110
	}
111

112
	if err := s.Err(); err != nil {
113
		return nil, err
114
	}
115

116
	return &stat, nil
117
}
118

119
// parseSockstatKVs parses a string slice into a map of key/value pairs.
120
func parseSockstatKVs(kvs []string) (map[string]int, error) {
121
	if len(kvs)%2 != 0 {
122
		return nil, errors.New("odd number of fields in key/value pairs")
123
	}
124

125
	// Iterate two values at a time to gather key/value pairs.
126
	out := make(map[string]int, len(kvs)/2)
127
	for i := 0; i < len(kvs); i += 2 {
128
		vp := util.NewValueParser(kvs[i+1])
129
		out[kvs[i]] = vp.Int()
130

131
		if err := vp.Err(); err != nil {
132
			return nil, err
133
		}
134
	}
135

136
	return out, nil
137
}
138

139
// parseSockstatProtocol parses a NetSockstatProtocol from the input kvs map.
140
func parseSockstatProtocol(kvs map[string]int) NetSockstatProtocol {
141
	var nsp NetSockstatProtocol
142
	for k, v := range kvs {
143
		// Capture the range variable to ensure we get unique pointers for
144
		// each of the optional fields.
145
		v := v
146
		switch k {
147
		case "inuse":
148
			nsp.InUse = v
149
		case "orphan":
150
			nsp.Orphan = &v
151
		case "tw":
152
			nsp.TW = &v
153
		case "alloc":
154
			nsp.Alloc = &v
155
		case "mem":
156
			nsp.Mem = &v
157
		case "memory":
158
			nsp.Memory = &v
159
		}
160
	}
161

162
	return nsp
163
}
164

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

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

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

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