|
9 | 9 | "os"
|
10 | 10 | "path/filepath"
|
11 | 11 | "sort"
|
| 12 | + "strconv" |
12 | 13 | "strings"
|
13 | 14 | "sync"
|
14 | 15 | "time"
|
|
41 | 42 | flag int
|
42 | 43 | }
|
43 | 44 | complexFlags map[string]func(*configs.Mount)
|
| 45 | + mpolModeMap map[specs.MemoryPolicyModeType]uint |
| 46 | + mpolModeFMap map[specs.MemoryPolicyFlagType]uint |
| 47 | +) |
| 48 | + |
| 49 | +const ( |
| 50 | + // maxNumaNode for a sensibility check to user-provided node |
| 51 | + // values and ranges. It does not reflect currently onlined nodes. |
| 52 | + // set_mempolicy() accepts call-time non-existent nodes, so do we. |
| 53 | + maxNumaNode = 1023 |
44 | 54 | )
|
45 | 55 |
|
46 | 56 | func initMaps() {
|
@@ -148,6 +158,22 @@ func initMaps() {
|
148 | 158 | m.IDMapping.Recursive = true
|
149 | 159 | },
|
150 | 160 | }
|
| 161 | + |
| 162 | + mpolModeMap = map[specs.MemoryPolicyModeType]uint{ |
| 163 | + specs.MpolDefault: 0, |
| 164 | + specs.MpolPreferred: 1, |
| 165 | + specs.MpolBind: 2, |
| 166 | + specs.MpolInterleave: 3, |
| 167 | + specs.MpolLocal: 4, |
| 168 | + specs.MpolPreferredMany: 5, |
| 169 | + specs.MpolWeightedInterleave: 6, |
| 170 | + } |
| 171 | + |
| 172 | + mpolModeFMap = map[specs.MemoryPolicyFlagType]uint{ |
| 173 | + specs.MpolFStaticNodes: 1 << 15, |
| 174 | + specs.MpolFRelativeNodes: 1 << 14, |
| 175 | + specs.MpolFNumaBalancing: 1 << 13, |
| 176 | + } |
151 | 177 | })
|
152 | 178 | }
|
153 | 179 |
|
@@ -184,6 +210,27 @@ func KnownMountOptions() []string {
|
184 | 210 | return res
|
185 | 211 | }
|
186 | 212 |
|
| 213 | +func KnownMemoryPolicyModes() []string { |
| 214 | + initMaps() |
| 215 | + var res []string |
| 216 | + for k := range mpolModeMap { |
| 217 | + res = append(res, string(k)) |
| 218 | + } |
| 219 | + sort.Strings(res) |
| 220 | + return res |
| 221 | +} |
| 222 | + |
| 223 | +func KnownMemoryPolicyFlags() []string { |
| 224 | + initMaps() |
| 225 | + var res []string |
| 226 | + for k := range mpolModeFMap { |
| 227 | + res = append(res, string(k)) |
| 228 | + } |
| 229 | + sort.Strings(res) |
| 230 | + return res |
| 231 | +} |
| 232 | + |
| 233 | + |
187 | 234 | // AllowedDevices is the set of devices which are automatically included for
|
188 | 235 | // all containers.
|
189 | 236 | //
|
@@ -467,6 +514,28 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
|
467 | 514 | MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
|
468 | 515 | }
|
469 | 516 | }
|
| 517 | + if spec.Linux.MemoryPolicy != nil && |
| 518 | + (spec.Linux.MemoryPolicy.Mode != "" || |
| 519 | + spec.Linux.MemoryPolicy.Nodes != "" || |
| 520 | + len(spec.Linux.MemoryPolicy.Flags) > 0) { |
| 521 | + var ok bool |
| 522 | + specMp := spec.Linux.MemoryPolicy |
| 523 | + confMp := &configs.LinuxMemoryPolicy{} |
| 524 | + if confMp.Mode, ok = mpolModeMap[specMp.Mode]; !ok { |
| 525 | + return nil, fmt.Errorf("invalid memory policy mode %q", specMp.Mode) |
| 526 | + } |
| 527 | + if confMp.Nodes, err = parseListSet(specMp.Nodes, 0, maxNumaNode); err != nil { |
| 528 | + return nil, fmt.Errorf("invalid memory policy nodes %q: %w", specMp.Nodes, err) |
| 529 | + } |
| 530 | + for _, specFlag := range specMp.Flags { |
| 531 | + confModeFlag, ok := mpolModeFMap[specFlag] |
| 532 | + if !ok { |
| 533 | + return nil, fmt.Errorf("invalid memory policy flag %q", specFlag) |
| 534 | + } |
| 535 | + confMp.Mode |= confModeFlag |
| 536 | + } |
| 537 | + config.MemoryPolicy = confMp |
| 538 | + } |
470 | 539 | if spec.Linux.Personality != nil {
|
471 | 540 | if len(spec.Linux.Personality.Flags) > 0 {
|
472 | 541 | logrus.Warnf("ignoring unsupported personality flags: %+v because personality flag has not supported at this time", spec.Linux.Personality.Flags)
|
@@ -1127,6 +1196,50 @@ func parseMountOptions(options []string) *configs.Mount {
|
1127 | 1196 | return &m
|
1128 | 1197 | }
|
1129 | 1198 |
|
| 1199 | +// parseListSet parses "list set" syntax ("0,61-63,2") into a list ([0, 61, 62, 63, 2]). |
| 1200 | +func parseListSet(listSet string, minValue, maxValue int) ([]int, error) { |
| 1201 | + var result []int |
| 1202 | + parts := strings.Split(listSet, ",") |
| 1203 | + for _, part := range parts { |
| 1204 | + switch { |
| 1205 | + case part == "": |
| 1206 | + continue |
| 1207 | + case strings.Contains(part, "-"): |
| 1208 | + rangeParts := strings.Split(part, "-") |
| 1209 | + if len(rangeParts) != 2 { |
| 1210 | + return nil, fmt.Errorf("invalid range: %s", part) |
| 1211 | + } |
| 1212 | + start, err := strconv.Atoi(rangeParts[0]) |
| 1213 | + if err != nil { |
| 1214 | + return nil, err |
| 1215 | + } |
| 1216 | + end, err := strconv.Atoi(rangeParts[1]) |
| 1217 | + if err != nil { |
| 1218 | + return nil, err |
| 1219 | + } |
| 1220 | + if start > end { |
| 1221 | + return nil, fmt.Errorf("invalid range %s: start > end", part) |
| 1222 | + } |
| 1223 | + if start < minValue || end > maxValue { |
| 1224 | + return nil, fmt.Errorf("invalid range %s: out of range %d-%d", part, minValue, maxValue) |
| 1225 | + } |
| 1226 | + for i := start; i <= end; i++ { |
| 1227 | + result = append(result, i) |
| 1228 | + } |
| 1229 | + default: |
| 1230 | + num, err := strconv.Atoi(part) |
| 1231 | + if err != nil { |
| 1232 | + return nil, err |
| 1233 | + } |
| 1234 | + if num < minValue || num > maxValue { |
| 1235 | + return nil, fmt.Errorf("invalid value %d: out of range %d-%d", num, minValue, maxValue) |
| 1236 | + } |
| 1237 | + result = append(result, num) |
| 1238 | + } |
| 1239 | + } |
| 1240 | + return result, nil |
| 1241 | +} |
| 1242 | + |
1130 | 1243 | func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
|
1131 | 1244 | if config == nil {
|
1132 | 1245 | return nil, nil
|
|
0 commit comments