Skip to content
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

Add racct limit option #11

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions cmd/runj/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ the console's pseudoterminal`)
if err := jail.CreateJail(cmd.Context(), confPath); err != nil {
return err
}
err = jail.Limit(id, ociConfig)
if err != nil {
return err
}
defer func() {
if err == nil {
return
}
jail.Unlimit(id, ociConfig)
}()
err = jail.Mount(ociConfig)
if err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions cmd/runj/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func deleteCommand() *cobra.Command {
if ociConfig == nil {
return errors.New("OCI config is required")
}
err = jail.Unlimit(id, ociConfig)
if err != nil {
return err
}
err = jail.Unmount(ociConfig)
if err != nil {
return err
Expand Down
123 changes: 123 additions & 0 deletions jail/limit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package jail

import (
"fmt"
"os/exec"

"go.sbk.wtf/runj/runtimespec"
)

// Limit uses rctl to add the rct rules
func Limit(id string, ociConfig *runtimespec.Spec) error {
if ociConfig.FreeBSD == nil {
return nil
}
for _, rule := range makeRCTLRules(id, ociConfig.FreeBSD.Resources) {
cmd := exec.Command("rctl", "-a", rule)
err := cmd.Run()
if err != nil {
return err
}
}
return nil
}

// Unlimit uses rctl to remove the rctl rules
func Unlimit(id string, ociConfig *runtimespec.Spec) error {
if ociConfig.FreeBSD == nil {
return nil
}
for _, rule := range makeRCTLRules(id, ociConfig.FreeBSD.Resources) {
cmd := exec.Command("rctl", "-r", rule)
err := cmd.Run()
if err != nil {
return err
}
}
return nil
}

func makeRCTLMemoryRules(id string, memory *runtimespec.FreeBSDMemory) []string {
var rules []string
if memory.Limit != nil {
rules = append(rules, formatRCTLRule(id, "memoryuse", "deny", *memory.Limit))
}
if memory.Warning != nil {
rules = append(rules, formatRCTLRule(id, "memoryuse", "devctl", *memory.Warning))
}
if memory.Swap != nil {
rules = append(rules, formatRCTLRule(id, "swapuse", "deny", *memory.Swap))
}
if memory.SwapWarning != nil {
rules = append(rules, formatRCTLRule(id, "swapuse", "devctl", *memory.SwapWarning))
}
return rules
}

func makeRCTLFSIORules(id string, fsio *runtimespec.FreeBSDFSIO) []string {
var rules []string
if fsio.ReadBPS != nil {
rules = append(rules, formatRCTLRule(id, "readbps", "throttle", *fsio.ReadBPS))
}
if fsio.WriteBPS != nil {
rules = append(rules, formatRCTLRule(id, "writebps", "throttle", *fsio.WriteBPS))
}
if fsio.ReadIOPS != nil {
rules = append(rules, formatRCTLRule(id, "readiops", "throttle", *fsio.ReadIOPS))
}
if fsio.WriteIOPS != nil {
rules = append(rules, formatRCTLRule(id, "writeiops", "throttle", *fsio.WriteIOPS))
}
return rules
}

func makeRCTLShmRules(id string, shm *runtimespec.FreeBSDShm) []string {
var rules []string
if shm.Count != nil {
rules = append(rules, formatRCTLRule(id, "nshm", "deny", *shm.Count))
}
if shm.Size != nil {
rules = append(rules, formatRCTLRule(id, "shmsize", "deny", *shm.Size))
}
return rules
}

func makeRCTLCPURules(id string, cpu *runtimespec.FreeBSDCPU) []string {
var rules []string
if cpu.Limit != nil {
rules = append(rules, formatRCTLRule(id, "pcpu", "deny", *cpu.Limit))
}
return rules
}

func makeRCTLProcessRules(id string, proc *runtimespec.FreeBSDProcess) []string {
var rules []string
if proc.Limit != nil {
rules = append(rules, formatRCTLRule(id, "maxproc", "deny", *proc.Limit))
}
return rules
}

func makeRCTLRules(id string, resources *runtimespec.FreeBSDResources) []string {
var rules []string
if resources.Memory != nil {
rules = append(rules, makeRCTLMemoryRules(id, resources.Memory)...)
}
if resources.FSIO != nil {
rules = append(rules, makeRCTLFSIORules(id, resources.FSIO)...)
}
if resources.Shm != nil {
rules = append(rules, makeRCTLShmRules(id, resources.Shm)...)
}
if resources.CPU != nil {
rules = append(rules, makeRCTLCPURules(id, resources.CPU)...)
}
if resources.Process != nil {
rules = append(rules, makeRCTLProcessRules(id, resources.Process)...)
}
return rules
}

func formatRCTLRule(id string, resource string, action string, amount uint64) string {
return fmt.Sprintf("jail:%v:%v:%v=%v", id, resource, action, amount)
}
66 changes: 66 additions & 0 deletions runtimespec/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ type Spec struct {
VM *VM `json:"vm,omitempty" platform:"vm"`
*/
// End of modification

// Modification by Cyril Zhang
// FreeBSD is platform-specific configuration for FreeBSD based containers.
FreeBSD *FreeBSD `json:"freebsd,omitempty" platform:"freebsd"`
// End of modification
}

// Modification by Samuel Karp
Expand Down Expand Up @@ -135,6 +140,67 @@ type Mount struct {
Options []string `json:"options,omitempty"`
}

// Modification by Cyril Zhang
// FreeBSD contains platform-specific configuration for FreeBSD based containers.
type FreeBSD struct {
// Resources is resource limits for FreeBSD.
Resources *FreeBSDResources `json:"resources,omitempty"`
}

// FreeBSDResources contains a set of resource limits for FreeBSD.
type FreeBSDResources struct {
// Memory is the memory restriction configuration.
Memory *FreeBSDMemory `json:"memory,omitempty"`
// FSIO is the filesystem IO restriction configuration.
FSIO *FreeBSDFSIO `json:"fsIO,omitempty"`
// Shm is the shared memory restriction configuration.
Shm *FreeBSDShm `json:"shm,omitempty"`
// CPU is the CPU restriction configuration.
CPU *FreeBSDCPU `json:"cpu,omitempty"`
// Process is the process restriction configuration.
Process *FreeBSDProcess `json:"process,omitempty"`
}

type FreeBSDMemory struct {
// Limit is the memory limit (in bytes).
Limit *uint64 `json:"limit,omitempty"`
// Warning is the amount of memory (in bytes) where a warning is sent to devd(8).
Warning *uint64 `json:"warning,omitempty"`
// Swap is the amount of swap that may be used (in bytes).
Swap *uint64 `json:"swap,omitempty"`
// SwapWarning is the amount of swap (in bytes) where a warning is sent to devd(8).
SwapWarning *uint64 `json:"swapWarning,omitempty"`
}

type FreeBSDFSIO struct {
// ReadBPS is the rate of filesystem reads (in bytes per second) before throttling occurs.
ReadBPS *uint64 `json:"readbps,omitempty"`
// WriteBPS is the rate of filesystem writes (in bytes per second) before throttling occurs.
WriteBPS *uint64 `json:"writebps,omitempty"`
// ReadIOPS is the rate of filesystem read (in operations per second) before throttling occurs.
ReadIOPS *uint64 `json:"readiops,omitempty"`
// WriteBPS is the rate of filesystem writes (in operations per second) before throttling occurs.
WriteIOPS *uint64 `json:"writeiops,omitempty"`
}

type FreeBSDShm struct {
// Count is the limit of shared memory object count.
Count *uint64 `json:"count,omitempty"`
// Size is the limit of total shared memory object size (in bytes).
Size *uint64 `json:"size,omitempty"`
}

type FreeBSDCPU struct {
// Limit is limit of CPU usage (in percent of a single CPU).
Limit *uint64 `json:"limit,omitempty"`
}

type FreeBSDProcess struct {
// Limit is the limit of process count.
Limit *uint64 `json:"limit,omitempty"`
}
// End of modification

// Modification by Samuel Karp
/*
Omitted type definitions for:
Expand Down