blob: 316df5fbb74e69c713ef88d42df7395f017561ae [file] [log] [blame]
Abhay Kumara61c5222025-11-10 07:32:50 +00001// 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 "strings"
22
23 "github.com/prometheus/procfs/internal/util"
24)
25
26// A ConntrackStatEntry represents one line from net/stat/nf_conntrack
27// and contains netfilter conntrack statistics at one CPU core.
28type ConntrackStatEntry struct {
29 Entries uint64
30 Searched uint64
31 Found uint64
32 New uint64
33 Invalid uint64
34 Ignore uint64
35 Delete uint64
36 DeleteList uint64
37 Insert uint64
38 InsertFailed uint64
39 Drop uint64
40 EarlyDrop uint64
41 SearchRestart uint64
42}
43
44// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores.
45func (fs FS) ConntrackStat() ([]ConntrackStatEntry, error) {
46 return readConntrackStat(fs.proc.Path("net", "stat", "nf_conntrack"))
47}
48
49// Parses a slice of ConntrackStatEntries from the given filepath.
50func readConntrackStat(path string) ([]ConntrackStatEntry, error) {
51 // This file is small and can be read with one syscall.
52 b, err := util.ReadFileNoStat(path)
53 if err != nil {
54 // Do not wrap this error so the caller can detect os.IsNotExist and
55 // similar conditions.
56 return nil, err
57 }
58
59 stat, err := parseConntrackStat(bytes.NewReader(b))
60 if err != nil {
61 return nil, fmt.Errorf("%w: Cannot read file: %v: %w", ErrFileRead, path, err)
62 }
63
64 return stat, nil
65}
66
67// Reads the contents of a conntrack statistics file and parses a slice of ConntrackStatEntries.
68func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) {
69 var entries []ConntrackStatEntry
70
71 scanner := bufio.NewScanner(r)
72 scanner.Scan()
73 for scanner.Scan() {
74 fields := strings.Fields(scanner.Text())
75 conntrackEntry, err := parseConntrackStatEntry(fields)
76 if err != nil {
77 return nil, err
78 }
79 entries = append(entries, *conntrackEntry)
80 }
81
82 return entries, nil
83}
84
85// Parses a ConntrackStatEntry from given array of fields.
86func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
87 entries, err := util.ParseHexUint64s(fields)
88 if err != nil {
89 return nil, fmt.Errorf("%w: Cannot parse entry: %d: %w", ErrFileParse, entries, err)
90 }
91 numEntries := len(entries)
92 if numEntries < 16 || numEntries > 17 {
93 return nil,
94 fmt.Errorf("%w: invalid conntrackstat entry, invalid number of fields: %d", ErrFileParse, numEntries)
95 }
96
97 stats := &ConntrackStatEntry{
98 Entries: *entries[0],
99 Searched: *entries[1],
100 Found: *entries[2],
101 New: *entries[3],
102 Invalid: *entries[4],
103 Ignore: *entries[5],
104 Delete: *entries[6],
105 DeleteList: *entries[7],
106 Insert: *entries[8],
107 InsertFailed: *entries[9],
108 Drop: *entries[10],
109 EarlyDrop: *entries[11],
110 }
111
112 // Ignore missing search_restart on Linux < 2.6.35.
113 if numEntries == 17 {
114 stats.SearchRestart = *entries[16]
115 }
116
117 return stats, nil
118}