-
Notifications
You must be signed in to change notification settings - Fork 388
krun: switch to passt-based networking #1913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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> | ||
|
|
@@ -68,6 +69,9 @@ | |
| #define KRUN_FLAVOR_AWS_NITRO "aws-nitro" | ||
| #define KRUN_FLAVOR_SEV "sev" | ||
|
|
||
| #define PASST_FD_PARENT 0 | ||
| #define PASST_FD_CHILD 1 | ||
|
|
||
| struct krun_config | ||
| { | ||
| void *handle; | ||
|
|
@@ -80,6 +84,7 @@ struct krun_config | |
| int32_t ctx_id_awsnitro; | ||
| bool has_kvm; | ||
| bool has_awsnitro; | ||
| int passt_fds[2]; | ||
| }; | ||
|
|
||
| /* libkrun handler. */ | ||
|
|
@@ -366,6 +371,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname | |
| int32_t (*krun_set_console_output) (uint32_t ctx_id, const char *c_filepath); | ||
| int32_t (*krun_set_exec) (uint32_t ctx_id, const char *exec_path, | ||
| const char *const argv[], const char *const envp[]); | ||
| 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; | ||
|
|
@@ -498,6 +504,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); | ||
|
|
@@ -515,6 +528,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. */ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, you can skip this whole dance by not passing 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, | ||
|
|
@@ -576,6 +652,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++) | ||
| { | ||
|
|
@@ -846,6 +926,42 @@ libkrun_modify_oci_configuration (void *cookie arg_unused, libcrun_context_t *co | |
| return 0; | ||
| } | ||
|
|
||
| static int | ||
| libkrun_close_fds (void *cookie, libcrun_container_t *container, 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 (container, first_fd_to_close, true, NULL); | ||
| } | ||
|
|
||
| struct custom_handler_s handler_libkrun = { | ||
| .name = "krun", | ||
| .alias = NULL, | ||
|
|
@@ -855,6 +971,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 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the if statement condition evaluates to true, then no error is created.
I think using
crun_error_release (err);(in line 1656) requires that we know for sureerris equal toNULLor pointing to an allocated error. It's not clear at first sight whether that requirement is fulfilled.One idea is to replace line 897
with
and add
erras a function argument tolibkrun_close_fds()