Skip to content

Commit fabde21

Browse files
committed
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 e18a762 commit fabde21

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

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>
@@ -68,6 +69,9 @@
6869
#define KRUN_FLAVOR_AWS_NITRO "aws-nitro"
6970
#define KRUN_FLAVOR_SEV "sev"
7071

72+
#define PASST_FD_PARENT 0
73+
#define PASST_FD_CHILD 1
74+
7175
struct krun_config
7276
{
7377
void *handle;
@@ -80,6 +84,7 @@ struct krun_config
8084
int32_t ctx_id_awsnitro;
8185
bool has_kvm;
8286
bool has_awsnitro;
87+
int passt_fds[2];
8388
};
8489

8590
/* libkrun handler. */
@@ -366,6 +371,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
366371
int32_t (*krun_set_console_output) (uint32_t ctx_id, const char *c_filepath);
367372
int32_t (*krun_set_exec) (uint32_t ctx_id, const char *exec_path,
368373
const char *const argv[], const char *const envp[]);
374+
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);
369375
struct krun_config *kconf = (struct krun_config *) cookie;
370376
void *handle;
371377
uint32_t num_vcpus, ram_mib;
@@ -498,6 +504,13 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
498504
if (UNLIKELY (ret < 0))
499505
error (EXIT_FAILURE, -ret, "could not set krun vm configuration");
500506

507+
krun_add_net_unixstream = dlsym (handle, "krun_add_net_unixstream");
508+
509+
uint8_t mac[] = { 0x5a, 0x94, 0xef, 0xe4, 0x0c, 0xee };
510+
ret = krun_add_net_unixstream (ctx_id, NULL, kconf->passt_fds[PASST_FD_PARENT], &mac[0], COMPAT_NET_FEATURES, 0);
511+
if (UNLIKELY (ret < 0))
512+
error (EXIT_FAILURE, -ret, "could not set krun net configuration");
513+
501514
if (access ("/dev/dri", F_OK) == 0 && access ("/usr/libexec/virgl_render_server", F_OK) == 0)
502515
{
503516
ret = libkrun_enable_virtio_gpu (kconf);
@@ -515,6 +528,69 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname
515528
return ret;
516529
}
517530

531+
static int
532+
libkrun_start_passt (void *cookie)
533+
{
534+
struct krun_config *kconf = (struct krun_config *) cookie;
535+
pid_t pid;
536+
char fd_as_str[16];
537+
int pipefd[2];
538+
int ret;
539+
540+
socketpair (AF_UNIX, SOCK_STREAM, 0, kconf->passt_fds);
541+
snprintf (fd_as_str, sizeof (fd_as_str), "%d", kconf->passt_fds[PASST_FD_CHILD]);
542+
543+
char *const argv[] = {
544+
(char *) "passt",
545+
(char *) "-t",
546+
(char *) "all",
547+
(char *) "-u",
548+
(char *) "all",
549+
(char *) "-f",
550+
(char *) "--fd",
551+
fd_as_str,
552+
NULL
553+
};
554+
555+
ret = pipe (pipefd);
556+
if (UNLIKELY (ret == -1))
557+
return ret;
558+
559+
pid = fork ();
560+
if (pid < 0)
561+
{
562+
close (pipefd[0]);
563+
close (pipefd[1]);
564+
return pid;
565+
}
566+
else if (pid == 0)
567+
{
568+
close (pipefd[0]);
569+
570+
ret = dup2 (pipefd[1], STDERR_FILENO);
571+
if (UNLIKELY (ret == -1))
572+
{
573+
exit (EXIT_FAILURE);
574+
}
575+
576+
close (pipefd[1]);
577+
execvp ("passt", argv);
578+
}
579+
else
580+
{
581+
/* We need to make sure passt has already started before continuing. A
582+
simple way to do it is with a blocking read on its stdout. */
583+
char buffer[1];
584+
close (pipefd[1]);
585+
ret = read (pipefd[0], buffer, 1);
586+
if (UNLIKELY (ret < 0))
587+
return ret;
588+
close (pipefd[0]);
589+
}
590+
591+
return 0;
592+
}
593+
518594
/* libkrun_create_kvm_device: explicitly adds kvm device. */
519595
static int
520596
libkrun_configure_container (void *cookie, enum handler_configure_phase phase,
@@ -576,6 +652,10 @@ libkrun_configure_container (void *cookie, enum handler_configure_phase phase,
576652
if (phase != HANDLER_CONFIGURE_AFTER_MOUNTS)
577653
return 0;
578654

655+
ret = libkrun_start_passt (cookie);
656+
if (UNLIKELY (ret < 0))
657+
return crun_make_error (err, errno, "start passt");
658+
579659
/* Do nothing if /dev/kvm is already present in spec */
580660
for (i = 0; i < def->linux->devices_len; i++)
581661
{
@@ -846,6 +926,42 @@ libkrun_modify_oci_configuration (void *cookie arg_unused, libcrun_context_t *co
846926
return 0;
847927
}
848928

929+
static int
930+
libkrun_close_fds (void *cookie, libcrun_container_t *container, int preserve_fds)
931+
{
932+
struct krun_config *kconf = (struct krun_config *) cookie;
933+
int first_fd_to_close = preserve_fds + 3;
934+
int high_passt_fd;
935+
int low_passt_fd;
936+
int ret;
937+
int i;
938+
939+
if (kconf->passt_fds[PASST_FD_CHILD] > kconf->passt_fds[PASST_FD_PARENT])
940+
{
941+
high_passt_fd = kconf->passt_fds[PASST_FD_CHILD];
942+
low_passt_fd = kconf->passt_fds[PASST_FD_PARENT];
943+
}
944+
else
945+
{
946+
high_passt_fd = kconf->passt_fds[PASST_FD_PARENT];
947+
low_passt_fd = kconf->passt_fds[PASST_FD_CHILD];
948+
}
949+
950+
if (first_fd_to_close < high_passt_fd)
951+
{
952+
for (i = first_fd_to_close; i < high_passt_fd; i++)
953+
{
954+
if (i == low_passt_fd)
955+
continue;
956+
close (i);
957+
}
958+
959+
first_fd_to_close = high_passt_fd + 1;
960+
}
961+
962+
return mark_or_close_fds_ge_than (container, first_fd_to_close, true, NULL);
963+
}
964+
849965
struct custom_handler_s handler_libkrun = {
850966
.name = "krun",
851967
.alias = NULL,
@@ -855,6 +971,7 @@ struct custom_handler_s handler_libkrun = {
855971
.run_func = libkrun_exec,
856972
.configure_container = libkrun_configure_container,
857973
.modify_oci_configuration = libkrun_modify_oci_configuration,
974+
.close_fds = libkrun_close_fds,
858975
};
859976

860977
#endif

0 commit comments

Comments
 (0)