|
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 |
|
@@ -467,6 +493,28 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
|
467 | 493 | MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
|
468 | 494 | }
|
469 | 495 | }
|
| 496 | + if spec.Linux.MemoryPolicy != nil && |
| 497 | + (spec.Linux.MemoryPolicy.Mode != "" || |
| 498 | + spec.Linux.MemoryPolicy.Nodes != "" || |
| 499 | + len(spec.Linux.MemoryPolicy.Flags) > 0) { |
| 500 | + var ok bool |
| 501 | + specMp := spec.Linux.MemoryPolicy |
| 502 | + confMp := &configs.LinuxMemoryPolicy{} |
| 503 | + if confMp.Mode, ok = mpolModeMap[specMp.Mode]; !ok { |
| 504 | + return nil, fmt.Errorf("invalid memory policy mode %q", specMp.Mode) |
| 505 | + } |
| 506 | + if confMp.Nodes, err = parseListSet(specMp.Nodes, 0, maxNumaNode); err != nil { |
| 507 | + return nil, fmt.Errorf("invalid memory policy nodes %q: %w", specMp.Nodes, err) |
| 508 | + } |
| 509 | + for _, specFlag := range specMp.Flags { |
| 510 | + confModeFlag, ok := mpolModeFMap[specFlag] |
| 511 | + if !ok { |
| 512 | + return nil, fmt.Errorf("invalid memory policy flag %q", specFlag) |
| 513 | + } |
| 514 | + confMp.Mode |= confModeFlag |
| 515 | + } |
| 516 | + config.MemoryPolicy = confMp |
| 517 | + } |
470 | 518 | if spec.Linux.Personality != nil {
|
471 | 519 | if len(spec.Linux.Personality.Flags) > 0 {
|
472 | 520 | logrus.Warnf("ignoring unsupported personality flags: %+v because personality flag has not supported at this time", spec.Linux.Personality.Flags)
|
@@ -1127,6 +1175,53 @@ func parseMountOptions(options []string) *configs.Mount {
|
1127 | 1175 | return &m
|
1128 | 1176 | }
|
1129 | 1177 |
|
| 1178 | +// parseListSet parses "list set" syntax ("0,61-63,2") into a list ([0, 61, 62, 63, 2]). |
| 1179 | +func parseListSet(listSet string, minValue, maxValue int) ([]int, error) { |
| 1180 | + var result []int |
| 1181 | + if listSet == "" { |
| 1182 | + return result, nil |
| 1183 | + } |
| 1184 | + parts := strings.Split(listSet, ",") |
| 1185 | + for _, part := range parts { |
| 1186 | + switch { |
| 1187 | + case part == "": |
| 1188 | + continue |
| 1189 | + case strings.Contains(part, "-"): |
| 1190 | + rangeParts := strings.Split(part, "-") |
| 1191 | + if len(rangeParts) != 2 { |
| 1192 | + return nil, fmt.Errorf("invalid range: %s", part) |
| 1193 | + } |
| 1194 | + start, err := strconv.Atoi(rangeParts[0]) |
| 1195 | + if err != nil { |
| 1196 | + return nil, err |
| 1197 | + } |
| 1198 | + end, err := strconv.Atoi(rangeParts[1]) |
| 1199 | + if err != nil { |
| 1200 | + return nil, err |
| 1201 | + } |
| 1202 | + if start > end { |
| 1203 | + return nil, fmt.Errorf("invalid range %s: start > end", part) |
| 1204 | + } |
| 1205 | + if start < minValue || end > maxValue { |
| 1206 | + return nil, fmt.Errorf("invalid range %s: not in %d-%d", part, minValue, maxValue) |
| 1207 | + } |
| 1208 | + for i := start; i <= end; i++ { |
| 1209 | + result = append(result, i) |
| 1210 | + } |
| 1211 | + default: |
| 1212 | + num, err := strconv.Atoi(part) |
| 1213 | + if err != nil { |
| 1214 | + return nil, err |
| 1215 | + } |
| 1216 | + if num < minValue || num > maxValue { |
| 1217 | + return nil, fmt.Errorf("invalid value %d: not in %d-%d", num, minValue, maxValue) |
| 1218 | + } |
| 1219 | + result = append(result, num) |
| 1220 | + } |
| 1221 | + } |
| 1222 | + return result, nil |
| 1223 | +} |
| 1224 | + |
1130 | 1225 | func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
|
1131 | 1226 | if config == nil {
|
1132 | 1227 | return nil, nil
|
|
0 commit comments