...

Source file src/github.com/prometheus/procfs/net_protocols.go

Documentation: github.com/prometheus/procfs

     1  // 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  
    14  package procfs
    15  
    16  import (
    17  	"bufio"
    18  	"bytes"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"github.com/prometheus/procfs/internal/util"
    24  )
    25  
    26  // NetProtocolStats stores the contents from /proc/net/protocols.
    27  type 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.
    32  type 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  
    44  // NetProtocolCapabilities contains a list of capabilities for each protocol.
    45  type 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
    73  func (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  
    81  func 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  
    98  func (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  	}
   118  	if fields[4] == enabled {
   119  		line.Pressure = 1
   120  	} else if fields[4] == disabled {
   121  		line.Pressure = 0
   122  	} else {
   123  		line.Pressure = -1
   124  	}
   125  	line.MaxHeader, err = strconv.ParseUint(fields[5], 10, 64)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	if fields[6] == enabled {
   130  		line.Slab = true
   131  	} else if fields[6] == disabled {
   132  		line.Slab = false
   133  	} else {
   134  		return nil, fmt.Errorf("%w: capability for protocol: %s", ErrFileParse, line.Name)
   135  	}
   136  	line.ModuleName = fields[7]
   137  
   138  	err = line.Capabilities.parseCapabilities(fields[8:])
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return line, nil
   144  }
   145  
   146  func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) error {
   147  	// The capabilities are all bools so we can loop over to map them
   148  	capabilityFields := [...]*bool{
   149  		&pc.Close,
   150  		&pc.Connect,
   151  		&pc.Disconnect,
   152  		&pc.Accept,
   153  		&pc.IoCtl,
   154  		&pc.Init,
   155  		&pc.Destroy,
   156  		&pc.Shutdown,
   157  		&pc.SetSockOpt,
   158  		&pc.GetSockOpt,
   159  		&pc.SendMsg,
   160  		&pc.RecvMsg,
   161  		&pc.SendPage,
   162  		&pc.Bind,
   163  		&pc.BacklogRcv,
   164  		&pc.Hash,
   165  		&pc.UnHash,
   166  		&pc.GetPort,
   167  		&pc.EnterMemoryPressure,
   168  	}
   169  
   170  	for i := 0; i < len(capabilities); i++ {
   171  		if capabilities[i] == "y" {
   172  			*capabilityFields[i] = true
   173  		} else if capabilities[i] == "n" {
   174  			*capabilityFields[i] = false
   175  		} else {
   176  			return fmt.Errorf("%w: capability block for protocol: position %d", ErrFileParse, i)
   177  		}
   178  	}
   179  	return nil
   180  }
   181  

View as plain text