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.

net_softnet.go 4.1KB

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