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
6 // http://www.apache.org/licenses/LICENSE-2.0
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.
29 // IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`.
30 type IPVSStats struct {
31 // Total count of connections.
33 // Total incoming packages processed.
34 IncomingPackets uint64
35 // Total outgoing packages processed.
36 OutgoingPackets uint64
37 // Total incoming traffic.
39 // Total outgoing traffic.
43 // IPVSBackendStatus holds current metrics of one virtual / real address pair.
44 type IPVSBackendStatus struct {
45 // The local (virtual) IP address.
47 // The remote (real) IP address.
49 // The local (virtual) port.
51 // The remote (real) port.
53 // The local firewall mark
55 // The transport protocol (TCP, UDP).
57 // The current number of active connections for this virtual/real address pair.
59 // The current number of inactive connections for this virtual/real address pair.
61 // The current weight of this virtual/real address pair.
65 // NewIPVSStats reads the IPVS statistics.
66 func NewIPVSStats() (IPVSStats, error) {
67 fs, err := NewFS(DefaultMountPoint)
69 return IPVSStats{}, err
72 return fs.NewIPVSStats()
75 // NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem.
76 func (fs FS) NewIPVSStats() (IPVSStats, error) {
77 file, err := os.Open(fs.Path("net/ip_vs_stats"))
79 return IPVSStats{}, err
83 return parseIPVSStats(file)
86 // parseIPVSStats performs the actual parsing of `ip_vs_stats`.
87 func parseIPVSStats(file io.Reader) (IPVSStats, error) {
95 statContent, err := ioutil.ReadAll(file)
97 return IPVSStats{}, err
100 statLines = strings.SplitN(string(statContent), "\n", 4)
101 if len(statLines) != 4 {
102 return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short")
105 statFields = strings.Fields(statLines[2])
106 if len(statFields) != 5 {
107 return IPVSStats{}, errors.New("ip_vs_stats corrupt: unexpected number of fields")
110 stats.Connections, err = strconv.ParseUint(statFields[0], 16, 64)
112 return IPVSStats{}, err
114 stats.IncomingPackets, err = strconv.ParseUint(statFields[1], 16, 64)
116 return IPVSStats{}, err
118 stats.OutgoingPackets, err = strconv.ParseUint(statFields[2], 16, 64)
120 return IPVSStats{}, err
122 stats.IncomingBytes, err = strconv.ParseUint(statFields[3], 16, 64)
124 return IPVSStats{}, err
126 stats.OutgoingBytes, err = strconv.ParseUint(statFields[4], 16, 64)
128 return IPVSStats{}, err
134 // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs.
135 func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) {
136 fs, err := NewFS(DefaultMountPoint)
138 return []IPVSBackendStatus{}, err
141 return fs.NewIPVSBackendStatus()
144 // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem.
145 func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) {
146 file, err := os.Open(fs.Path("net/ip_vs"))
152 return parseIPVSBackendStatus(file)
155 func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
157 status []IPVSBackendStatus
158 scanner = bufio.NewScanner(file)
167 fields := strings.Fields(scanner.Text())
168 if len(fields) == 0 {
172 case fields[0] == "IP" || fields[0] == "Prot" || fields[1] == "RemoteAddress:Port":
174 case fields[0] == "TCP" || fields[0] == "UDP":
180 localAddress, localPort, err = parseIPPort(fields[1])
184 case fields[0] == "FWM":
189 localMark = fields[1]
192 case fields[0] == "->":
196 remoteAddress, remotePort, err := parseIPPort(fields[1])
200 weight, err := strconv.ParseUint(fields[3], 10, 64)
204 activeConn, err := strconv.ParseUint(fields[4], 10, 64)
208 inactConn, err := strconv.ParseUint(fields[5], 10, 64)
212 status = append(status, IPVSBackendStatus{
213 LocalAddress: localAddress,
214 LocalPort: localPort,
215 LocalMark: localMark,
216 RemoteAddress: remoteAddress,
217 RemotePort: remotePort,
220 ActiveConn: activeConn,
221 InactConn: inactConn,
228 func parseIPPort(s string) (net.IP, uint16, error) {
236 ip, err = hex.DecodeString(s[0:8])
241 ip = net.ParseIP(s[1:40])
243 return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40])
246 return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s)
249 portString := s[len(s)-4:]
250 if len(portString) != 4 {
251 return nil, 0, fmt.Errorf("unexpected port string format: %s", portString)
253 port, err := strconv.ParseUint(portString, 16, 16)
258 return ip, uint16(port), nil