...

Source file src/github.com/containerd/cgroups/rdma.go

Documentation: github.com/containerd/cgroups

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package cgroups
    18  
    19  import (
    20  	"math"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"strings"
    25  
    26  	v1 "github.com/containerd/cgroups/stats/v1"
    27  	specs "github.com/opencontainers/runtime-spec/specs-go"
    28  )
    29  
    30  type rdmaController struct {
    31  	root string
    32  }
    33  
    34  func (p *rdmaController) Name() Name {
    35  	return Rdma
    36  }
    37  
    38  func (p *rdmaController) Path(path string) string {
    39  	return filepath.Join(p.root, path)
    40  }
    41  
    42  func NewRdma(root string) *rdmaController {
    43  	return &rdmaController{
    44  		root: filepath.Join(root, string(Rdma)),
    45  	}
    46  }
    47  
    48  func createCmdString(device string, limits *specs.LinuxRdma) string {
    49  	var cmdString string
    50  
    51  	cmdString = device
    52  	if limits.HcaHandles != nil {
    53  		cmdString = cmdString + " " + "hca_handle=" + strconv.FormatUint(uint64(*limits.HcaHandles), 10)
    54  	}
    55  
    56  	if limits.HcaObjects != nil {
    57  		cmdString = cmdString + " " + "hca_object=" + strconv.FormatUint(uint64(*limits.HcaObjects), 10)
    58  	}
    59  	return cmdString
    60  }
    61  
    62  func (p *rdmaController) Create(path string, resources *specs.LinuxResources) error {
    63  	if err := os.MkdirAll(p.Path(path), defaultDirPerm); err != nil {
    64  		return err
    65  	}
    66  
    67  	for device, limit := range resources.Rdma {
    68  		if device != "" && (limit.HcaHandles != nil || limit.HcaObjects != nil) {
    69  			limit := limit
    70  			return retryingWriteFile(
    71  				filepath.Join(p.Path(path), "rdma.max"),
    72  				[]byte(createCmdString(device, &limit)),
    73  				defaultFilePerm,
    74  			)
    75  		}
    76  	}
    77  	return nil
    78  }
    79  
    80  func (p *rdmaController) Update(path string, resources *specs.LinuxResources) error {
    81  	return p.Create(path, resources)
    82  }
    83  
    84  func parseRdmaKV(raw string, entry *v1.RdmaEntry) {
    85  	var value uint64
    86  	var err error
    87  
    88  	parts := strings.Split(raw, "=")
    89  	switch len(parts) {
    90  	case 2:
    91  		if parts[1] == "max" {
    92  			value = math.MaxUint32
    93  		} else {
    94  			value, err = parseUint(parts[1], 10, 32)
    95  			if err != nil {
    96  				return
    97  			}
    98  		}
    99  		if parts[0] == "hca_handle" {
   100  			entry.HcaHandles = uint32(value)
   101  		} else if parts[0] == "hca_object" {
   102  			entry.HcaObjects = uint32(value)
   103  		}
   104  	}
   105  }
   106  
   107  func toRdmaEntry(strEntries []string) []*v1.RdmaEntry {
   108  	var rdmaEntries []*v1.RdmaEntry
   109  	for i := range strEntries {
   110  		parts := strings.Fields(strEntries[i])
   111  		switch len(parts) {
   112  		case 3:
   113  			entry := new(v1.RdmaEntry)
   114  			entry.Device = parts[0]
   115  			parseRdmaKV(parts[1], entry)
   116  			parseRdmaKV(parts[2], entry)
   117  
   118  			rdmaEntries = append(rdmaEntries, entry)
   119  		default:
   120  			continue
   121  		}
   122  	}
   123  	return rdmaEntries
   124  }
   125  
   126  func (p *rdmaController) Stat(path string, stats *v1.Metrics) error {
   127  
   128  	currentData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.current"))
   129  	if err != nil {
   130  		return err
   131  	}
   132  	currentPerDevices := strings.Split(string(currentData), "\n")
   133  
   134  	maxData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.max"))
   135  	if err != nil {
   136  		return err
   137  	}
   138  	maxPerDevices := strings.Split(string(maxData), "\n")
   139  
   140  	// If device got removed between reading two files, ignore returning
   141  	// stats.
   142  	if len(currentPerDevices) != len(maxPerDevices) {
   143  		return nil
   144  	}
   145  
   146  	currentEntries := toRdmaEntry(currentPerDevices)
   147  	maxEntries := toRdmaEntry(maxPerDevices)
   148  
   149  	stats.Rdma = &v1.RdmaStat{
   150  		Current: currentEntries,
   151  		Limit:   maxEntries,
   152  	}
   153  	return nil
   154  }
   155  

View as plain text