Skip to content

Commit 51439ac

Browse files
WhatAmISupposedToPutHereslp
authored andcommitted
Use vsock for communication with server.
This will allow implementing other network topologies. Signed-off-by: Sasha Finkelstein <[email protected]>
1 parent 40230ef commit 51439ac

11 files changed

Lines changed: 97 additions & 189 deletions

File tree

crates/muvm/src/bin/muvm.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use std::collections::HashMap;
2-
use std::env;
32
use std::ffi::{c_char, CString};
43
use std::io::Write;
54
use std::os::fd::{IntoRawFd, OwnedFd};
65
use std::path::Path;
76
use std::process::ExitCode;
7+
use std::{env, fs};
88

99
use anyhow::{anyhow, Context, Result};
1010
use krun_sys::{
11-
krun_add_disk, krun_add_virtiofs2, krun_add_vsock_port, krun_create_ctx, krun_set_env,
12-
krun_set_gpu_options2, krun_set_log_level, krun_set_passt_fd, krun_set_root,
11+
krun_add_disk, krun_add_virtiofs2, krun_add_vsock_port, krun_add_vsock_port2, krun_create_ctx,
12+
krun_set_env, krun_set_gpu_options2, krun_set_log_level, krun_set_passt_fd, krun_set_root,
1313
krun_set_vm_config, krun_set_workdir, krun_start_enter, VIRGLRENDERER_DRM,
1414
VIRGLRENDERER_THREAD_SYNC, VIRGLRENDERER_USE_ASYNC_FENCE_CB, VIRGLRENDERER_USE_EGL,
1515
};
@@ -22,7 +22,9 @@ use muvm::launch::{launch_or_lock, LaunchResult, DYNAMIC_PORT_RANGE};
2222
use muvm::monitor::spawn_monitor;
2323
use muvm::net::{connect_to_passt, start_passt};
2424
use muvm::types::MiB;
25-
use muvm::utils::launch::{GuestConfiguration, Launch};
25+
use muvm::utils::launch::{
26+
GuestConfiguration, Launch, HIDPIPE_SOCKET, MUVM_GUEST_SOCKET, PULSE_SOCKET,
27+
};
2628
use nix::sys::sysinfo::sysinfo;
2729
use nix::unistd::User;
2830
use rustix::io::Errno;
@@ -72,8 +74,7 @@ fn main() -> Result<ExitCode> {
7274

7375
let options = options().fallback_to_usage().run();
7476

75-
let (cookie, _lock_file, command, command_args, env) = match launch_or_lock(
76-
options.server_port,
77+
let (_lock_file, command, command_args, env) = match launch_or_lock(
7778
options.command,
7879
options.command_args,
7980
options.env,
@@ -87,12 +88,11 @@ fn main() -> Result<ExitCode> {
8788
return Ok(code);
8889
},
8990
LaunchResult::LockAcquired {
90-
cookie,
9191
lock_file,
9292
command,
9393
command_args,
9494
env,
95-
} => (cookie, lock_file, command, command_args, env),
95+
} => (lock_file, command, command_args, env),
9696
};
9797

9898
let mut env = prepare_env_vars(env).context("Failed to prepare environment variables")?;
@@ -264,9 +264,7 @@ fn main() -> Result<ExitCode> {
264264
.context("Failed to connect to `passt`")?
265265
.into()
266266
} else {
267-
start_passt(options.server_port)
268-
.context("Failed to start `passt`")?
269-
.into()
267+
start_passt().context("Failed to start `passt`")?.into()
270268
};
271269
// SAFETY: `passt_fd` is an `OwnedFd` and consumed to prevent closing on drop.
272270
// See https://doc.rust-lang.org/std/io/index.html#io-safety
@@ -287,7 +285,7 @@ fn main() -> Result<ExitCode> {
287285
)
288286
.context("Failed to process `pulse/native` path as it contains NUL character")?;
289287
// SAFETY: `pulse_path` is a pointer to a `CString` with long enough lifetime.
290-
let err = unsafe { krun_add_vsock_port(ctx_id, 3333, pulse_path.as_ptr()) };
288+
let err = unsafe { krun_add_vsock_port(ctx_id, PULSE_SOCKET, pulse_path.as_ptr()) };
291289
if err < 0 {
292290
let err = Errno::from_raw_os_error(-err);
293291
return Err(err).context("Failed to configure vsock for pulse socket");
@@ -304,7 +302,7 @@ fn main() -> Result<ExitCode> {
304302
.context("Failed to process `hidpipe` path as it contains NUL character")?;
305303

306304
// SAFETY: `hidpipe_path` is a pointer to a `CString` with long enough lifetime.
307-
let err = unsafe { krun_add_vsock_port(ctx_id, 3334, hidpipe_path.as_ptr()) };
305+
let err = unsafe { krun_add_vsock_port(ctx_id, HIDPIPE_SOCKET, hidpipe_path.as_ptr()) };
308306
if err < 0 {
309307
let err = Errno::from_raw_os_error(-err);
310308
return Err(err).context("Failed to configure vsock for hidpipe socket");
@@ -328,6 +326,22 @@ fn main() -> Result<ExitCode> {
328326
return Err(err).context("Failed to configure vsock for dynamic socket");
329327
}
330328
}
329+
330+
let server_path = Path::new(&run_path).join("krun/server");
331+
_ = fs::remove_file(&server_path);
332+
let server_path = CString::new(
333+
server_path
334+
.to_str()
335+
.expect("server_path should not contain invalid UTF-8"),
336+
)
337+
.context("Failed to process `muvm-guest` path as it contains NUL characters")?;
338+
// SAFETY: `server_path` is a pointer to a `CString` with long enough lifetime.
339+
let err =
340+
unsafe { krun_add_vsock_port2(ctx_id, MUVM_GUEST_SOCKET, server_path.as_ptr(), true) };
341+
if err < 0 {
342+
let err = Errno::from_raw_os_error(-err);
343+
return Err(err).context("Failed to configure vsock for guest server socket");
344+
}
331345
}
332346

333347
let username = env::var("USER").context("Failed to get username from environment")?;
@@ -366,20 +380,17 @@ fn main() -> Result<ExitCode> {
366380
let display = env::var("DISPLAY").ok();
367381
let guest_config = GuestConfiguration {
368382
command: Launch {
369-
cookie,
370383
command,
371384
command_args,
372385
env: HashMap::new(),
373386
vsock_port: 0,
374387
tty: false,
375388
privileged: false,
376389
},
377-
server_port: options.server_port,
378390
username,
379391
uid: getuid().as_raw(),
380392
gid: getgid().as_raw(),
381393
host_display: display,
382-
server_cookie: cookie,
383394
merged_rootfs: options.merged_rootfs,
384395
};
385396
let mut muvm_config_file = NamedTempFile::new()
@@ -449,7 +460,7 @@ fn main() -> Result<ExitCode> {
449460
}
450461
}
451462

452-
spawn_monitor(options.server_port, cookie);
463+
spawn_monitor();
453464

454465
{
455466
// Start and enter the microVM. Unless there is some error while creating the

crates/muvm/src/cli_options.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub struct Options {
1313
pub mem: Option<MiB>,
1414
pub vram: Option<MiB>,
1515
pub passt_socket: Option<PathBuf>,
16-
pub server_port: u32,
1716
pub fex_images: Vec<String>,
1817
pub merged_rootfs: bool,
1918
pub interactive: bool,
@@ -98,12 +97,6 @@ pub fn options() -> OptionParser<Options> {
9897
.help("Instead of starting passt, connect to passt socket at PATH")
9998
.argument("PATH")
10099
.optional();
101-
let server_port = long("server-port")
102-
.short('p')
103-
.help("Set the port to be used in server mode")
104-
.argument("SERVER_PORT")
105-
.fallback(3334)
106-
.display_fallback();
107100
let interactive = long("interactive")
108101
.short('i')
109102
.help("Attach to the command's stdin/out after starting it")
@@ -131,7 +124,6 @@ pub fn options() -> OptionParser<Options> {
131124
mem,
132125
vram,
133126
passt_socket,
134-
server_port,
135127
fex_images,
136128
merged_rootfs,
137129
interactive,

crates/muvm/src/guest/bin/muvm-guest.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use muvm::guest::socket::setup_socket_proxy;
1515
use muvm::guest::user::setup_user;
1616
use muvm::guest::x11::setup_x11_forwarding;
1717
use muvm::guest::x11bridge::start_x11bridge;
18-
use muvm::utils::launch::GuestConfiguration;
18+
use muvm::utils::launch::{GuestConfiguration, PULSE_SOCKET};
1919
use nix::unistd::{Gid, Uid};
2020
use rustix::process::{getrlimit, setrlimit, Resource};
2121

@@ -94,7 +94,7 @@ fn main() -> Result<()> {
9494
std::fs::create_dir(&pulse_path)
9595
.context("Failed to create `pulse` directory in `XDG_RUNTIME_DIR`")?;
9696
let pulse_path = pulse_path.join("native");
97-
setup_socket_proxy(pulse_path, 3333)?;
97+
setup_socket_proxy(pulse_path, PULSE_SOCKET)?;
9898

9999
if let Some(host_display) = options.host_display {
100100
setup_x11_forwarding(run_path, &host_display)?;
@@ -108,13 +108,5 @@ fn main() -> Result<()> {
108108
});
109109

110110
let rt = tokio::runtime::Runtime::new().unwrap();
111-
rt.block_on(async {
112-
server_main(
113-
options.server_port,
114-
options.server_cookie,
115-
options.command.command,
116-
options.command.command_args,
117-
)
118-
.await
119-
})
111+
rt.block_on(async { server_main(options.command.command, options.command.command_args).await })
120112
}

crates/muvm/src/guest/hidpipe.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::hidpipe_common::{
33
empty_input_event, struct_to_socket, AddDevice, ClientHello, FFErase, FFUpload, InputEvent,
44
MessageType, RemoveDevice, ServerHello,
55
};
6+
use crate::utils::launch::HIDPIPE_SOCKET;
67
use input_linux::bitmask::BitmaskTrait;
78
use input_linux::{
89
AbsoluteAxis, AbsoluteInfo, Bitmask, EventKind, ForceFeedbackKind, InputProperty, Key, LedKind,
@@ -161,7 +162,7 @@ pub fn start_hidpipe(user_id: u32) {
161162
None,
162163
)
163164
.unwrap();
164-
connect(sock_fd.as_raw_fd(), &VsockAddr::new(2, 3334)).unwrap();
165+
connect(sock_fd.as_raw_fd(), &VsockAddr::new(2, HIDPIPE_SOCKET)).unwrap();
165166
let mut sock = UnixStream::from(sock_fd);
166167
let c_hello = ClientHello { version: 0 };
167168
let c_hello_data = unsafe {

crates/muvm/src/guest/server.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,41 @@
11
use crate::guest::server_worker::{State, Worker};
2+
use crate::utils::launch::MUVM_GUEST_SOCKET;
23
use anyhow::Result;
34
use log::error;
5+
use nix::libc::VMADDR_CID_ANY;
6+
use nix::sys::socket::{
7+
bind, listen, socket, AddressFamily, Backlog, SockFlag, SockType, VsockAddr,
8+
};
9+
use std::os::fd::AsRawFd;
10+
use std::os::unix::net::UnixListener as StdUnixListener;
411
use std::os::unix::process::ExitStatusExt as _;
512
use std::path::PathBuf;
6-
use tokio::net::TcpListener;
13+
use tokio::net::UnixListener;
714
use tokio::process::Command;
815
use tokio::sync::watch;
916
use tokio_stream::wrappers::WatchStream;
1017
use tokio_stream::StreamExt as _;
11-
use uuid::Uuid;
1218

13-
pub async fn server_main(
14-
server_port: u32,
15-
cookie: Uuid,
16-
command: PathBuf,
17-
command_args: Vec<String>,
18-
) -> Result<()> {
19-
let listener = TcpListener::bind(format!("0.0.0.0:{server_port}")).await?;
19+
pub async fn server_main(command: PathBuf, command_args: Vec<String>) -> Result<()> {
20+
let sock_fd = socket(
21+
AddressFamily::Vsock,
22+
SockType::Stream,
23+
SockFlag::empty(),
24+
None,
25+
)
26+
.unwrap();
27+
bind(
28+
sock_fd.as_raw_fd(),
29+
&VsockAddr::new(VMADDR_CID_ANY, MUVM_GUEST_SOCKET),
30+
)?;
31+
listen(&sock_fd, Backlog::MAXCONN)?;
32+
let std_listener = StdUnixListener::from(sock_fd);
33+
std_listener.set_nonblocking(true)?;
34+
let listener = UnixListener::from_std(std_listener)?;
2035
let (state_tx, state_rx) = watch::channel(State::new());
2136

2237
let mut worker_handle = tokio::spawn(async move {
23-
let mut worker = Worker::new(cookie, listener, state_tx);
38+
let mut worker = Worker::new(listener, state_tx);
2439
worker.run().await;
2540
});
2641
let command_status = Command::new(&command).args(command_args).status();

crates/muvm/src/guest/server_worker.rs

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::io::{Read, Write};
55
use std::os::fd::{AsRawFd, OwnedFd};
66
use std::os::unix::ffi::OsStringExt;
77
use std::os::unix::fs::OpenOptionsExt;
8-
use std::os::unix::net::UnixStream;
8+
use std::os::unix::net::UnixStream as StdUnixStream;
99
use std::os::unix::process::ExitStatusExt as _;
1010
use std::path::{Path, PathBuf};
1111
use std::process::{ExitStatus, Stdio};
@@ -21,13 +21,12 @@ use rustix::process::ioctl_tiocsctty;
2121
use rustix::pty::{ptsname, unlockpt};
2222
use rustix::termios::{tcsetwinsize, Winsize};
2323
use tokio::io::{AsyncBufReadExt as _, AsyncWriteExt as _, BufStream};
24-
use tokio::net::{TcpListener, TcpStream};
24+
use tokio::net::{UnixListener, UnixStream};
2525
use tokio::process::{Child, Command};
2626
use tokio::sync::watch;
2727
use tokio::task::{JoinError, JoinSet};
28-
use tokio_stream::wrappers::TcpListenerStream;
28+
use tokio_stream::wrappers::UnixListenerStream;
2929
use tokio_stream::StreamExt as _;
30-
use uuid::Uuid;
3130

3231
use crate::guest::user;
3332
use crate::utils::launch::Launch;
@@ -45,8 +44,7 @@ pub enum ConnRequest {
4544

4645
#[derive(Debug)]
4746
pub struct Worker {
48-
cookie: Uuid,
49-
listener_stream: TcpListenerStream,
47+
listener_stream: UnixListenerStream,
5048
state_tx: watch::Sender<State>,
5149
child_set: JoinSet<(PathBuf, ChildResult, Option<OwnedFd>)>,
5250
}
@@ -60,10 +58,9 @@ pub struct State {
6058
type ChildResult = Result<ExitStatus, io::Error>;
6159

6260
impl Worker {
63-
pub fn new(cookie: Uuid, listener: TcpListener, state_tx: watch::Sender<State>) -> Self {
61+
pub fn new(listener: UnixListener, state_tx: watch::Sender<State>) -> Self {
6462
Worker {
65-
cookie,
66-
listener_stream: TcpListenerStream::new(listener),
63+
listener_stream: UnixListenerStream::new(listener),
6764
state_tx,
6865
child_set: JoinSet::new(),
6966
}
@@ -84,7 +81,7 @@ impl Worker {
8481
};
8582
let stream = BufStream::new(stream);
8683

87-
match handle_connection(self.cookie, stream).await {
84+
match handle_connection(stream).await {
8885
Ok(request) => match request {
8986
ConnRequest::DropCaches => {},
9087
ConnRequest::ExecuteCommand {command, mut child, stop_pipe } => {
@@ -180,7 +177,7 @@ impl Default for State {
180177
}
181178
}
182179

183-
async fn read_request(stream: &mut BufStream<TcpStream>) -> Result<Launch> {
180+
async fn read_request(stream: &mut BufStream<UnixStream>) -> Result<Launch> {
184181
let mut buf = String::new();
185182
loop {
186183
if stream.read_line(&mut buf).await? == 0 {
@@ -193,14 +190,10 @@ async fn read_request(stream: &mut BufStream<TcpStream>) -> Result<Launch> {
193190
}
194191
}
195192

196-
async fn handle_connection(
197-
server_cookie: Uuid,
198-
mut stream: BufStream<TcpStream>,
199-
) -> Result<ConnRequest> {
193+
async fn handle_connection(mut stream: BufStream<UnixStream>) -> Result<ConnRequest> {
200194
let mut envs: HashMap<String, String> = env::vars().collect();
201195

202196
let Launch {
203-
cookie,
204197
command,
205198
command_args,
206199
env,
@@ -209,13 +202,6 @@ async fn handle_connection(
209202
privileged,
210203
} = read_request(&mut stream).await?;
211204
debug!(command:?, command_args:?, env:?; "received launch request");
212-
if cookie != server_cookie {
213-
debug!("invalid cookie in launch request");
214-
let msg = "Invalid cookie";
215-
stream.write_all(msg.as_bytes()).await.ok();
216-
stream.flush().await.ok();
217-
return Err(anyhow!(msg));
218-
}
219205

220206
if command == Path::new("/muvmdropcaches") {
221207
// SAFETY: everything below should be async signal safe
@@ -370,7 +356,7 @@ fn run_io_guest(
370356
vsock_fd.as_raw_fd(),
371357
&VsockAddr::new(nix::libc::VMADDR_CID_HOST, vsock_port),
372358
)?;
373-
let mut vsock = UnixStream::from(vsock_fd);
359+
let mut vsock = StdUnixStream::from(vsock_fd);
374360
let epoll = Epoll::new(EpollCreateFlags::empty())?;
375361
epoll.add(&stdout, EpollEvent::new(EpollFlags::EPOLLIN, 1))?;
376362
if stderr.is_some() {

crates/muvm/src/guest/socket.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use anyhow::{Context, Result};
88
use crate::utils::env::find_in_path;
99
use crate::utils::stdio::make_stdout_stderr;
1010

11-
pub fn setup_socket_proxy<P>(socket_path: P, port: u16) -> Result<()>
11+
pub fn setup_socket_proxy<P>(socket_path: P, port: u32) -> Result<()>
1212
where
1313
P: AsRef<Path>,
1414
{

0 commit comments

Comments
 (0)