Browse Source

Set up the vsock server on host with Rust

Alice Wang 1 year ago
parent
commit
d6dd6445f2

+ 9 - 2
examples/aarch64/Makefile

@@ -4,7 +4,8 @@ kernel := target/$(target)/$(mode)/aarch64
 kernel_qemu_bin := target/$(target)/$(mode)/aarch64_qemu.bin
 kernel_crosvm_bin := target/$(target)/$(mode)/aarch64_crosvm.bin
 img := target/$(target)/$(mode)/img
-vsock_server_bin := target/$(target)/$(mode)/vsock_server.bin
+vsock_server_path := ../vsock_server
+vsock_server_bin := $(vsock_server_path)/target/x86_64-unknown-linux-gnu/$(mode)/vsock_server
 
 sysroot := $(shell rustc --print sysroot)
 objdump := $(shell find $(sysroot) -name llvm-objdump) --arch-name=aarch64
@@ -15,6 +16,11 @@ ifeq ($(mode), release)
 	BUILD_ARGS += --release
 endif
 
+VSOCK_BUILD_ARGS = --target=x86_64-unknown-linux-gnu
+ifeq ($(mode), release)
+	VSOCK_BUILD_ARGS += --release
+endif
+
 .PHONY: kernel clean qemu run env
 
 env:
@@ -36,7 +42,7 @@ $(kernel_crosvm_bin): kernel_crosvm
 	aarch64-linux-gnu-objcopy -O binary $(kernel) $(kernel_crosvm_bin)
 
 $(vsock_server_bin):
-	gcc vsock_server.cc -o $(vsock_server_bin)
+	cargo build --manifest-path=$(vsock_server_path)/Cargo.toml $(VSOCK_BUILD_ARGS)
 
 asm: kernel
 	$(objdump) -d $(kernel) | less
@@ -69,6 +75,7 @@ qemu: $(kernel_qemu_bin) $(img) $(vsock_server_bin)
 		-device virtconsole,chardev=char0
 
 qemu-pci: $(kernel_qemu_bin) $(img)
+	$(vsock_server_bin) &
 	qemu-system-aarch64 \
 		$(QEMU_ARGS) \
 		-machine virt \

+ 2 - 0
examples/aarch64/src/main.rs

@@ -187,6 +187,8 @@ fn virtio_socket<T: Transport>(transport: T) {
     info!("Connecting to host on port {port}...");
     if let Err(e) = socket.connect(host_cid, port, port) {
         error!("Failed to connect to host: {:?}", e);
+    } else {
+        info!("Connected to host on port {port} successfully.")
     }
     info!("VirtIO socket test finished");
 }

+ 0 - 55
examples/aarch64/vsock_server.cc

@@ -1,55 +0,0 @@
-// Sets a listening socket on host.
-#include <err.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <cstdio>
-#include <cstdlib>
-
-// Needs to be included after sys/socket.h
-#include <linux/vm_sockets.h>
-
-constexpr int kPort = 1221;
-
-int main(int argc, const char *argv[]) {
-  int server_fd(socket(AF_VSOCK, SOCK_STREAM, 0));
-  if (server_fd < 0) {
-    errx(EXIT_FAILURE, "failed to set up the socket");
-  }
-
-  struct sockaddr_vm server_sa = (struct sockaddr_vm){
-      .svm_family = AF_VSOCK,
-      .svm_port = kPort,
-      .svm_cid = VMADDR_CID_ANY,
-  };
-
-  int ret = bind(server_fd, (struct sockaddr *)&server_sa, sizeof(server_sa));
-  if (ret != 0) {
-    errx(EXIT_FAILURE, "failed to bind to the address");
-  }
-  ret = listen(server_fd, 1);
-  if (ret != 0) {
-    errx(EXIT_FAILURE, "failed to listen to port %d", kPort);
-  }
-
-  printf("Listening for connections on port %d...\n", kPort);
-  struct sockaddr_vm client_sa;
-  socklen_t client_sa_len = sizeof(client_sa);
-  int client_fd =
-      accept(server_fd, (struct sockaddr *)&client_sa, &client_sa_len);
-  if (client_fd < 0) {
-    errx(EXIT_FAILURE, "failed to get the client fd");
-  }
-
-  char buffer[64];
-  // Receive data from the client
-  if (recv(client_fd, buffer, sizeof(buffer), 0) == -1) {
-    errx(EXIT_FAILURE, "failed to receive");
-  }
-
-  printf("Received: %s\n", buffer);
-  close(server_fd);
-  close(client_fd);
-
-  return EXIT_SUCCESS;
-}

+ 8 - 0
examples/vsock_server/Cargo.toml

@@ -0,0 +1,8 @@
+[package]
+name = "vsock_server"
+version = "0.1.0"
+authors = ["Alice Wang <[email protected]>"]
+edition = "2021"
+
+[dependencies]
+vsock = "0.3.0"

+ 13 - 0
examples/vsock_server/src/main.rs

@@ -0,0 +1,13 @@
+// Sets a listening socket on host.
+use vsock::{VsockAddr, VsockListener, VMADDR_CID_HOST};
+
+const PORT: u32 = 1221;
+
+fn main() {
+    println!("Setting up listening socket on port {PORT}");
+    let listener = VsockListener::bind(&VsockAddr::new(VMADDR_CID_HOST, PORT))
+        .expect("Failed to set up listening port");
+    for incoming in listener.incoming() {
+        println!("Accept connection: {incoming:?}");
+    }
+}

+ 13 - 10
src/device/socket/protocol.rs

@@ -1,4 +1,4 @@
-//! This module defines the socket device protocol according to the virtio spec 5.10 Socket Device
+//! This module defines the socket device protocol according to the virtio spec v1.1 5.10 Socket Device
 
 use super::error::{self, SocketError};
 use crate::volatile::ReadOnly;
@@ -13,15 +13,16 @@ use zerocopy::{
 };
 
 /// Currently only stream sockets are supported. type is 1 for stream socket types.
-/// Stream sockets provide in-order, guaranteed, connection-oriented delivery without message boundaries.
 #[derive(Copy, Clone, Debug)]
+#[repr(u16)]
 pub enum SocketType {
-    Stream,
+    /// Stream sockets provide in-order, guaranteed, connection-oriented delivery without message boundaries.
+    Stream = 1,
 }
 
-impl Into<U16<LittleEndian>> for SocketType {
-    fn into(self) -> U16<LittleEndian> {
-        (self as u16).into()
+impl From<SocketType> for U16<LittleEndian> {
+    fn from(socket_type: SocketType) -> Self {
+        (socket_type as u16).into()
     }
 }
 
@@ -31,7 +32,9 @@ pub struct VirtioVsockConfig {
     /// The guest_cid field contains the guest’s context ID, which uniquely identifies
     /// the device for its lifetime. The upper 32 bits of the CID are reserved and zeroed.
     ///
-    /// We need to split the guest_cid into two parts because VirtIO only guarantees 4 bytes alignment.
+    /// According to virtio spec v1.1 2.4.1 Driver Requirements: Device Configuration Space,
+    /// drivers MUST NOT assume reads from fields greater than 32 bits wide are atomic.
+    /// So we need to split the u64 guest_cid into two parts.
     pub guest_cid_low: ReadOnly<u32>,
     pub guest_cid_high: ReadOnly<u32>,
 }
@@ -118,9 +121,9 @@ pub enum VirtioVsockOp {
     CreditRequest = 7,
 }
 
-impl Into<U16<LittleEndian>> for VirtioVsockOp {
-    fn into(self) -> U16<LittleEndian> {
-        (self as u16).into()
+impl From<VirtioVsockOp> for U16<LittleEndian> {
+    fn from(op: VirtioVsockOp) -> Self {
+        (op as u16).into()
     }
 }