Skip to content

Commit e86e8e1

Browse files
authored
Merge pull request #1950 from jakecorrenti/annotations
krun: support OCI annotations to configure microVM
2 parents 2fc8fc7 + 2bff129 commit e86e8e1

File tree

3 files changed

+84
-30
lines changed

3 files changed

+84
-30
lines changed

src/libcrun/container.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ static char *potentially_unsafe_annotations[] = {
383383
"io.kubernetes.cri.container-type",
384384
"run.oci.",
385385
"org.criu.",
386+
"krun.",
386387
};
387388

388389
#define SYNC_SOCKET_MESSAGE_LEN(x, l) (offsetof (struct sync_socket_message_s, message) + l)

src/libcrun/handlers/krun.c

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
/* libkrun has a hard-limit of 16 vCPUs per microVM. */
4444
#define LIBKRUN_MAX_VCPUS 16
4545

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+
4652
/* crun dumps the container configuration into this file, which will be read by
4753
* libkrun to set up the environment for the workload inside the microVM.
4854
*/
@@ -184,68 +190,114 @@ libkrun_read_vm_config (yajl_val *config_tree, libcrun_error_t *err)
184190
return 0;
185191
}
186192

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+
*/
187201
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)
189237
{
190238
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;
193240
const char *path_cpus[] = { "cpus", (const char *) 0 };
194241
const char *path_ram_mib[] = { "ram_mib", (const char *) 0 };
195-
int ret;
196242

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;
199246

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;
213250

214251
krun_set_vm_config = dlsym (handle, "krun_set_vm_config");
215252

216253
if (krun_set_vm_config == NULL)
217254
return crun_make_error (err, 0, "could not find symbol in the krun library");
218255

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);
220257
if (UNLIKELY (ret < 0))
221258
return crun_make_error (err, -ret, "could not set krun vm configuration");
222259

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+
223271
*configured = true;
224272

225273
return 0;
226274
}
227275

228276
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)
230278
{
231279
int ret, sev_indicated = 0, nitro_indicated = 0;
232280
const char *path_flavor[] = { "flavor", (const char *) 0 };
233281
struct krun_config *kconf = (struct krun_config *) cookie;
234282
yajl_val val_flavor = NULL;
235-
char *flavor = NULL;
283+
const char *flavor = NULL;
236284
void *close_handles[2];
237285

238286
close_handles[0] = NULL;
239287
close_handles[1] = NULL;
240288

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)
244292
{
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+
}
246298

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+
{
249301
sev_indicated |= strcmp (flavor, KRUN_FLAVOR_SEV) == 0;
250302
nitro_indicated |= strcmp (flavor, KRUN_FLAVOR_NITRO) == 0;
251303
}
@@ -327,7 +379,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
327379
if (UNLIKELY (ret < 0))
328380
error (EXIT_FAILURE, -ret, "libkrun VM config exists, but unable to parse");
329381

330-
ret = libkrun_configure_flavor (cookie, &config_tree, &err);
382+
ret = libkrun_configure_flavor (cookie, &config_tree, container, &err);
331383
if (UNLIKELY (ret < 0))
332384
error (EXIT_FAILURE, -ret, "unable to configure libkrun flavor");
333385

@@ -391,7 +443,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
391443
error (EXIT_FAILURE, -ret, "could not set enclave execution arguments");
392444
}
393445

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);
395447
if (UNLIKELY (ret))
396448
{
397449
int errcode = crun_error_get_errno (&err);

tests/test_oci_features.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def test_crun_features():
175175
"io.kubernetes.cri.container-type",
176176
"run.oci.",
177177
"org.criu.",
178+
"krun.",
178179
]
179180
}
180181

0 commit comments

Comments
 (0)