From d12719a7c759423f2fef57bf8a5e9845e8edcdeb Mon Sep 17 00:00:00 2001 From: Quanwei Zhou Date: Sun, 22 Dec 2024 16:36:46 +0800 Subject: [PATCH] vsock: parse cid from vsock Parse vsock cid and port from address("vsock://cid:port"). Fixes: containerd#266 Signed-off-by: Quanwei Zhou --- src/common.rs | 77 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/src/common.rs b/src/common.rs index 926d241a..302c5fd5 100644 --- a/src/common.rs +++ b/src/common.rs @@ -101,8 +101,40 @@ fn make_addr(_domain: Domain, sockaddr: &str) -> Result { UnixAddr::new(sockaddr).map_err(err_to_others_err!(e, "")) } -fn make_socket(addr: (&str, u32)) -> Result<(RawFd, Domain, Box)> { - let (sockaddr, _) = addr; +// addr: cid:port +// return (cid, port) +#[cfg(any(target_os = "linux", target_os = "android"))] +fn parse_vscok(addr: &str) -> Result<(u32, u32)> { + // vsock://cid:port + let sockaddr_port_v: Vec<&str> = addr.split(':').collect(); + if sockaddr_port_v.len() != 2 { + return Err(Error::Others(format!( + "sockaddr {addr} is not right for vsock" + ))); + } + + // for -1 need trace to libc::VMADDR_CID_ANY + let cid: u32 = if sockaddr_port_v[0].trim().eq("-1") { + libc::VMADDR_CID_ANY + } else { + sockaddr_port_v[0].parse().map_err(|e| { + Error::Others(format!( + "failed to parse cid from {:?} error: {:?}", + sockaddr_port_v[0], e + )) + })? + }; + + let port: u32 = sockaddr_port_v[1].parse().map_err(|e| { + Error::Others(format!( + "failed to parse port from {:?} error: {:?}", + sockaddr_port_v[1], e + )) + })?; + Ok((cid, port)) +} + +fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box)> { let (domain, sockaddrv) = parse_sockaddr(sockaddr)?; let get_sock_addr = |domain, sockaddr| -> Result<(RawFd, Box)> { @@ -121,15 +153,7 @@ fn make_socket(addr: (&str, u32)) -> Result<(RawFd, Domain, Box get_sock_addr(domain, sockaddrv)?, #[cfg(any(target_os = "linux", target_os = "android"))] Domain::Vsock => { - let sockaddr_port_v: Vec<&str> = sockaddrv.split(':').collect(); - if sockaddr_port_v.len() != 2 { - return Err(Error::Others(format!( - "sockaddr {sockaddr} is not right for vsock" - ))); - } - let port: u32 = sockaddr_port_v[1] - .parse() - .expect("the vsock port is not an number"); + let (cid, port) = parse_vscok(sockaddrv)?; let fd = socket( AddressFamily::Vsock, SockType::Stream, @@ -137,7 +161,6 @@ fn make_socket(addr: (&str, u32)) -> Result<(RawFd, Domain, Box Result<(RawFd, Domain, Box Result<(RawFd, Domain)> { - let (fd, domain, sockaddr) = make_socket((sockaddr, VMADDR_CID_ANY))?; + let (fd, domain, sockaddr) = make_socket(sockaddr)?; setsockopt(fd, sockopt::ReusePort, &true)?; bind(fd, sockaddr.as_ref()).map_err(err_to_others_err!(e, ""))?; @@ -167,7 +180,7 @@ pub(crate) fn do_bind(sockaddr: &str) -> Result<(RawFd, Domain)> { /// Creates a unix socket for client. pub(crate) unsafe fn client_connect(sockaddr: &str) -> Result { - let (fd, _, sockaddr) = make_socket((sockaddr, VMADDR_CID_HOST))?; + let (fd, _, sockaddr) = make_socket(sockaddr)?; connect(fd, sockaddr.as_ref())?; @@ -236,4 +249,20 @@ mod tests { } } } + #[cfg(any(target_os = "linux", target_os = "android"))] + #[test] + fn test_parse_vscok() { + for i in &[ + ("-1:1024", (libc::VMADDR_CID_ANY, 1024)), + ("0:1", (0, 1)), + ("1:2", (1, 2)), + ("4294967294:3", (4294967294, 3)), + // 4294967295 = 0xFFFFFFFF + ("4294967295:4", (libc::VMADDR_CID_ANY, 4)), + ] { + let (input, (cid, port)) = (i.0, i.1); + let r = parse_vscok(input); + assert_eq!(r.unwrap(), (cid, port), "parse {:?} failed", i); + } + } }