Skip to content
Draft
Changes from 1 commit
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
117 changes: 117 additions & 0 deletions src/libcrun/handlers/krun.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "../linux.h"
#include <unistd.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
Expand Down Expand Up @@ -62,6 +63,9 @@
#define KRUN_FLAVOR_NITRO "aws-nitro"
#define KRUN_FLAVOR_SEV "sev"

#define PASST_FD_PARENT 0
#define PASST_FD_CHILD 1

struct krun_config
{
void *handle;
Expand All @@ -74,6 +78,7 @@ struct krun_config
int32_t ctx_id_nitro;
bool has_kvm;
bool has_nitro;
int passt_fds[2];
};

/* libkrun handler. */
Expand Down Expand Up @@ -350,6 +355,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
int32_t (*krun_set_root) (uint32_t ctx_id, const char *root_path);
int32_t (*krun_set_root_disk) (uint32_t ctx_id, const char *disk_path);
int32_t (*krun_set_tee_config_file) (uint32_t ctx_id, const char *file_path);
int32_t (*krun_add_net_unixstream) (uint32_t ctx_id, const char *c_path, int fd, uint8_t *const c_mac, uint32_t features, uint32_t flags);
struct krun_config *kconf = (struct krun_config *) cookie;
void *handle;
uint32_t num_vcpus, ram_mib;
Expand Down Expand Up @@ -450,6 +456,13 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
if (UNLIKELY (ret < 0))
error (EXIT_FAILURE, -ret, "could not set krun vm configuration");

krun_add_net_unixstream = dlsym (handle, "krun_add_net_unixstream");

uint8_t mac[] = { 0x5a, 0x94, 0xef, 0xe4, 0x0c, 0xee };
ret = krun_add_net_unixstream (ctx_id, NULL, kconf->passt_fds[PASST_FD_PARENT], &mac[0], COMPAT_NET_FEATURES, 0);
if (UNLIKELY (ret < 0))
error (EXIT_FAILURE, -ret, "could not set krun net configuration");

if (access ("/dev/dri", F_OK) == 0 && access ("/usr/libexec/virgl_render_server", F_OK) == 0)
{
ret = libkrun_enable_virtio_gpu (kconf);
Expand All @@ -464,6 +477,69 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
return -ret;
}

static int
libkrun_start_passt (void *cookie)
{
struct krun_config *kconf = (struct krun_config *) cookie;
pid_t pid;
char fd_as_str[16];
int pipefd[2];
int ret;

socketpair (AF_UNIX, SOCK_STREAM, 0, kconf->passt_fds);
snprintf (fd_as_str, sizeof (fd_as_str), "%d", kconf->passt_fds[PASST_FD_CHILD]);

char *const argv[] = {
(char *) "passt",
(char *) "-t",
(char *) "all",
(char *) "-u",
(char *) "all",
(char *) "-f",
(char *) "--fd",
fd_as_str,
NULL
};

ret = pipe (pipefd);
if (UNLIKELY (ret == -1))
return ret;

pid = fork ();
if (pid < 0)
{
close (pipefd[0]);
close (pipefd[1]);
return pid;
}
else if (pid == 0)
{
close (pipefd[0]);

ret = dup2 (pipefd[1], STDERR_FILENO);
if (UNLIKELY (ret == -1))
{
exit (EXIT_FAILURE);
}

close (pipefd[1]);
execvp ("passt", argv);
}
else
{
/* We need to make sure passt has already started before continuing. A
simple way to do it is with a blocking read on its stdout. */

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, you can skip this whole dance by not passing -f: passt behaves like usual UNIX daemons and forks into background when it's ready, and if you give -1 / --one-off, it terminates by itself once the guest disconnects.

Conversely, getting something from its stdout doesn't guarantee that it's ready. Which is the only (minor) issue I spotted here, by the way, so if you need to stick to this approach for whatever reason it looks fine to me as well.

char buffer[1];
close (pipefd[1]);
ret = read (pipefd[0], buffer, 1);
if (UNLIKELY (ret < 0))
return ret;
close (pipefd[0]);
}

return 0;
}

/* libkrun_create_kvm_device: explicitly adds kvm device. */
static int
libkrun_configure_container (void *cookie, enum handler_configure_phase phase,
Expand Down Expand Up @@ -525,6 +601,10 @@ libkrun_configure_container (void *cookie, enum handler_configure_phase phase,
if (phase != HANDLER_CONFIGURE_AFTER_MOUNTS)
return 0;

ret = libkrun_start_passt (cookie);
if (UNLIKELY (ret < 0))
return crun_make_error (err, errno, "start passt");

/* Do nothing if /dev/kvm is already present in spec */
for (i = 0; i < def->linux->devices_len; i++)
{
Expand Down Expand Up @@ -781,6 +861,42 @@ libkrun_modify_oci_configuration (void *cookie arg_unused, libcrun_context_t *co
return 0;
}

static int
libkrun_close_fds (void *cookie, int preserve_fds)
{
struct krun_config *kconf = (struct krun_config *) cookie;
int first_fd_to_close = preserve_fds + 3;
int high_passt_fd;
int low_passt_fd;
int ret;
int i;

if (kconf->passt_fds[PASST_FD_CHILD] > kconf->passt_fds[PASST_FD_PARENT])
{
high_passt_fd = kconf->passt_fds[PASST_FD_CHILD];
low_passt_fd = kconf->passt_fds[PASST_FD_PARENT];
}
else
{
high_passt_fd = kconf->passt_fds[PASST_FD_PARENT];
low_passt_fd = kconf->passt_fds[PASST_FD_CHILD];
}

if (first_fd_to_close < high_passt_fd)
{
for (i = first_fd_to_close; i < high_passt_fd; i++)
{
if (i == low_passt_fd)
continue;
close (i);
}

first_fd_to_close = high_passt_fd + 1;
}

return mark_or_close_fds_ge_than (first_fd_to_close, true, NULL);
}

struct custom_handler_s handler_libkrun = {
.name = "krun",
.alias = NULL,
Expand All @@ -790,6 +906,7 @@ struct custom_handler_s handler_libkrun = {
.run_func = libkrun_exec,
.configure_container = libkrun_configure_container,
.modify_oci_configuration = libkrun_modify_oci_configuration,
.close_fds = libkrun_close_fds,
};

#endif