| // Copyright 2019 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" |
| "io" |
| "strconv" |
| "strings" |
| |
| "github.com/prometheus/procfs/internal/util" |
| ) |
| |
| // For the proc file format details, |
| // See: |
| // * Linux 2.6.23 https://elixir.bootlin.com/linux/v2.6.23/source/net/core/dev.c#L2343 |
| // * Linux 4.17 https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162 |
| // and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810. |
| |
| // SoftnetStat contains a single row of data from /proc/net/softnet_stat |
| type SoftnetStat struct { |
| // Number of processed packets |
| Processed uint32 |
| // Number of dropped packets |
| Dropped uint32 |
| // Number of times processing packets ran out of quota |
| TimeSqueezed uint32 |
| } |
| |
| var softNetProcFile = "net/softnet_stat" |
| |
| // NetSoftnetStat reads data from /proc/net/softnet_stat. |
| func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) { |
| b, err := util.ReadFileNoStat(fs.proc.Path(softNetProcFile)) |
| if err != nil { |
| return nil, err |
| } |
| |
| entries, err := parseSoftnet(bytes.NewReader(b)) |
| if err != nil { |
| return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %w", err) |
| } |
| |
| return entries, nil |
| } |
| |
| func parseSoftnet(r io.Reader) ([]SoftnetStat, error) { |
| const minColumns = 9 |
| |
| s := bufio.NewScanner(r) |
| |
| var stats []SoftnetStat |
| for s.Scan() { |
| columns := strings.Fields(s.Text()) |
| width := len(columns) |
| |
| if width < minColumns { |
| return nil, fmt.Errorf("%d columns were detected, but at least %d were expected", width, minColumns) |
| } |
| |
| // We only parse the first three columns at the moment. |
| us, err := parseHexUint32s(columns[0:3]) |
| if err != nil { |
| return nil, err |
| } |
| |
| stats = append(stats, SoftnetStat{ |
| Processed: us[0], |
| Dropped: us[1], |
| TimeSqueezed: us[2], |
| }) |
| } |
| |
| return stats, nil |
| } |
| |
| func parseHexUint32s(ss []string) ([]uint32, error) { |
| us := make([]uint32, 0, len(ss)) |
| for _, s := range ss { |
| u, err := strconv.ParseUint(s, 16, 32) |
| if err != nil { |
| return nil, err |
| } |
| |
| us = append(us, uint32(u)) |
| } |
| |
| return us, nil |
| } |