Copyright 2018 The Prometheus Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

package procfs

import (
	
	
	
	
	
	
	
	
	
	
	

	
)
IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`.
Total count of connections.
Total incoming packages processed.
Total outgoing packages processed.
Total incoming traffic.
Total outgoing traffic.
IPVSBackendStatus holds current metrics of one virtual / real address pair.
The local (virtual) IP address.
The remote (real) IP address.
The local (virtual) port.
The remote (real) port.
The local firewall mark
The transport protocol (TCP, UDP).
The current number of active connections for this virtual/real address pair.
The current number of inactive connections for this virtual/real address pair.
The current weight of this virtual/real address pair.
IPVSStats reads the IPVS statistics from the specified `proc` filesystem.
func ( FS) () (IPVSStats, error) {
	,  := util.ReadFileNoStat(.proc.Path("net/ip_vs_stats"))
	if  != nil {
		return IPVSStats{}, 
	}

	return parseIPVSStats(bytes.NewReader())
}
parseIPVSStats performs the actual parsing of `ip_vs_stats`.
func ( io.Reader) (IPVSStats, error) {
	var (
		 []byte
		   []string
		  []string
		       IPVSStats
	)

	,  := ioutil.ReadAll()
	if  != nil {
		return IPVSStats{}, 
	}

	 = strings.SplitN(string(), "\n", 4)
	if len() != 4 {
		return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short")
	}

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

	.Connections,  = strconv.ParseUint([0], 16, 64)
	if  != nil {
		return IPVSStats{}, 
	}
	.IncomingPackets,  = strconv.ParseUint([1], 16, 64)
	if  != nil {
		return IPVSStats{}, 
	}
	.OutgoingPackets,  = strconv.ParseUint([2], 16, 64)
	if  != nil {
		return IPVSStats{}, 
	}
	.IncomingBytes,  = strconv.ParseUint([3], 16, 64)
	if  != nil {
		return IPVSStats{}, 
	}
	.OutgoingBytes,  = strconv.ParseUint([4], 16, 64)
	if  != nil {
		return IPVSStats{}, 
	}

	return , nil
}
IPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem.
func ( FS) () ([]IPVSBackendStatus, error) {
	,  := os.Open(.proc.Path("net/ip_vs"))
	if  != nil {
		return nil, 
	}
	defer .Close()

	return parseIPVSBackendStatus()
}

func ( io.Reader) ([]IPVSBackendStatus, error) {
	var (
		       []IPVSBackendStatus
		      = bufio.NewScanner()
		        string
		    string
		 net.IP
		    uint16
		          error
	)

	for .Scan() {
		 := strings.Fields(.Text())
		if len() == 0 {
			continue
		}
		switch {
		case [0] == "IP" || [0] == "Prot" || [1] == "RemoteAddress:Port":
			continue
		case [0] == "TCP" || [0] == "UDP":
			if len() < 2 {
				continue
			}
			 = [0]
			 = ""
			, ,  = parseIPPort([1])
			if  != nil {
				return nil, 
			}
		case [0] == "FWM":
			if len() < 2 {
				continue
			}
			 = [0]
			 = [1]
			 = nil
			 = 0
		case [0] == "->":
			if len() < 6 {
				continue
			}
			, ,  := parseIPPort([1])
			if  != nil {
				return nil, 
			}
			,  := strconv.ParseUint([3], 10, 64)
			if  != nil {
				return nil, 
			}
			,  := strconv.ParseUint([4], 10, 64)
			if  != nil {
				return nil, 
			}
			,  := strconv.ParseUint([5], 10, 64)
			if  != nil {
				return nil, 
			}
			 = append(, IPVSBackendStatus{
				LocalAddress:  ,
				LocalPort:     ,
				LocalMark:     ,
				RemoteAddress: ,
				RemotePort:    ,
				Proto:         ,
				Weight:        ,
				ActiveConn:    ,
				InactConn:     ,
			})
		}
	}
	return , nil
}

func ( string) (net.IP, uint16, error) {
	var (
		  net.IP
		 error
	)

	switch len() {
	case 13:
		,  = hex.DecodeString([0:8])
		if  != nil {
			return nil, 0, 
		}
	case 46:
		 = net.ParseIP([1:40])
		if  == nil {
			return nil, 0, fmt.Errorf("invalid IPv6 address: %s", [1:40])
		}
	default:
		return nil, 0, fmt.Errorf("unexpected IP:Port: %s", )
	}

	 := [len()-4:]
	if len() != 4 {
		return nil, 0, fmt.Errorf("unexpected port string format: %s", )
	}
	,  := strconv.ParseUint(, 16, 16)
	if  != nil {
		return nil, 0, 
	}

	return , uint16(), nil