diff --git a/Cargo.lock b/Cargo.lock index 9c958fc..a0f81ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,9 +310,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] diff --git a/src/main.rs b/src/main.rs index db6b85f..7b0c8ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ -use std::u32; +use std::{io::Read, os::unix::net::UnixListener, path::Path, thread::sleep, u32}; use clap::Parser; -use vmm::VMM; +use vmm::{devices::Writer, VMM}; #[derive(Parser)] #[clap(version = "0.1", author = "Polytech Montpellier - DevOps")] @@ -37,6 +37,9 @@ struct VMMOpts { /// no-console #[clap(long)] no_console: bool, + + #[clap(long)] + socket: bool, } #[derive(Debug)] @@ -51,6 +54,32 @@ pub enum Error { fn main() -> Result<(), Error> { let opts: VMMOpts = VMMOpts::parse(); + let console = opts.console.unwrap(); + if opts.socket { + let path = Path::new(console.as_str()); + if std::fs::metadata(path).is_ok() { + std::fs::remove_file(path).unwrap(); + } + + println!("Socket path: {}", path.to_str().unwrap()); + + let unix_listener = UnixListener::bind(path).unwrap(); + + std::thread::spawn(move || { + // read from socket + let (mut stream, _) = unix_listener.accept().unwrap(); + let mut buffer = [0; 1024]; + loop { + let n = stream.read(&mut buffer).unwrap(); + if n == 0 { + break; + } + let s = String::from_utf8_lossy(&buffer[0..n]).to_string(); + print!("{}", s); + } + }); + } + // Create a new VMM let mut vmm = VMM::new().map_err(Error::VmmNew)?; @@ -63,21 +92,14 @@ fn main() -> Result<(), Error> { opts.cpus, opts.memory, &opts.kernel, - opts.console, + Some(console), opts.no_console, opts.initramfs, opts.net, + opts.socket, ) .map_err(Error::VmmConfigure)?; - // To use Writer with serial device : - // * Create mpsc channel : - // let (tx, rx) = std::sync::mpsc::channel(); - // * Create a new Writer - // let writer = Writer::new(tx); - // * Add the Writer when configuring the VMM - // * Use the rx receiver to read the data - // Run the VMM vmm.run(opts.no_console).map_err(Error::VmmRun)?; diff --git a/src/vmm/src/cpu/mod.rs b/src/vmm/src/cpu/mod.rs index c7e0467..b72e54c 100644 --- a/src/vmm/src/cpu/mod.rs +++ b/src/vmm/src/cpu/mod.rs @@ -227,9 +227,7 @@ impl Vcpu { // Call into KVM to launch (VMLAUNCH) or resume (VMRESUME) the virtual CPU. // This is a blocking function, it only returns for either an error or a // VM-Exit. In the latter case, we can inspect the exit reason. - println!("Before running vCPU {}...", self.index); let run = self.vcpu_fd.run(); - println!("After running vCPU {}...", self.index); match run { Ok(exit_reason) => match exit_reason { diff --git a/src/vmm/src/devices/mod.rs b/src/vmm/src/devices/mod.rs index 9ea0ca0..d6bb0e4 100644 --- a/src/vmm/src/devices/mod.rs +++ b/src/vmm/src/devices/mod.rs @@ -1,26 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 use std::io::{Result, Write}; -use std::sync::mpsc; +use std::os::unix::net::UnixStream; pub(crate) mod net; pub(crate) mod serial; pub struct Writer { - tx: mpsc::Sender, + unix_stream: UnixStream, } impl Write for Writer { fn write(&mut self, buf: &[u8]) -> Result { - if buf.len() > 0 && (buf[0] != 10 && buf[0] != 13) { - let s = String::from_utf8_lossy(buf).to_string(); - self.tx.send(s).map_err(|_| { - std::io::Error::new( - std::io::ErrorKind::Other, - "Error while sending data to channel", - ) - })?; - } + let s = String::from_utf8_lossy(buf).to_string(); + let _ = &self.unix_stream.write(s.as_bytes()).unwrap(); + Ok(buf.len()) } @@ -30,7 +24,7 @@ impl Write for Writer { } impl Writer { - pub fn new(tx: mpsc::Sender) -> Self { - Writer { tx } + pub fn new(unix_stream: UnixStream) -> Self { + Writer { unix_stream } } } diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index ffeed34..be11e00 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -12,6 +12,7 @@ use std::any::Any; use std::fs::File; use std::io::stdout; use std::os::unix::io::AsRawFd; +use std::os::unix::net::UnixStream; use std::os::unix::prelude::RawFd; use std::sync::{Arc, Mutex}; use std::thread; @@ -268,6 +269,7 @@ impl VMM { &mut self, console_path: Option, disable_console: bool, + is_socket: bool, ) -> Result<()> { if disable_console { return Ok(()); @@ -278,11 +280,23 @@ impl VMM { .map_err(Error::Cmdline)?; if let Some(console_path) = console_path { - // We create the file if it does not exist, else we open - let file = File::create(&console_path).map_err(Error::ConsoleError)?; + if is_socket { + println!("Connecting to socket: {}", console_path); + let unix_stream = UnixStream::connect(console_path).unwrap(); - let mut serial = self.serial.lock().unwrap(); - *serial = LumperSerial::new(Box::new(file)).map_err(Error::SerialCreation)?; + // create writer + + let writer = Writer::new(unix_stream); + let mut serial = self.serial.lock().unwrap(); + + *serial = LumperSerial::new(Box::new(writer)).map_err(Error::SerialCreation)?; + } else { + // We create the file if it does not exist, else we open + let file = File::create(&console_path).map_err(Error::ConsoleError)?; + + let mut serial = self.serial.lock().unwrap(); + *serial = LumperSerial::new(Box::new(file)).map_err(Error::SerialCreation)?; + } } Ok(()) @@ -429,9 +443,6 @@ impl VMM { } } - console: Option, - no_console: bool, - pub fn configure( &mut self, num_vcpus: u8, @@ -441,8 +452,9 @@ impl VMM { no_console: bool, initramfs_path: Option, if_name: Option, + is_socket: bool, ) -> Result<()> { - self.configure_console(console, no_console)?; + self.configure_console(console, no_console, is_socket)?; self.configure_memory(mem_size_mb)?; self.load_default_cmdline()?;