Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.4 KiB
180 lines
5.4 KiB
// Copyright 2020 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" |
|
"strconv" |
|
"strings" |
|
|
|
"github.com/prometheus/procfs/internal/util" |
|
) |
|
|
|
// NetProtocolStats stores the contents from /proc/net/protocols |
|
type NetProtocolStats map[string]NetProtocolStatLine |
|
|
|
// NetProtocolStatLine contains a single line parsed from /proc/net/protocols. We |
|
// only care about the first six columns as the rest are not likely to change |
|
// and only serve to provide a set of capabilities for each protocol. |
|
type NetProtocolStatLine struct { |
|
Name string // 0 The name of the protocol |
|
Size uint64 // 1 The size, in bytes, of a given protocol structure. e.g. sizeof(struct tcp_sock) or sizeof(struct unix_sock) |
|
Sockets int64 // 2 Number of sockets in use by this protocol |
|
Memory int64 // 3 Number of 4KB pages allocated by all sockets of this protocol |
|
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. |
|
MaxHeader uint64 // 5 Protocol specific max header size |
|
Slab bool // 6 Indicates whether or not memory is allocated from the SLAB |
|
ModuleName string // 7 The name of the module that implemented this protocol or "kernel" if not from a module |
|
Capabilities NetProtocolCapabilities |
|
} |
|
|
|
// NetProtocolCapabilities contains a list of capabilities for each protocol |
|
type NetProtocolCapabilities struct { |
|
Close bool // 8 |
|
Connect bool // 9 |
|
Disconnect bool // 10 |
|
Accept bool // 11 |
|
IoCtl bool // 12 |
|
Init bool // 13 |
|
Destroy bool // 14 |
|
Shutdown bool // 15 |
|
SetSockOpt bool // 16 |
|
GetSockOpt bool // 17 |
|
SendMsg bool // 18 |
|
RecvMsg bool // 19 |
|
SendPage bool // 20 |
|
Bind bool // 21 |
|
BacklogRcv bool // 22 |
|
Hash bool // 23 |
|
UnHash bool // 24 |
|
GetPort bool // 25 |
|
EnterMemoryPressure bool // 26 |
|
} |
|
|
|
// NetProtocols reads stats from /proc/net/protocols and returns a map of |
|
// PortocolStatLine entries. As of this writing no official Linux Documentation |
|
// exists, however the source is fairly self-explanatory and the format seems |
|
// stable since its introduction in 2.6.12-rc2 |
|
// Linux 2.6.12-rc2 - https://elixir.bootlin.com/linux/v2.6.12-rc2/source/net/core/sock.c#L1452 |
|
// Linux 5.10 - https://elixir.bootlin.com/linux/v5.10.4/source/net/core/sock.c#L3586 |
|
func (fs FS) NetProtocols() (NetProtocolStats, error) { |
|
data, err := util.ReadFileNoStat(fs.proc.Path("net/protocols")) |
|
if err != nil { |
|
return NetProtocolStats{}, err |
|
} |
|
return parseNetProtocols(bufio.NewScanner(bytes.NewReader(data))) |
|
} |
|
|
|
func parseNetProtocols(s *bufio.Scanner) (NetProtocolStats, error) { |
|
nps := NetProtocolStats{} |
|
|
|
// Skip the header line |
|
s.Scan() |
|
|
|
for s.Scan() { |
|
line, err := nps.parseLine(s.Text()) |
|
if err != nil { |
|
return NetProtocolStats{}, err |
|
} |
|
|
|
nps[line.Name] = *line |
|
} |
|
return nps, nil |
|
} |
|
|
|
func (ps NetProtocolStats) parseLine(rawLine string) (*NetProtocolStatLine, error) { |
|
line := &NetProtocolStatLine{Capabilities: NetProtocolCapabilities{}} |
|
var err error |
|
const enabled = "yes" |
|
const disabled = "no" |
|
|
|
fields := strings.Fields(rawLine) |
|
line.Name = fields[0] |
|
line.Size, err = strconv.ParseUint(fields[1], 10, 64) |
|
if err != nil { |
|
return nil, err |
|
} |
|
line.Sockets, err = strconv.ParseInt(fields[2], 10, 64) |
|
if err != nil { |
|
return nil, err |
|
} |
|
line.Memory, err = strconv.ParseInt(fields[3], 10, 64) |
|
if err != nil { |
|
return nil, err |
|
} |
|
if fields[4] == enabled { |
|
line.Pressure = 1 |
|
} else if fields[4] == disabled { |
|
line.Pressure = 0 |
|
} else { |
|
line.Pressure = -1 |
|
} |
|
line.MaxHeader, err = strconv.ParseUint(fields[5], 10, 64) |
|
if err != nil { |
|
return nil, err |
|
} |
|
if fields[6] == enabled { |
|
line.Slab = true |
|
} else if fields[6] == disabled { |
|
line.Slab = false |
|
} else { |
|
return nil, fmt.Errorf("unable to parse capability for protocol: %s", line.Name) |
|
} |
|
line.ModuleName = fields[7] |
|
|
|
err = line.Capabilities.parseCapabilities(fields[8:]) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return line, nil |
|
} |
|
|
|
func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) error { |
|
// The capabilities are all bools so we can loop over to map them |
|
capabilityFields := [...]*bool{ |
|
&pc.Close, |
|
&pc.Connect, |
|
&pc.Disconnect, |
|
&pc.Accept, |
|
&pc.IoCtl, |
|
&pc.Init, |
|
&pc.Destroy, |
|
&pc.Shutdown, |
|
&pc.SetSockOpt, |
|
&pc.GetSockOpt, |
|
&pc.SendMsg, |
|
&pc.RecvMsg, |
|
&pc.SendPage, |
|
&pc.Bind, |
|
&pc.BacklogRcv, |
|
&pc.Hash, |
|
&pc.UnHash, |
|
&pc.GetPort, |
|
&pc.EnterMemoryPressure, |
|
} |
|
|
|
for i := 0; i < len(capabilities); i++ { |
|
if capabilities[i] == "y" { |
|
*capabilityFields[i] = true |
|
} else if capabilities[i] == "n" { |
|
*capabilityFields[i] = false |
|
} else { |
|
return fmt.Errorf("unable to parse capability block for protocol: position %d", i) |
|
} |
|
} |
|
return nil |
|
}
|
|
|