| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package fscommon
- import (
- "bufio"
- "errors"
- "math"
- "os"
- "strconv"
- "strings"
- "github.com/opencontainers/runc/libcontainer/cgroups"
- "github.com/opencontainers/runc/libcontainer/configs"
- "golang.org/x/sys/unix"
- )
- // parseRdmaKV parses raw string to RdmaEntry.
- func parseRdmaKV(raw string, entry *cgroups.RdmaEntry) error {
- var value uint32
- parts := strings.SplitN(raw, "=", 3)
- if len(parts) != 2 {
- return errors.New("Unable to parse RDMA entry")
- }
- k, v := parts[0], parts[1]
- if v == "max" {
- value = math.MaxUint32
- } else {
- val64, err := strconv.ParseUint(v, 10, 32)
- if err != nil {
- return err
- }
- value = uint32(val64)
- }
- if k == "hca_handle" {
- entry.HcaHandles = value
- } else if k == "hca_object" {
- entry.HcaObjects = value
- }
- return nil
- }
- // readRdmaEntries reads and converts array of rawstrings to RdmaEntries from file.
- // example entry: mlx4_0 hca_handle=2 hca_object=2000
- func readRdmaEntries(dir, file string) ([]cgroups.RdmaEntry, error) {
- rdmaEntries := make([]cgroups.RdmaEntry, 0)
- fd, err := cgroups.OpenFile(dir, file, unix.O_RDONLY)
- if err != nil {
- return nil, err
- }
- defer fd.Close() //nolint:errorlint
- scanner := bufio.NewScanner(fd)
- for scanner.Scan() {
- parts := strings.SplitN(scanner.Text(), " ", 4)
- if len(parts) == 3 {
- entry := new(cgroups.RdmaEntry)
- entry.Device = parts[0]
- err = parseRdmaKV(parts[1], entry)
- if err != nil {
- continue
- }
- err = parseRdmaKV(parts[2], entry)
- if err != nil {
- continue
- }
- rdmaEntries = append(rdmaEntries, *entry)
- }
- }
- return rdmaEntries, scanner.Err()
- }
- // RdmaGetStats returns rdma stats such as totalLimit and current entries.
- func RdmaGetStats(path string, stats *cgroups.Stats) error {
- currentEntries, err := readRdmaEntries(path, "rdma.current")
- if err != nil {
- if errors.Is(err, os.ErrNotExist) {
- err = nil
- }
- return err
- }
- maxEntries, err := readRdmaEntries(path, "rdma.max")
- if err != nil {
- return err
- }
- // If device got removed between reading two files, ignore returning stats.
- if len(currentEntries) != len(maxEntries) {
- return nil
- }
- stats.RdmaStats = cgroups.RdmaStats{
- RdmaLimit: maxEntries,
- RdmaCurrent: currentEntries,
- }
- return nil
- }
- func createCmdString(device string, limits configs.LinuxRdma) string {
- cmdString := device
- if limits.HcaHandles != nil {
- cmdString += " hca_handle=" + strconv.FormatUint(uint64(*limits.HcaHandles), 10)
- }
- if limits.HcaObjects != nil {
- cmdString += " hca_object=" + strconv.FormatUint(uint64(*limits.HcaObjects), 10)
- }
- return cmdString
- }
- // RdmaSet sets RDMA resources.
- func RdmaSet(path string, r *configs.Resources) error {
- for device, limits := range r.Rdma {
- if err := cgroups.WriteFile(path, "rdma.max", createCmdString(device, limits)); err != nil {
- return err
- }
- }
- return nil
- }
|