libchromeos-rs: Implement VsockCid (from Sirenia).
This provides a idomatic rust implementation of CIDs for Vsock and
refactors the usage of CIDs in related code.
BUG=b:162502718,b:144915425
TEST=cargo test for libchromeos, 9s, chunnel, andsirenia
Change-Id: I2e2eab2fd5027bded8233e03131391d0069dd576
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2338984
Tested-by: Allen Webb <allenwebb@google.com>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
diff --git a/libchromeos-rs/src/vsock.rs b/libchromeos-rs/src/vsock.rs
index b4fa589..34b9943 100644
--- a/libchromeos-rs/src/vsock.rs
+++ b/libchromeos-rs/src/vsock.rs
@@ -6,20 +6,24 @@
use std::fmt;
use std::io;
use std::mem::{self, size_of};
+use std::num::ParseIntError;
use std::os::raw::{c_int, c_uchar, c_uint, c_ushort};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::result;
use std::str::FromStr;
-use libc::{self, c_void, sa_family_t, size_t, sockaddr, socklen_t, F_GETFL, F_SETFL, O_NONBLOCK};
+use libc::{
+ self, c_void, sa_family_t, size_t, sockaddr, socklen_t, F_GETFL, F_SETFL, O_NONBLOCK,
+ VMADDR_CID_ANY, VMADDR_CID_HOST, VMADDR_CID_HYPERVISOR,
+};
// The domain for vsock sockets.
const AF_VSOCK: sa_family_t = 40;
-// Vsock equivalent of INADDR_ANY. Indicates the context id of the current endpoint.
-pub const VMADDR_CID_ANY: c_uint = c_uint::max_value();
+// Vsock loopback address.
+const VMADDR_CID_LOCAL: c_uint = 1;
-// Vsock equivalent of binding on port 0. Binds to a random port.
+/// Vsock equivalent of binding on port 0. Binds to a random port.
pub const VMADDR_PORT_ANY: c_uint = c_uint::max_value();
// The number of bytes of padding to be added to the sockaddr_vm struct. Taken directly
@@ -47,10 +51,70 @@
}
}
+/// The vsock equivalent of an IP address.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum VsockCid {
+ /// Vsock equivalent of INADDR_ANY. Indicates the context id of the current endpoint.
+ Any,
+ /// An address that refers to the bare-metal machine that serves as the hypervisor.
+ Hypervisor,
+ /// The loopback address.
+ Local,
+ /// The parent machine. It may not be the hypervisor for nested VMs.
+ Host,
+ /// An assigned CID that serves as the address for VSOCK.
+ Cid(c_uint),
+}
+
+impl fmt::Display for VsockCid {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match &self {
+ VsockCid::Any => write!(fmt, "Any"),
+ VsockCid::Hypervisor => write!(fmt, "Hypervisor"),
+ VsockCid::Local => write!(fmt, "Local"),
+ VsockCid::Host => write!(fmt, "Host"),
+ VsockCid::Cid(c) => write!(fmt, "'{}'", c),
+ }
+ }
+}
+
+impl From<c_uint> for VsockCid {
+ fn from(c: c_uint) -> Self {
+ match c {
+ VMADDR_CID_ANY => VsockCid::Any,
+ VMADDR_CID_HYPERVISOR => VsockCid::Hypervisor,
+ VMADDR_CID_LOCAL => VsockCid::Local,
+ VMADDR_CID_HOST => VsockCid::Host,
+ _ => VsockCid::Cid(c),
+ }
+ }
+}
+
+impl FromStr for VsockCid {
+ type Err = ParseIntError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let c: c_uint = s.parse()?;
+ Ok(c.into())
+ }
+}
+
+impl Into<c_uint> for VsockCid {
+ fn into(self) -> c_uint {
+ match self {
+ VsockCid::Any => VMADDR_CID_ANY,
+ VsockCid::Hypervisor => VMADDR_CID_HYPERVISOR,
+ VsockCid::Local => VMADDR_CID_LOCAL,
+ VsockCid::Host => VMADDR_CID_HOST,
+ VsockCid::Cid(c) => c,
+ }
+ }
+}
+
/// An address associated with a virtual socket.
#[derive(Debug, Copy, Clone)]
pub struct SocketAddr {
- pub cid: c_uint,
+ pub cid: VsockCid,
pub port: c_uint,
}
@@ -143,7 +207,7 @@
let mut svm: sockaddr_vm = Default::default();
svm.svm_family = AF_VSOCK;
- svm.svm_cid = sockaddr.cid;
+ svm.svm_cid = sockaddr.cid.into();
svm.svm_port = sockaddr.port;
// Safe because this just connects a vsock socket, and the return value is checked.
@@ -253,7 +317,7 @@
impl VsockListener {
/// Creates a new `VsockListener` bound to the specified port on the current virtual socket
/// endpoint.
- pub fn bind(port: c_uint) -> io::Result<VsockListener> {
+ pub fn bind(cid: VsockCid, port: c_uint) -> io::Result<VsockListener> {
// The compiler should optimize this out since these are both compile-time constants.
assert_eq!(size_of::<sockaddr_vm>(), size_of::<sockaddr>());
@@ -271,7 +335,7 @@
let mut svm: sockaddr_vm = Default::default();
svm.svm_family = AF_VSOCK;
- svm.svm_cid = VMADDR_CID_ANY;
+ svm.svm_cid = cid.into();
svm.svm_port = port;
// Safe because this doesn't modify any memory and we check the return value.
@@ -357,7 +421,7 @@
Ok((
VsockStream { fd },
SocketAddr {
- cid: svm.svm_cid,
+ cid: svm.svm_cid.into(),
port: svm.svm_port,
},
))
diff --git a/sirenia/src/dugong.rs b/sirenia/src/dugong.rs
index b7bdfd7..5a15c35 100644
--- a/sirenia/src/dugong.rs
+++ b/sirenia/src/dugong.rs
@@ -8,8 +8,8 @@
use std::io::{copy, stdin, stdout};
use std::thread::spawn;
+use libchromeos::vsock::VsockCid;
use sirenia::cli::{initialize_common_arguments, TransportType};
-use sirenia::to_sys_util::VsockCid;
use sirenia::transport::{ClientTransport, IPClientTransport, Transport, VsockClientTransport};
fn main() {
diff --git a/sirenia/src/to_sys_util/mod.rs b/sirenia/src/to_sys_util/mod.rs
index d52d3d2..b28c443 100644
--- a/sirenia/src/to_sys_util/mod.rs
+++ b/sirenia/src/to_sys_util/mod.rs
@@ -12,12 +12,7 @@
use std::mem::MaybeUninit;
use std::ptr::null_mut;
-use libc::{
- self, c_int, sigfillset, sigprocmask, sigset_t, wait, ECHILD, SIG_BLOCK, SIG_UNBLOCK,
- VMADDR_CID_ANY, VMADDR_CID_HOST, VMADDR_CID_HYPERVISOR,
-};
-
-const VMADDR_CID_LOCAL: u32 = 1;
+use libc::{self, c_int, sigfillset, sigprocmask, sigset_t, wait, ECHILD, SIG_BLOCK, SIG_UNBLOCK};
pub fn errno() -> c_int {
io::Error::last_os_error().raw_os_error().unwrap()
@@ -72,36 +67,3 @@
Ok(ret)
}
}
-
-#[derive(Debug, Copy, Clone)]
-pub enum VsockCid {
- Any,
- Hypervisor,
- Local,
- Host,
- Cid(u32),
-}
-
-impl From<u32> for VsockCid {
- fn from(c: u32) -> Self {
- match c {
- VMADDR_CID_ANY => VsockCid::Any,
- VMADDR_CID_HYPERVISOR => VsockCid::Hypervisor,
- VMADDR_CID_LOCAL => VsockCid::Local,
- VMADDR_CID_HOST => VsockCid::Host,
- _ => VsockCid::Cid(c),
- }
- }
-}
-
-impl Into<u32> for VsockCid {
- fn into(self) -> u32 {
- match self {
- VsockCid::Any => VMADDR_CID_ANY,
- VsockCid::Hypervisor => VMADDR_CID_HYPERVISOR,
- VsockCid::Local => VMADDR_CID_LOCAL,
- VsockCid::Host => VMADDR_CID_HOST,
- VsockCid::Cid(c) => c,
- }
- }
-}
diff --git a/sirenia/src/transport/mod.rs b/sirenia/src/transport/mod.rs
index a9321b2..130c277 100644
--- a/sirenia/src/transport/mod.rs
+++ b/sirenia/src/transport/mod.rs
@@ -16,11 +16,9 @@
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use core::mem::replace;
-use libchromeos::vsock::{self, VsockListener, VsockStream};
+use libchromeos::vsock::{self, VsockCid, VsockListener, VsockStream};
use sys_util::{handle_eintr, pipe};
-use super::to_sys_util::VsockCid;
-
const DEFAULT_PORT: u32 = 5552;
#[derive(Debug)]
@@ -165,7 +163,7 @@
impl VsockServerTransport {
pub fn new() -> Result<Self> {
- let listener = VsockListener::bind(DEFAULT_PORT).map_err(Error::Bind)?;
+ let listener = VsockListener::bind(VsockCid::Any, DEFAULT_PORT).map_err(Error::Bind)?;
Ok(VsockServerTransport(listener))
}
}
@@ -189,7 +187,7 @@
impl ClientTransport for VsockClientTransport {
fn connect(&mut self) -> Result<Transport> {
let addr = vsock::SocketAddr {
- cid: self.0.into(),
+ cid: self.0,
port: DEFAULT_PORT,
};
let stream = handle_eintr!(VsockStream::connect(&addr)).map_err(Error::Connect)?;
diff --git a/vm_tools/9s/src/main.rs b/vm_tools/9s/src/main.rs
index 458fc2a..1210eb2 100644
--- a/vm_tools/9s/src/main.rs
+++ b/vm_tools/9s/src/main.rs
@@ -219,9 +219,9 @@
fn run_vsock_server(
server_params: Arc<ServerParams>,
port: c_uint,
- accept_cid: c_uint,
+ accept_cid: VsockCid,
) -> io::Result<()> {
- let listener = VsockListener::bind(port)?;
+ let listener = VsockListener::bind(VsockCid::Any, port)?;
loop {
let (stream, peer) = listener.accept()?;
@@ -409,7 +409,7 @@
{
ListenAddress::Vsock(port) => {
let accept_cid = if let Some(cid) = matches.opt_str("accept_cid") {
- cid.parse::<c_uint>().map_err(Error::Cid)
+ cid.parse::<VsockCid>().map_err(Error::Cid)
} else {
Err(Error::MissingAcceptCid)
}?;
diff --git a/vm_tools/chunnel/src/bin/chunneld.rs b/vm_tools/chunnel/src/bin/chunneld.rs
index 0084a01..a6b2e4f 100644
--- a/vm_tools/chunnel/src/bin/chunneld.rs
+++ b/vm_tools/chunnel/src/bin/chunneld.rs
@@ -21,7 +21,7 @@
self, tree, Connection as DBusConnection, Error as DBusError, Message as DBusMessage, OwnedFd,
};
use libchromeos::syslog;
-use libchromeos::vsock::{VsockListener, VMADDR_PORT_ANY};
+use libchromeos::vsock::{VsockCid, VsockListener, VMADDR_PORT_ANY};
use log::{error, warn};
use protobuf::{self, Message as ProtoMessage, ProtobufError};
use sys_util::{self, block_signal, pipe, EventFd, PollContext, PollToken};
@@ -71,7 +71,7 @@
DBusRegisterTree(DBusError),
EventFdClone(sys_util::Error),
EventFdNew(sys_util::Error),
- IncorrectCid(u32),
+ IncorrectCid(VsockCid),
LifelinePipe(sys_util::Error),
NoListenerForPort(u16),
NoSessionForTag(SessionTag),
@@ -141,7 +141,7 @@
pub vm_name: String,
pub container_name: String,
pub owner_id: String,
- pub vsock_cid: u32,
+ pub vsock_cid: VsockCid,
}
/// A tag that uniquely identifies a particular forwarding session. This has arbitrarily been
@@ -464,7 +464,8 @@
) -> Result<ForwarderSession> {
let (tcp_stream, _) = listener.accept().map_err(Error::TcpAccept)?;
// Bind a vsock port, tell the guest to connect, and accept the connection.
- let mut vsock_listener = VsockListener::bind(VMADDR_PORT_ANY).map_err(Error::BindVsock)?;
+ let mut vsock_listener =
+ VsockListener::bind(VsockCid::Any, VMADDR_PORT_ANY).map_err(Error::BindVsock)?;
vsock_listener
.set_nonblocking(true)
.map_err(Error::SetVsockNonblocking)?;
@@ -531,7 +532,7 @@
vm_name: forward_target.take_vm_name(),
owner_id: forward_target.take_owner_id(),
container_name: forward_target.take_container_name(),
- vsock_cid: forward_target.vsock_cid,
+ vsock_cid: forward_target.vsock_cid.into(),
});
}