-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Add support for rdma cgroup introduced in Linux Kernel 4.11 #2883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package fs | ||
|
|
||
| import ( | ||
| "github.com/opencontainers/runc/libcontainer/cgroups" | ||
| "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" | ||
| "github.com/opencontainers/runc/libcontainer/configs" | ||
| ) | ||
|
|
||
| type RdmaGroup struct{} | ||
|
|
||
| func (s *RdmaGroup) Name() string { | ||
| return "rdma" | ||
| } | ||
|
|
||
| func (s *RdmaGroup) Apply(path string, d *cgroupData) error { | ||
| return join(path, d.pid) | ||
| } | ||
|
|
||
| func (s *RdmaGroup) Set(path string, r *configs.Resources) error { | ||
| return fscommon.RdmaSet(path, r) | ||
| } | ||
|
|
||
| func (s *RdmaGroup) GetStats(path string, stats *cgroups.Stats) error { | ||
| return fscommon.RdmaGetStats(path, stats) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| 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) | ||
flouthoc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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 | ||
flouthoc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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 | ||
kolyshkin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| err = parseRdmaKV(parts[2], entry) | ||
| if err != nil { | ||
| continue | ||
flouthoc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| 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 | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| package fscommon | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "github.com/opencontainers/runc/libcontainer/configs" | ||
| ) | ||
|
|
||
| /* Roadmap for future */ | ||
| // (Low-priority) TODO: Check if it is possible to virtually mimic an actual RDMA device. | ||
| // TODO: Think of more edge-cases to add. | ||
|
|
||
| // TestRdmaSet performs an E2E test of RdmaSet(), parseRdmaKV() using dummy device and a dummy cgroup file-system. | ||
| // Note: Following test does not guarantees that your host supports RDMA since this mocks underlying infrastructure. | ||
| func TestRdmaSet(t *testing.T) { | ||
| testCgroupPath := filepath.Join(t.TempDir(), "rdma") | ||
|
|
||
| // Ensure the full mock cgroup path exists. | ||
| err := os.Mkdir(testCgroupPath, 0o755) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| rdmaDevice := "mlx5_1" | ||
| maxHandles := uint32(100) | ||
| maxObjects := uint32(300) | ||
kolyshkin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| rdmaStubResource := &configs.Resources{ | ||
| Rdma: map[string]configs.LinuxRdma{ | ||
| rdmaDevice: { | ||
| HcaHandles: &maxHandles, | ||
| HcaObjects: &maxObjects, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| if err := RdmaSet(testCgroupPath, rdmaStubResource); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| // The default rdma.max must be written. | ||
| rdmaEntries, err := readRdmaEntries(testCgroupPath, "rdma.max") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if len(rdmaEntries) != 1 { | ||
| t.Fatal("rdma_test: Got the wrong values while parsing entries from rdma.max") | ||
| } | ||
| if rdmaEntries[0].HcaHandles != maxHandles { | ||
| t.Fatalf("rdma_test: Got the wrong value for hca_handles") | ||
| } | ||
| if rdmaEntries[0].HcaObjects != maxObjects { | ||
| t.Fatalf("rdma_test: Got the wrong value for hca_Objects") | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package configs | ||
|
|
||
| // LinuxRdma for Linux cgroup 'rdma' resource management (Linux 4.11) | ||
| type LinuxRdma struct { | ||
| // Maximum number of HCA handles that can be opened. Default is "no limit". | ||
| HcaHandles *uint32 `json:"hca_handles,omitempty"` | ||
| // Maximum number of HCA objects that can be created. Default is "no limit". | ||
| HcaObjects *uint32 `json:"hca_objects,omitempty"` | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.