|
43 | 43 | /* libkrun has a hard-limit of 16 vCPUs per microVM. */ |
44 | 44 | #define LIBKRUN_MAX_VCPUS 16 |
45 | 45 |
|
| 46 | +/* If the user doesn't configure the vCPU count, fallback to this value. */ |
| 47 | +#define LIBKRUN_DEFAULT_VCPUS 1 |
| 48 | + |
| 49 | +/* If the user doesn't configure the RAM amount, fallback to this value. */ |
| 50 | +#define LIBKRUN_DEFAULT_RAM_MIB 1024 |
| 51 | + |
46 | 52 | /* crun dumps the container configuration into this file, which will be read by |
47 | 53 | * libkrun to set up the environment for the workload inside the microVM. |
48 | 54 | */ |
@@ -184,68 +190,114 @@ libkrun_read_vm_config (yajl_val *config_tree, libcrun_error_t *err) |
184 | 190 | return 0; |
185 | 191 | } |
186 | 192 |
|
| 193 | +/* |
| 194 | + * Default to parsing the OCI annotations to find the specified microVM |
| 195 | + * attribute. If the desired attribute is not found within the OCI annotations |
| 196 | + * or the krun_vm.json file, then return a negative integer. |
| 197 | + * |
| 198 | + * The configuration precedence is as follows: |
| 199 | + * OCI annotations -> krun_vm.json. |
| 200 | + */ |
187 | 201 | static int |
188 | | -libkrun_configure_vm (uint32_t ctx_id, void *handle, bool *configured, yajl_val *config_tree, libcrun_error_t *err) |
| 202 | +libkrun_parse_resource_configuration (yajl_val *config_tree, libcrun_container_t *container, const char *annotation, const char *path[]) |
| 203 | +{ |
| 204 | + char *val_str, *endptr; |
| 205 | + int val = -1; |
| 206 | + yajl_val val_json = NULL; |
| 207 | + |
| 208 | + val_str = (char *) find_annotation (container, annotation); |
| 209 | + if (val_str != NULL) |
| 210 | + { |
| 211 | + errno = 0; |
| 212 | + val = (int) strtol (val_str, &endptr, 10); |
| 213 | + if (errno != 0 || endptr == val_str || *endptr != '\0') |
| 214 | + /* Annotations value is not a valid integer. */ |
| 215 | + error (EXIT_FAILURE, 0, "krun annotation %s value cannot be converted to an integer", annotation); |
| 216 | + |
| 217 | + if (val <= 0) |
| 218 | + error (EXIT_FAILURE, 0, "krun annotation %s value must be a positive integer", annotation); |
| 219 | + |
| 220 | + return val; |
| 221 | + } |
| 222 | + else if (*config_tree != NULL) |
| 223 | + { |
| 224 | + val_json = yajl_tree_get (*config_tree, path, yajl_t_number); |
| 225 | + if (! YAJL_IS_INTEGER (val_json)) |
| 226 | + error (EXIT_FAILURE, 0, "krun krun_vm.json %s value is not an integer", path[0]); |
| 227 | + |
| 228 | + if (! (val = (int) YAJL_GET_INTEGER (val_json))) |
| 229 | + error (EXIT_FAILURE, 0, "krun krun_vm.json %s value must be a positive integer", path[0]); |
| 230 | + } |
| 231 | + |
| 232 | + return val; |
| 233 | +} |
| 234 | + |
| 235 | +static int |
| 236 | +libkrun_configure_vm (uint32_t ctx_id, void *handle, bool *configured, yajl_val *config_tree, libcrun_container_t *container, libcrun_error_t *err) |
189 | 237 | { |
190 | 238 | int32_t (*krun_set_vm_config) (uint32_t ctx_id, uint8_t num_vcpus, uint32_t ram_mib); |
191 | | - yajl_val cpus = NULL; |
192 | | - yajl_val ram_mib = NULL; |
| 239 | + int cpus, ram_mib, ret; |
193 | 240 | const char *path_cpus[] = { "cpus", (const char *) 0 }; |
194 | 241 | const char *path_ram_mib[] = { "ram_mib", (const char *) 0 }; |
195 | | - int ret; |
196 | 242 |
|
197 | | - if (*config_tree == NULL) |
198 | | - return 0; |
| 243 | + cpus = libkrun_parse_resource_configuration (config_tree, container, "krun.cpus", path_cpus); |
| 244 | + if (cpus <= 0) |
| 245 | + cpus = LIBKRUN_DEFAULT_VCPUS; |
199 | 246 |
|
200 | | - /* Try to configure an external kernel. If the configuration file doesn't |
201 | | - * specify a kernel, libkrun automatically fall back to using libkrunfw, |
202 | | - * if the library is present and was loaded while creating the context. |
203 | | - */ |
204 | | - ret = libkrun_configure_kernel (ctx_id, handle, config_tree, err); |
205 | | - if (UNLIKELY (ret)) |
206 | | - return ret; |
207 | | - |
208 | | - cpus = yajl_tree_get (*config_tree, path_cpus, yajl_t_number); |
209 | | - ram_mib = yajl_tree_get (*config_tree, path_ram_mib, yajl_t_number); |
210 | | - /* Both cpus and ram_mib must be present at the same time */ |
211 | | - if (cpus == NULL || ram_mib == NULL || ! YAJL_IS_INTEGER (cpus) || ! YAJL_IS_INTEGER (ram_mib)) |
212 | | - return 0; |
| 247 | + ram_mib = libkrun_parse_resource_configuration (config_tree, container, "krun.ram_mib", path_ram_mib); |
| 248 | + if (ram_mib <= 0) |
| 249 | + ram_mib = LIBKRUN_DEFAULT_RAM_MIB; |
213 | 250 |
|
214 | 251 | krun_set_vm_config = dlsym (handle, "krun_set_vm_config"); |
215 | 252 |
|
216 | 253 | if (krun_set_vm_config == NULL) |
217 | 254 | return crun_make_error (err, 0, "could not find symbol in the krun library"); |
218 | 255 |
|
219 | | - ret = krun_set_vm_config (ctx_id, YAJL_GET_INTEGER (cpus), YAJL_GET_INTEGER (ram_mib)); |
| 256 | + ret = krun_set_vm_config (ctx_id, cpus, ram_mib); |
220 | 257 | if (UNLIKELY (ret < 0)) |
221 | 258 | return crun_make_error (err, -ret, "could not set krun vm configuration"); |
222 | 259 |
|
| 260 | + if (*config_tree != NULL) |
| 261 | + { |
| 262 | + /* Try to configure an external kernel. If the configuration file doesn't |
| 263 | + * specify a kernel, libkrun automatically fall back to using libkrunfw, |
| 264 | + * if the library is present and was loaded while creating the context. |
| 265 | + */ |
| 266 | + ret = libkrun_configure_kernel (ctx_id, handle, config_tree, err); |
| 267 | + if (UNLIKELY (ret)) |
| 268 | + return ret; |
| 269 | + } |
| 270 | + |
223 | 271 | *configured = true; |
224 | 272 |
|
225 | 273 | return 0; |
226 | 274 | } |
227 | 275 |
|
228 | 276 | static int |
229 | | -libkrun_configure_flavor (void *cookie, yajl_val *config_tree, libcrun_error_t *err) |
| 277 | +libkrun_configure_flavor (void *cookie, yajl_val *config_tree, libcrun_container_t *container, libcrun_error_t *err) |
230 | 278 | { |
231 | 279 | int ret, sev_indicated = 0, nitro_indicated = 0; |
232 | 280 | const char *path_flavor[] = { "flavor", (const char *) 0 }; |
233 | 281 | struct krun_config *kconf = (struct krun_config *) cookie; |
234 | 282 | yajl_val val_flavor = NULL; |
235 | | - char *flavor = NULL; |
| 283 | + const char *flavor = NULL; |
236 | 284 | void *close_handles[2]; |
237 | 285 |
|
238 | 286 | close_handles[0] = NULL; |
239 | 287 | close_handles[1] = NULL; |
240 | 288 |
|
241 | | - // Read if the SEV flavor was indicated in the krun VM config. |
242 | | - val_flavor = yajl_tree_get (*config_tree, path_flavor, yajl_t_string); |
243 | | - if (val_flavor != NULL && YAJL_IS_STRING (val_flavor)) |
| 289 | + // Check if the user provided the krun variant through OCI annotations. |
| 290 | + flavor = find_annotation (container, "krun.variant"); |
| 291 | + if (flavor == NULL && *config_tree != NULL) |
244 | 292 | { |
245 | | - flavor = YAJL_GET_STRING (val_flavor); |
| 293 | + // If the user doesn't specify a variant via OCI annotations, check the krun VM config to see if the "flavor" field was populated. |
| 294 | + val_flavor = yajl_tree_get (*config_tree, path_flavor, yajl_t_string); |
| 295 | + if (val_flavor != NULL && YAJL_IS_STRING (val_flavor)) |
| 296 | + flavor = YAJL_GET_STRING (val_flavor); |
| 297 | + } |
246 | 298 |
|
247 | | - // The SEV flavor will be used if the krun VM config indicates to use SEV |
248 | | - // within the "flavor" field. |
| 299 | + if (flavor != NULL) |
| 300 | + { |
249 | 301 | sev_indicated |= strcmp (flavor, KRUN_FLAVOR_SEV) == 0; |
250 | 302 | nitro_indicated |= strcmp (flavor, KRUN_FLAVOR_NITRO) == 0; |
251 | 303 | } |
@@ -327,7 +379,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname |
327 | 379 | if (UNLIKELY (ret < 0)) |
328 | 380 | error (EXIT_FAILURE, -ret, "libkrun VM config exists, but unable to parse"); |
329 | 381 |
|
330 | | - ret = libkrun_configure_flavor (cookie, &config_tree, &err); |
| 382 | + ret = libkrun_configure_flavor (cookie, &config_tree, container, &err); |
331 | 383 | if (UNLIKELY (ret < 0)) |
332 | 384 | error (EXIT_FAILURE, -ret, "unable to configure libkrun flavor"); |
333 | 385 |
|
@@ -391,7 +443,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname |
391 | 443 | error (EXIT_FAILURE, -ret, "could not set enclave execution arguments"); |
392 | 444 | } |
393 | 445 |
|
394 | | - ret = libkrun_configure_vm (ctx_id, handle, &configured, &config_tree, &err); |
| 446 | + ret = libkrun_configure_vm (ctx_id, handle, &configured, &config_tree, container, &err); |
395 | 447 | if (UNLIKELY (ret)) |
396 | 448 | { |
397 | 449 | int errcode = crun_error_get_errno (&err); |
|
0 commit comments