...

Source file src/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/rdma.go

Documentation: github.com/opencontainers/runc/libcontainer/cgroups/fscommon

     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  // parseRdmaKV parses raw string to RdmaEntry.
    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  // readRdmaEntries reads and converts array of rawstrings to RdmaEntries from file.
    47  // example entry: mlx4_0 hca_handle=2 hca_object=2000
    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() //nolint:errorlint
    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  // RdmaGetStats returns rdma stats such as totalLimit and current entries.
    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  	// If device got removed between reading two files, ignore returning stats.
    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  // RdmaSet sets RDMA resources.
   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