Skip to content

Commit a7b9774

Browse files
slptylerfanelli
authored andcommitted
krun: switch to passt-based networking
Automatically start passt and use it for adding a virtio-net interface to the microVM. This allows us to have networking even when running generic kernels that doesn't support TSI. Signed-off-by: Sergio Lopez <slp@redhat.com>
1 parent 1486f4b commit a7b9774

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

src/libcrun/handlers/krun.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "../linux.h"
2525
#include <unistd.h>
2626
#include <sys/stat.h>
27+
#include <sys/socket.h>
2728
#include <errno.h>
2829
#include <sys/param.h>
2930
#include <sys/types.h>
@@ -62,6 +63,9 @@
6263
#define KRUN_FLAVOR_NITRO "aws-nitro"
6364
#define KRUN_FLAVOR_SEV "sev"
6465

66+
#define PASST_FD_PARENT 0
67+
#define PASST_FD_CHILD 1
68+
6569
struct krun_config
6670
{
6771
void *handle;
@@ -74,6 +78,7 @@ struct krun_config
7478
int32_t ctx_id_nitro;
7579
bool has_kvm;
7680
bool has_nitro;
81+
int passt_fds[2];
7782
};
7883

7984
/* libkrun handler. */
@@ -314,6 +319,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
314319
int32_t (*krun_set_console_output) (uint32_t ctx_id, const char *c_filepath);
315320
int32_t (*krun_set_exec) (uint32_t ctx_id, const char *exec_path,
316321
const char *const argv[], const char *const envp[]);
322+
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);
317323
struct krun_config *kconf = (struct krun_config *) cookie;
318324
void *handle;
319325
uint32_t num_vcpus, ram_mib;
@@ -426,6 +432,13 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
426432
if (UNLIKELY (ret < 0))
427433
error (EXIT_FAILURE, -ret, "could not set krun vm configuration");
428434

435+
krun_add_net_unixstream = dlsym (handle, "krun_add_net_unixstream");
436+
437+
uint8_t mac[] = { 0x5a, 0x94, 0xef, 0xe4, 0x0c, 0xee };
438+
ret = krun_add_net_unixstream (ctx_id, NULL, kconf->passt_fds[PASST_FD_PARENT], &mac[0], COMPAT_NET_FEATURES, 0);
439+
if (UNLIKELY (ret < 0))
440+
error (EXIT_FAILURE, -ret, "could not set krun net configuration");
441+
429442
if (access ("/dev/dri", F_OK) == 0 && access ("/usr/libexec/virgl_render_server", F_OK) == 0)
430443
{
431444
ret = libkrun_enable_virtio_gpu (kconf);
@@ -440,6 +453,69 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
440453
return -ret;
441454
}
442455

456+
static int
457+
libkrun_start_passt (void *cookie)
458+
{
459+
struct krun_config *kconf = (struct krun_config *) cookie;
460+
pid_t pid;
461+
char fd_as_str[16];
462+
int pipefd[2];
463+
int ret;
464+
465+
socketpair (AF_UNIX, SOCK_STREAM, 0, kconf->passt_fds);
466+
snprintf (fd_as_str, sizeof (fd_as_str), "%d", kconf->passt_fds[PASST_FD_CHILD]);
467+
468+
char *const argv[] = {
469+
(char *) "passt",
470+
(char *) "-t",
471+
(char *) "all",
472+
(char *) "-u",
473+
(char *) "all",
474+
(char *) "-f",
475+
(char *) "--fd",
476+
fd_as_str,
477+
NULL
478+
};
479+
480+
ret = pipe (pipefd);
481+
if (UNLIKELY (ret == -1))
482+
return ret;
483+
484+
pid = fork ();
485+
if (pid < 0)
486+
{
487+
close (pipefd[0]);
488+
close (pipefd[1]);
489+
return pid;
490+
}
491+
else if (pid == 0)
492+
{
493+
close (pipefd[0]);
494+
495+
ret = dup2 (pipefd[1], STDERR_FILENO);
496+
if (UNLIKELY (ret == -1))
497+
{
498+
exit (EXIT_FAILURE);
499+
}
500+
501+
close (pipefd[1]);
502+
execvp ("passt", argv);
503+
}
504+
else
505+
{
506+
/* We need to make sure passt has already started before continuing. A
507+
simple way to do it is with a blocking read on its stdout. */
508+
char buffer[1];
509+
close (pipefd[1]);
510+
ret = read (pipefd[0], buffer, 1);
511+
if (UNLIKELY (ret < 0))
512+
return ret;
513+
close (pipefd[0]);
514+
}
515+
516+
return 0;
517+
}
518+
443519
/* libkrun_create_kvm_device: explicitly adds kvm device. */
444520
static int
445521
libkrun_configure_container (void *cookie, enum handler_configure_phase phase,
@@ -501,6 +577,10 @@ libkrun_configure_container (void *cookie, enum handler_configure_phase phase,
501577
if (phase != HANDLER_CONFIGURE_AFTER_MOUNTS)
502578
return 0;
503579

580+
ret = libkrun_start_passt (cookie);
581+
if (UNLIKELY (ret < 0))
582+
return crun_make_error (err, errno, "start passt");
583+
504584
/* Do nothing if /dev/kvm is already present in spec */
505585
for (i = 0; i < def->linux->devices_len; i++)
506586
{
@@ -771,6 +851,42 @@ libkrun_modify_oci_configuration (void *cookie arg_unused, libcrun_context_t *co
771851
return 0;
772852
}
773853

854+
static int
855+
libkrun_close_fds (void *cookie, int preserve_fds)
856+
{
857+
struct krun_config *kconf = (struct krun_config *) cookie;
858+
int first_fd_to_close = preserve_fds + 3;
859+
int high_passt_fd;
860+
int low_passt_fd;
861+
int ret;
862+
int i;
863+
864+
if (kconf->passt_fds[PASST_FD_CHILD] > kconf->passt_fds[PASST_FD_PARENT])
865+
{
866+
high_passt_fd = kconf->passt_fds[PASST_FD_CHILD];
867+
low_passt_fd = kconf->passt_fds[PASST_FD_PARENT];
868+
}
869+
else
870+
{
871+
high_passt_fd = kconf->passt_fds[PASST_FD_PARENT];
872+
low_passt_fd = kconf->passt_fds[PASST_FD_CHILD];
873+
}
874+
875+
if (first_fd_to_close < high_passt_fd)
876+
{
877+
for (i = first_fd_to_close; i < high_passt_fd; i++)
878+
{
879+
if (i == low_passt_fd)
880+
continue;
881+
close (i);
882+
}
883+
884+
first_fd_to_close = high_passt_fd + 1;
885+
}
886+
887+
return mark_or_close_fds_ge_than (first_fd_to_close, true, NULL);
888+
}
889+
774890
struct custom_handler_s handler_libkrun = {
775891
.name = "krun",
776892
.alias = NULL,
@@ -780,6 +896,7 @@ struct custom_handler_s handler_libkrun = {
780896
.run_func = libkrun_exec,
781897
.configure_container = libkrun_configure_container,
782898
.modify_oci_configuration = libkrun_modify_oci_configuration,
899+
.close_fds = libkrun_close_fds,
783900
};
784901

785902
#endif

0 commit comments

Comments
 (0)