...

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

Documentation: github.com/prometheus/procfs

     1  // Copyright 2019 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  	"io"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/prometheus/procfs/internal/util"
    25  )
    26  
    27  // For the proc file format details,
    28  // See:
    29  // * Linux 2.6.23 https://elixir.bootlin.com/linux/v2.6.23/source/net/core/dev.c#L2343
    30  // * Linux 2.6.39 https://elixir.bootlin.com/linux/v2.6.39/source/net/core/dev.c#L4086
    31  // * Linux 4.18 https://elixir.bootlin.com/linux/v4.18/source/net/core/net-procfs.c#L162
    32  // * Linux 5.14 https://elixir.bootlin.com/linux/v5.14/source/net/core/net-procfs.c#L169
    33  
    34  // SoftnetStat contains a single row of data from /proc/net/softnet_stat.
    35  type SoftnetStat struct {
    36  	// Number of processed packets.
    37  	Processed uint32
    38  	// Number of dropped packets.
    39  	Dropped uint32
    40  	// Number of times processing packets ran out of quota.
    41  	TimeSqueezed uint32
    42  	// Number of collision occur while obtaining device lock while transmitting.
    43  	CPUCollision uint32
    44  	// Number of times cpu woken up received_rps.
    45  	ReceivedRps uint32
    46  	// number of times flow limit has been reached.
    47  	FlowLimitCount uint32
    48  	// Softnet backlog status.
    49  	SoftnetBacklogLen uint32
    50  	// CPU id owning this softnet_data.
    51  	Index uint32
    52  	// softnet_data's Width.
    53  	Width int
    54  }
    55  
    56  var softNetProcFile = "net/softnet_stat"
    57  
    58  // NetSoftnetStat reads data from /proc/net/softnet_stat.
    59  func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
    60  	b, err := util.ReadFileNoStat(fs.proc.Path(softNetProcFile))
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	entries, err := parseSoftnet(bytes.NewReader(b))
    66  	if err != nil {
    67  		return nil, fmt.Errorf("%s: /proc/net/softnet_stat: %w", ErrFileParse, err)
    68  	}
    69  
    70  	return entries, nil
    71  }
    72  
    73  func parseSoftnet(r io.Reader) ([]SoftnetStat, error) {
    74  	const minColumns = 9
    75  
    76  	s := bufio.NewScanner(r)
    77  
    78  	var stats []SoftnetStat
    79  	cpuIndex := 0
    80  	for s.Scan() {
    81  		columns := strings.Fields(s.Text())
    82  		width := len(columns)
    83  		softnetStat := SoftnetStat{}
    84  
    85  		if width < minColumns {
    86  			return nil, fmt.Errorf("%w: detected %d columns, but expected at least %d", ErrFileParse, width, minColumns)
    87  		}
    88  
    89  		// Linux 2.6.23 https://elixir.bootlin.com/linux/v2.6.23/source/net/core/dev.c#L2347
    90  		if width >= minColumns {
    91  			us, err := parseHexUint32s(columns[0:9])
    92  			if err != nil {
    93  				return nil, err
    94  			}
    95  
    96  			softnetStat.Processed = us[0]
    97  			softnetStat.Dropped = us[1]
    98  			softnetStat.TimeSqueezed = us[2]
    99  			softnetStat.CPUCollision = us[8]
   100  		}
   101  
   102  		// Linux 2.6.39 https://elixir.bootlin.com/linux/v2.6.39/source/net/core/dev.c#L4086
   103  		if width >= 10 {
   104  			us, err := parseHexUint32s(columns[9:10])
   105  			if err != nil {
   106  				return nil, err
   107  			}
   108  
   109  			softnetStat.ReceivedRps = us[0]
   110  		}
   111  
   112  		// Linux 4.18 https://elixir.bootlin.com/linux/v4.18/source/net/core/net-procfs.c#L162
   113  		if width >= 11 {
   114  			us, err := parseHexUint32s(columns[10:11])
   115  			if err != nil {
   116  				return nil, err
   117  			}
   118  
   119  			softnetStat.FlowLimitCount = us[0]
   120  		}
   121  
   122  		// Linux 5.14 https://elixir.bootlin.com/linux/v5.14/source/net/core/net-procfs.c#L169
   123  		if width >= 13 {
   124  			us, err := parseHexUint32s(columns[11:13])
   125  			if err != nil {
   126  				return nil, err
   127  			}
   128  
   129  			softnetStat.SoftnetBacklogLen = us[0]
   130  			softnetStat.Index = us[1]
   131  		} else {
   132  			// For older kernels, create the Index based on the scan line number.
   133  			softnetStat.Index = uint32(cpuIndex)
   134  		}
   135  		softnetStat.Width = width
   136  		stats = append(stats, softnetStat)
   137  		cpuIndex++
   138  	}
   139  
   140  	return stats, nil
   141  }
   142  
   143  func parseHexUint32s(ss []string) ([]uint32, error) {
   144  	us := make([]uint32, 0, len(ss))
   145  	for _, s := range ss {
   146  		u, err := strconv.ParseUint(s, 16, 32)
   147  		if err != nil {
   148  			return nil, err
   149  		}
   150  
   151  		us = append(us, uint32(u))
   152  	}
   153  
   154  	return us, nil
   155  }
   156  

View as plain text