source: code/trunk/vendor/github.com/prometheus/procfs/ipvs.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 5.9 KB
RevLine 
[822]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
14package procfs
15
16import (
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`.
32type 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.
46type 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.
68func (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`.
78func 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.
126func (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
136func 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
209func 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}
Note: See TracBrowser for help on using the repository browser.