net_conntrackstat.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. 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. // A ConntrackStatEntry represents one line from net/stat/nf_conntrack
  24. // and contains netfilter conntrack statistics at one CPU core.
  25. type ConntrackStatEntry struct {
  26. Entries uint64
  27. Found uint64
  28. Invalid uint64
  29. Ignore uint64
  30. Insert uint64
  31. InsertFailed uint64
  32. Drop uint64
  33. EarlyDrop uint64
  34. SearchRestart uint64
  35. }
  36. // ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores.
  37. func (fs FS) ConntrackStat() ([]ConntrackStatEntry, error) {
  38. return readConntrackStat(fs.proc.Path("net", "stat", "nf_conntrack"))
  39. }
  40. // Parses a slice of ConntrackStatEntries from the given filepath.
  41. func readConntrackStat(path string) ([]ConntrackStatEntry, error) {
  42. // This file is small and can be read with one syscall.
  43. b, err := util.ReadFileNoStat(path)
  44. if err != nil {
  45. // Do not wrap this error so the caller can detect os.IsNotExist and
  46. // similar conditions.
  47. return nil, err
  48. }
  49. stat, err := parseConntrackStat(bytes.NewReader(b))
  50. if err != nil {
  51. return nil, fmt.Errorf("failed to read conntrack stats from %q: %w", path, err)
  52. }
  53. return stat, nil
  54. }
  55. // Reads the contents of a conntrack statistics file and parses a slice of ConntrackStatEntries.
  56. func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) {
  57. var entries []ConntrackStatEntry
  58. scanner := bufio.NewScanner(r)
  59. scanner.Scan()
  60. for scanner.Scan() {
  61. fields := strings.Fields(scanner.Text())
  62. conntrackEntry, err := parseConntrackStatEntry(fields)
  63. if err != nil {
  64. return nil, err
  65. }
  66. entries = append(entries, *conntrackEntry)
  67. }
  68. return entries, nil
  69. }
  70. // Parses a ConntrackStatEntry from given array of fields.
  71. func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
  72. if len(fields) != 17 {
  73. return nil, fmt.Errorf("invalid conntrackstat entry, missing fields")
  74. }
  75. entry := &ConntrackStatEntry{}
  76. entries, err := parseConntrackStatField(fields[0])
  77. if err != nil {
  78. return nil, err
  79. }
  80. entry.Entries = entries
  81. found, err := parseConntrackStatField(fields[2])
  82. if err != nil {
  83. return nil, err
  84. }
  85. entry.Found = found
  86. invalid, err := parseConntrackStatField(fields[4])
  87. if err != nil {
  88. return nil, err
  89. }
  90. entry.Invalid = invalid
  91. ignore, err := parseConntrackStatField(fields[5])
  92. if err != nil {
  93. return nil, err
  94. }
  95. entry.Ignore = ignore
  96. insert, err := parseConntrackStatField(fields[8])
  97. if err != nil {
  98. return nil, err
  99. }
  100. entry.Insert = insert
  101. insertFailed, err := parseConntrackStatField(fields[9])
  102. if err != nil {
  103. return nil, err
  104. }
  105. entry.InsertFailed = insertFailed
  106. drop, err := parseConntrackStatField(fields[10])
  107. if err != nil {
  108. return nil, err
  109. }
  110. entry.Drop = drop
  111. earlyDrop, err := parseConntrackStatField(fields[11])
  112. if err != nil {
  113. return nil, err
  114. }
  115. entry.EarlyDrop = earlyDrop
  116. searchRestart, err := parseConntrackStatField(fields[16])
  117. if err != nil {
  118. return nil, err
  119. }
  120. entry.SearchRestart = searchRestart
  121. return entry, nil
  122. }
  123. // Parses a uint64 from given hex in string.
  124. func parseConntrackStatField(field string) (uint64, error) {
  125. val, err := strconv.ParseUint(field, 16, 64)
  126. if err != nil {
  127. return 0, fmt.Errorf("couldn't parse %q field: %w", field, err)
  128. }
  129. return val, err
  130. }