...
1 package fscommon
2
3 import (
4 "bufio"
5 "errors"
6 "math"
7 "os"
8 "strconv"
9 "strings"
10
11 "github.com/opencontainers/runc/libcontainer/cgroups"
12 "github.com/opencontainers/runc/libcontainer/configs"
13 "golang.org/x/sys/unix"
14 )
15
16
17 func parseRdmaKV(raw string, entry *cgroups.RdmaEntry) error {
18 var value uint32
19
20 parts := strings.SplitN(raw, "=", 3)
21
22 if len(parts) != 2 {
23 return errors.New("Unable to parse RDMA entry")
24 }
25
26 k, v := parts[0], parts[1]
27
28 if v == "max" {
29 value = math.MaxUint32
30 } else {
31 val64, err := strconv.ParseUint(v, 10, 32)
32 if err != nil {
33 return err
34 }
35 value = uint32(val64)
36 }
37 if k == "hca_handle" {
38 entry.HcaHandles = value
39 } else if k == "hca_object" {
40 entry.HcaObjects = value
41 }
42
43 return nil
44 }
45
46
47
48 func readRdmaEntries(dir, file string) ([]cgroups.RdmaEntry, error) {
49 rdmaEntries := make([]cgroups.RdmaEntry, 0)
50 fd, err := cgroups.OpenFile(dir, file, unix.O_RDONLY)
51 if err != nil {
52 return nil, err
53 }
54 defer fd.Close()
55 scanner := bufio.NewScanner(fd)
56 for scanner.Scan() {
57 parts := strings.SplitN(scanner.Text(), " ", 4)
58 if len(parts) == 3 {
59 entry := new(cgroups.RdmaEntry)
60 entry.Device = parts[0]
61 err = parseRdmaKV(parts[1], entry)
62 if err != nil {
63 continue
64 }
65 err = parseRdmaKV(parts[2], entry)
66 if err != nil {
67 continue
68 }
69
70 rdmaEntries = append(rdmaEntries, *entry)
71 }
72 }
73 return rdmaEntries, scanner.Err()
74 }
75
76
77 func RdmaGetStats(path string, stats *cgroups.Stats) error {
78 currentEntries, err := readRdmaEntries(path, "rdma.current")
79 if err != nil {
80 if errors.Is(err, os.ErrNotExist) {
81 err = nil
82 }
83 return err
84 }
85 maxEntries, err := readRdmaEntries(path, "rdma.max")
86 if err != nil {
87 return err
88 }
89
90 if len(currentEntries) != len(maxEntries) {
91 return nil
92 }
93
94 stats.RdmaStats = cgroups.RdmaStats{
95 RdmaLimit: maxEntries,
96 RdmaCurrent: currentEntries,
97 }
98
99 return nil
100 }
101
102 func createCmdString(device string, limits configs.LinuxRdma) string {
103 cmdString := device
104 if limits.HcaHandles != nil {
105 cmdString += " hca_handle=" + strconv.FormatUint(uint64(*limits.HcaHandles), 10)
106 }
107 if limits.HcaObjects != nil {
108 cmdString += " hca_object=" + strconv.FormatUint(uint64(*limits.HcaObjects), 10)
109 }
110 return cmdString
111 }
112
113
114 func RdmaSet(path string, r *configs.Resources) error {
115 for device, limits := range r.Rdma {
116 if err := cgroups.WriteFile(path, "rdma.max", createCmdString(device, limits)); err != nil {
117 return err
118 }
119 }
120 return nil
121 }
122
View as plain text