// Copyright 2022 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 ( "bufio" "bytes" "fmt" "io" "strconv" "strings" "github.com/prometheus/procfs/internal/util" ) // ProcSnmp models the content of /proc/<pid>/net/snmp. type ProcSnmp struct { // The process ID. PID int Ip Icmp IcmpMsg Tcp Udp UdpLite } type Ip struct { // nolint:revive Forwarding *float64 DefaultTTL *float64 InReceives *float64 InHdrErrors *float64 InAddrErrors *float64 ForwDatagrams *float64 InUnknownProtos *float64 InDiscards *float64 InDelivers *float64 OutRequests *float64 OutDiscards *float64 OutNoRoutes *float64 ReasmTimeout *float64 ReasmReqds *float64 ReasmOKs *float64 ReasmFails *float64 FragOKs *float64 FragFails *float64 FragCreates *float64 } type Icmp struct { // nolint:revive InMsgs *float64 InErrors *float64 InCsumErrors *float64 InDestUnreachs *float64 InTimeExcds *float64 InParmProbs *float64 InSrcQuenchs *float64 InRedirects *float64 InEchos *float64 InEchoReps *float64 InTimestamps *float64 InTimestampReps *float64 InAddrMasks *float64 InAddrMaskReps *float64 OutMsgs *float64 OutErrors *float64 OutDestUnreachs *float64 OutTimeExcds *float64 OutParmProbs *float64 OutSrcQuenchs *float64 OutRedirects *float64 OutEchos *float64 OutEchoReps *float64 OutTimestamps *float64 OutTimestampReps *float64 OutAddrMasks *float64 OutAddrMaskReps *float64 } type IcmpMsg struct { InType3 *float64 OutType3 *float64 } type Tcp struct { // nolint:revive RtoAlgorithm *float64 RtoMin *float64 RtoMax *float64 MaxConn *float64 ActiveOpens *float64 PassiveOpens *float64 AttemptFails *float64 EstabResets *float64 CurrEstab *float64 InSegs *float64 OutSegs *float64 RetransSegs *float64 InErrs *float64 OutRsts *float64 InCsumErrors *float64 } type Udp struct { // nolint:revive InDatagrams *float64 NoPorts *float64 InErrors *float64 OutDatagrams *float64 RcvbufErrors *float64 SndbufErrors *float64 InCsumErrors *float64 IgnoredMulti *float64 } type UdpLite struct { // nolint:revive InDatagrams *float64 NoPorts *float64 InErrors *float64 OutDatagrams *float64 RcvbufErrors *float64 SndbufErrors *float64 InCsumErrors *float64 IgnoredMulti *float64 } func (p Proc) Snmp() (ProcSnmp, error) { filename := p.path("net/snmp") data, err := util.ReadFileNoStat(filename) if err != nil { return ProcSnmp{PID: p.PID}, err } procSnmp, err := parseSnmp(bytes.NewReader(data), filename) procSnmp.PID = p.PID return procSnmp, err } // parseSnmp parses the metrics from proc/<pid>/net/snmp file // and returns a map contains those metrics (e.g. {"Ip": {"Forwarding": 2}}). func parseSnmp(r io.Reader, fileName string) (ProcSnmp, error) { var ( scanner = bufio.NewScanner(r) procSnmp = ProcSnmp{} ) for scanner.Scan() { nameParts := strings.Split(scanner.Text(), " ") scanner.Scan() valueParts := strings.Split(scanner.Text(), " ") // Remove trailing :. protocol := strings.TrimSuffix(nameParts[0], ":") if len(nameParts) != len(valueParts) { return procSnmp, fmt.Errorf("%w: mismatch field count mismatch in %s: %s", ErrFileParse, fileName, protocol) } for i := 1; i < len(nameParts); i++ { value, err := strconv.ParseFloat(valueParts[i], 64) if err != nil { return procSnmp, err } key := nameParts[i] switch protocol { case "Ip": switch key { case "Forwarding": procSnmp.Ip.Forwarding = &value case "DefaultTTL": procSnmp.Ip.DefaultTTL = &value case "InReceives": procSnmp.Ip.InReceives = &value case "InHdrErrors": procSnmp.Ip.InHdrErrors = &value case "InAddrErrors": procSnmp.Ip.InAddrErrors = &value case "ForwDatagrams": procSnmp.Ip.ForwDatagrams = &value case "InUnknownProtos": procSnmp.Ip.InUnknownProtos = &value case "InDiscards": procSnmp.Ip.InDiscards = &value case "InDelivers": procSnmp.Ip.InDelivers = &value case "OutRequests": procSnmp.Ip.OutRequests = &value case "OutDiscards": procSnmp.Ip.OutDiscards = &value case "OutNoRoutes": procSnmp.Ip.OutNoRoutes = &value case "ReasmTimeout": procSnmp.Ip.ReasmTimeout = &value case "ReasmReqds": procSnmp.Ip.ReasmReqds = &value case "ReasmOKs": procSnmp.Ip.ReasmOKs = &value case "ReasmFails": procSnmp.Ip.ReasmFails = &value case "FragOKs": procSnmp.Ip.FragOKs = &value case "FragFails": procSnmp.Ip.FragFails = &value case "FragCreates": procSnmp.Ip.FragCreates = &value } case "Icmp": switch key { case "InMsgs": procSnmp.Icmp.InMsgs = &value case "InErrors": procSnmp.Icmp.InErrors = &value case "InCsumErrors": procSnmp.Icmp.InCsumErrors = &value case "InDestUnreachs": procSnmp.Icmp.InDestUnreachs = &value case "InTimeExcds": procSnmp.Icmp.InTimeExcds = &value case "InParmProbs": procSnmp.Icmp.InParmProbs = &value case "InSrcQuenchs": procSnmp.Icmp.InSrcQuenchs = &value case "InRedirects": procSnmp.Icmp.InRedirects = &value case "InEchos": procSnmp.Icmp.InEchos = &value case "InEchoReps": procSnmp.Icmp.InEchoReps = &value case "InTimestamps": procSnmp.Icmp.InTimestamps = &value case "InTimestampReps": procSnmp.Icmp.InTimestampReps = &value case "InAddrMasks": procSnmp.Icmp.InAddrMasks = &value case "InAddrMaskReps": procSnmp.Icmp.InAddrMaskReps = &value case "OutMsgs": procSnmp.Icmp.OutMsgs = &value case "OutErrors": procSnmp.Icmp.OutErrors = &value case "OutDestUnreachs": procSnmp.Icmp.OutDestUnreachs = &value case "OutTimeExcds": procSnmp.Icmp.OutTimeExcds = &value case "OutParmProbs": procSnmp.Icmp.OutParmProbs = &value case "OutSrcQuenchs": procSnmp.Icmp.OutSrcQuenchs = &value case "OutRedirects": procSnmp.Icmp.OutRedirects = &value case "OutEchos": procSnmp.Icmp.OutEchos = &value case "OutEchoReps": procSnmp.Icmp.OutEchoReps = &value case "OutTimestamps": procSnmp.Icmp.OutTimestamps = &value case "OutTimestampReps": procSnmp.Icmp.OutTimestampReps = &value case "OutAddrMasks": procSnmp.Icmp.OutAddrMasks = &value case "OutAddrMaskReps": procSnmp.Icmp.OutAddrMaskReps = &value } case "IcmpMsg": switch key { case "InType3": procSnmp.IcmpMsg.InType3 = &value case "OutType3": procSnmp.IcmpMsg.OutType3 = &value } case "Tcp": switch key { case "RtoAlgorithm": procSnmp.Tcp.RtoAlgorithm = &value case "RtoMin": procSnmp.Tcp.RtoMin = &value case "RtoMax": procSnmp.Tcp.RtoMax = &value case "MaxConn": procSnmp.Tcp.MaxConn = &value case "ActiveOpens": procSnmp.Tcp.ActiveOpens = &value case "PassiveOpens": procSnmp.Tcp.PassiveOpens = &value case "AttemptFails": procSnmp.Tcp.AttemptFails = &value case "EstabResets": procSnmp.Tcp.EstabResets = &value case "CurrEstab": procSnmp.Tcp.CurrEstab = &value case "InSegs": procSnmp.Tcp.InSegs = &value case "OutSegs": procSnmp.Tcp.OutSegs = &value case "RetransSegs": procSnmp.Tcp.RetransSegs = &value case "InErrs": procSnmp.Tcp.InErrs = &value case "OutRsts": procSnmp.Tcp.OutRsts = &value case "InCsumErrors": procSnmp.Tcp.InCsumErrors = &value } case "Udp": switch key { case "InDatagrams": procSnmp.Udp.InDatagrams = &value case "NoPorts": procSnmp.Udp.NoPorts = &value case "InErrors": procSnmp.Udp.InErrors = &value case "OutDatagrams": procSnmp.Udp.OutDatagrams = &value case "RcvbufErrors": procSnmp.Udp.RcvbufErrors = &value case "SndbufErrors": procSnmp.Udp.SndbufErrors = &value case "InCsumErrors": procSnmp.Udp.InCsumErrors = &value case "IgnoredMulti": procSnmp.Udp.IgnoredMulti = &value } case "UdpLite": switch key { case "InDatagrams": procSnmp.UdpLite.InDatagrams = &value case "NoPorts": procSnmp.UdpLite.NoPorts = &value case "InErrors": procSnmp.UdpLite.InErrors = &value case "OutDatagrams": procSnmp.UdpLite.OutDatagrams = &value case "RcvbufErrors": procSnmp.UdpLite.RcvbufErrors = &value case "SndbufErrors": procSnmp.UdpLite.SndbufErrors = &value case "InCsumErrors": procSnmp.UdpLite.InCsumErrors = &value case "IgnoredMulti": procSnmp.UdpLite.IgnoredMulti = &value } } } } return procSnmp, scanner.Err() }