blob: 9964a3600b4ba9315a48507e14035ca1c886f29c [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// Copyright 2020 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 "fmt"
20 "io"
21 "strconv"
22 "strings"
23
24 "github.com/prometheus/procfs/internal/util"
25)
26
27// A ConntrackStatEntry represents one line from net/stat/nf_conntrack
28// and contains netfilter conntrack statistics at one CPU core
29type ConntrackStatEntry struct {
30 Entries uint64
31 Found uint64
32 Invalid uint64
33 Ignore uint64
34 Insert uint64
35 InsertFailed uint64
36 Drop uint64
37 EarlyDrop uint64
38 SearchRestart uint64
39}
40
41// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores
42func (fs FS) ConntrackStat() ([]ConntrackStatEntry, error) {
43 return readConntrackStat(fs.proc.Path("net", "stat", "nf_conntrack"))
44}
45
46// Parses a slice of ConntrackStatEntries from the given filepath
47func readConntrackStat(path string) ([]ConntrackStatEntry, error) {
48 // This file is small and can be read with one syscall.
49 b, err := util.ReadFileNoStat(path)
50 if err != nil {
51 // Do not wrap this error so the caller can detect os.IsNotExist and
52 // similar conditions.
53 return nil, err
54 }
55
56 stat, err := parseConntrackStat(bytes.NewReader(b))
57 if err != nil {
58 return nil, fmt.Errorf("failed to read conntrack stats from %q: %w", path, err)
59 }
60
61 return stat, nil
62}
63
64// Reads the contents of a conntrack statistics file and parses a slice of ConntrackStatEntries
65func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) {
66 var entries []ConntrackStatEntry
67
68 scanner := bufio.NewScanner(r)
69 scanner.Scan()
70 for scanner.Scan() {
71 fields := strings.Fields(scanner.Text())
72 conntrackEntry, err := parseConntrackStatEntry(fields)
73 if err != nil {
74 return nil, err
75 }
76 entries = append(entries, *conntrackEntry)
77 }
78
79 return entries, nil
80}
81
82// Parses a ConntrackStatEntry from given array of fields
83func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
84 if len(fields) != 17 {
85 return nil, fmt.Errorf("invalid conntrackstat entry, missing fields")
86 }
87 entry := &ConntrackStatEntry{}
88
89 entries, err := parseConntrackStatField(fields[0])
90 if err != nil {
91 return nil, err
92 }
93 entry.Entries = entries
94
95 found, err := parseConntrackStatField(fields[2])
96 if err != nil {
97 return nil, err
98 }
99 entry.Found = found
100
101 invalid, err := parseConntrackStatField(fields[4])
102 if err != nil {
103 return nil, err
104 }
105 entry.Invalid = invalid
106
107 ignore, err := parseConntrackStatField(fields[5])
108 if err != nil {
109 return nil, err
110 }
111 entry.Ignore = ignore
112
113 insert, err := parseConntrackStatField(fields[8])
114 if err != nil {
115 return nil, err
116 }
117 entry.Insert = insert
118
119 insertFailed, err := parseConntrackStatField(fields[9])
120 if err != nil {
121 return nil, err
122 }
123 entry.InsertFailed = insertFailed
124
125 drop, err := parseConntrackStatField(fields[10])
126 if err != nil {
127 return nil, err
128 }
129 entry.Drop = drop
130
131 earlyDrop, err := parseConntrackStatField(fields[11])
132 if err != nil {
133 return nil, err
134 }
135 entry.EarlyDrop = earlyDrop
136
137 searchRestart, err := parseConntrackStatField(fields[16])
138 if err != nil {
139 return nil, err
140 }
141 entry.SearchRestart = searchRestart
142
143 return entry, nil
144}
145
146// Parses a uint64 from given hex in string
147func parseConntrackStatField(field string) (uint64, error) {
148 val, err := strconv.ParseUint(field, 16, 64)
149 if err != nil {
150 return 0, fmt.Errorf("couldn't parse %q field: %w", field, err)
151 }
152 return val, err
153}