blob: 8d4b1ac05b006fa9f24fa91c00d0d7351da8d711 [file] [log] [blame]
khenaidoo26721882021-08-11 17:42:52 -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 "strconv"
21 "strings"
22
23 "github.com/prometheus/procfs/internal/util"
24)
25
Abhay Kumar40252eb2025-10-13 13:25:53 +000026// NetProtocolStats stores the contents from /proc/net/protocols.
khenaidoo26721882021-08-11 17:42:52 -040027type NetProtocolStats map[string]NetProtocolStatLine
28
29// NetProtocolStatLine contains a single line parsed from /proc/net/protocols. We
30// only care about the first six columns as the rest are not likely to change
31// and only serve to provide a set of capabilities for each protocol.
32type NetProtocolStatLine struct {
33 Name string // 0 The name of the protocol
34 Size uint64 // 1 The size, in bytes, of a given protocol structure. e.g. sizeof(struct tcp_sock) or sizeof(struct unix_sock)
35 Sockets int64 // 2 Number of sockets in use by this protocol
36 Memory int64 // 3 Number of 4KB pages allocated by all sockets of this protocol
37 Pressure int // 4 This is either yes, no, or NI (not implemented). For the sake of simplicity we treat NI as not experiencing memory pressure.
38 MaxHeader uint64 // 5 Protocol specific max header size
39 Slab bool // 6 Indicates whether or not memory is allocated from the SLAB
40 ModuleName string // 7 The name of the module that implemented this protocol or "kernel" if not from a module
41 Capabilities NetProtocolCapabilities
42}
43
Abhay Kumar40252eb2025-10-13 13:25:53 +000044// NetProtocolCapabilities contains a list of capabilities for each protocol.
khenaidoo26721882021-08-11 17:42:52 -040045type NetProtocolCapabilities struct {
46 Close bool // 8
47 Connect bool // 9
48 Disconnect bool // 10
49 Accept bool // 11
50 IoCtl bool // 12
51 Init bool // 13
52 Destroy bool // 14
53 Shutdown bool // 15
54 SetSockOpt bool // 16
55 GetSockOpt bool // 17
56 SendMsg bool // 18
57 RecvMsg bool // 19
58 SendPage bool // 20
59 Bind bool // 21
60 BacklogRcv bool // 22
61 Hash bool // 23
62 UnHash bool // 24
63 GetPort bool // 25
64 EnterMemoryPressure bool // 26
65}
66
67// NetProtocols reads stats from /proc/net/protocols and returns a map of
68// PortocolStatLine entries. As of this writing no official Linux Documentation
69// exists, however the source is fairly self-explanatory and the format seems
70// stable since its introduction in 2.6.12-rc2
71// Linux 2.6.12-rc2 - https://elixir.bootlin.com/linux/v2.6.12-rc2/source/net/core/sock.c#L1452
72// Linux 5.10 - https://elixir.bootlin.com/linux/v5.10.4/source/net/core/sock.c#L3586
73func (fs FS) NetProtocols() (NetProtocolStats, error) {
74 data, err := util.ReadFileNoStat(fs.proc.Path("net/protocols"))
75 if err != nil {
76 return NetProtocolStats{}, err
77 }
78 return parseNetProtocols(bufio.NewScanner(bytes.NewReader(data)))
79}
80
81func parseNetProtocols(s *bufio.Scanner) (NetProtocolStats, error) {
82 nps := NetProtocolStats{}
83
84 // Skip the header line
85 s.Scan()
86
87 for s.Scan() {
88 line, err := nps.parseLine(s.Text())
89 if err != nil {
90 return NetProtocolStats{}, err
91 }
92
93 nps[line.Name] = *line
94 }
95 return nps, nil
96}
97
98func (ps NetProtocolStats) parseLine(rawLine string) (*NetProtocolStatLine, error) {
99 line := &NetProtocolStatLine{Capabilities: NetProtocolCapabilities{}}
100 var err error
101 const enabled = "yes"
102 const disabled = "no"
103
104 fields := strings.Fields(rawLine)
105 line.Name = fields[0]
106 line.Size, err = strconv.ParseUint(fields[1], 10, 64)
107 if err != nil {
108 return nil, err
109 }
110 line.Sockets, err = strconv.ParseInt(fields[2], 10, 64)
111 if err != nil {
112 return nil, err
113 }
114 line.Memory, err = strconv.ParseInt(fields[3], 10, 64)
115 if err != nil {
116 return nil, err
117 }
Abhay Kumar40252eb2025-10-13 13:25:53 +0000118 switch fields[4] {
119 case enabled:
khenaidoo26721882021-08-11 17:42:52 -0400120 line.Pressure = 1
Abhay Kumar40252eb2025-10-13 13:25:53 +0000121 case disabled:
khenaidoo26721882021-08-11 17:42:52 -0400122 line.Pressure = 0
Abhay Kumar40252eb2025-10-13 13:25:53 +0000123 default:
khenaidoo26721882021-08-11 17:42:52 -0400124 line.Pressure = -1
125 }
126 line.MaxHeader, err = strconv.ParseUint(fields[5], 10, 64)
127 if err != nil {
128 return nil, err
129 }
Abhay Kumar40252eb2025-10-13 13:25:53 +0000130 switch fields[6] {
131 case enabled:
khenaidoo26721882021-08-11 17:42:52 -0400132 line.Slab = true
Abhay Kumar40252eb2025-10-13 13:25:53 +0000133 case disabled:
khenaidoo26721882021-08-11 17:42:52 -0400134 line.Slab = false
Abhay Kumar40252eb2025-10-13 13:25:53 +0000135 default:
136 return nil, fmt.Errorf("%w: capability for protocol: %s", ErrFileParse, line.Name)
khenaidoo26721882021-08-11 17:42:52 -0400137 }
138 line.ModuleName = fields[7]
139
140 err = line.Capabilities.parseCapabilities(fields[8:])
141 if err != nil {
142 return nil, err
143 }
144
145 return line, nil
146}
147
148func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) error {
149 // The capabilities are all bools so we can loop over to map them
150 capabilityFields := [...]*bool{
151 &pc.Close,
152 &pc.Connect,
153 &pc.Disconnect,
154 &pc.Accept,
155 &pc.IoCtl,
156 &pc.Init,
157 &pc.Destroy,
158 &pc.Shutdown,
159 &pc.SetSockOpt,
160 &pc.GetSockOpt,
161 &pc.SendMsg,
162 &pc.RecvMsg,
163 &pc.SendPage,
164 &pc.Bind,
165 &pc.BacklogRcv,
166 &pc.Hash,
167 &pc.UnHash,
168 &pc.GetPort,
169 &pc.EnterMemoryPressure,
170 }
171
172 for i := 0; i < len(capabilities); i++ {
Abhay Kumar40252eb2025-10-13 13:25:53 +0000173 switch capabilities[i] {
174 case "y":
khenaidoo26721882021-08-11 17:42:52 -0400175 *capabilityFields[i] = true
Abhay Kumar40252eb2025-10-13 13:25:53 +0000176 case "n":
khenaidoo26721882021-08-11 17:42:52 -0400177 *capabilityFields[i] = false
Abhay Kumar40252eb2025-10-13 13:25:53 +0000178 default:
179 return fmt.Errorf("%w: capability block for protocol: position %d", ErrFileParse, i)
khenaidoo26721882021-08-11 17:42:52 -0400180 }
181 }
182 return nil
183}