Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions runner/src/resource_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ pub struct ResourceManager {
allocation: Arc<RwLock<ResourceState>>,
// IP pool - queue of available IPs
free_ips: Arc<RwLock<VecDeque<Ipv4Addr>>>,
// CID pool - queue of available Context IDs for vsock (Linux VMs only)
free_cids: Arc<RwLock<VecDeque<u32>>>,
}

impl ResourceManager {
Expand All @@ -187,10 +189,28 @@ impl ResourceManager {
free_ips.push_back(Ipv4Addr::new(10, 0, 0, i));
}

// Initialize CID pool with a range of CIDs (3 - 1024)
//
// The Context Identifier (CID) is a 32-bit address for vsock communication.
// The combination of a CID and a port number uniquely identifies a vsock connection.
//
// There are several special addresses:
// -1U32: VMADDR_CID_ANY is used to indicate any CID.
// 0: VMADDR_CID_HYPERVISOR is reserved for the hypervisor.
// 1: VMADDR_CID_LOCAL is the well-known address for local communication (loopback).
// 2: VMADDR_CID_HOST is the well-known address of the host.
//
// Guest CIDs range from 3 to max(2^32 - 1).
let mut free_cids = VecDeque::new();
for cid in 3..=1024 {
free_cids.push_back(cid);
}

Self {
limits,
allocation: Arc::new(RwLock::new(ResourceState::new())),
free_ips: Arc::new(RwLock::new(free_ips)),
free_cids: Arc::new(RwLock::new(free_cids)),
}
}

Expand Down Expand Up @@ -356,6 +376,31 @@ impl ResourceManager {
free_ips.len()
);
}

/// Allocate a CID (Context ID) from the pool for vsock communication
pub async fn allocate_cid(&self) -> Option<u32> {
let mut free_cids = self.free_cids.write().await;
let cid = free_cids.pop_front();

if let Some(cid) = cid {
tracing::debug!(
"Allocated CID: {} ({} CIDs remaining)",
cid,
free_cids.len()
);
} else {
tracing::warn!("No available CIDs in pool");
}

cid
}

/// Release a CID back to the pool
pub async fn release_cid(&self, cid: u32) {
let mut free_cids = self.free_cids.write().await;
free_cids.push_back(cid);
tracing::debug!("Released CID: {} ({} CIDs available)", cid, free_cids.len());
}
}

/// RAII guard for IP address allocation
Expand Down Expand Up @@ -398,6 +443,41 @@ impl Drop for IpGuard {
}
}

/// RAII guard for CID allocation (Linux VMs only)
/// Automatically releases the CID when dropped
pub struct CidGuard {
cid: Option<u32>,
resource_manager: Arc<ResourceManager>,
}

impl CidGuard {
/// Create a new CID guard by allocating a CID from the resource manager
pub async fn new(resource_manager: Arc<ResourceManager>) -> Option<Self> {
let cid = resource_manager.allocate_cid().await?;
Some(Self {
cid: Some(cid),
resource_manager,
})
}

/// Get the allocated CID
pub fn cid(&self) -> Option<u32> {
self.cid
}
}

impl Drop for CidGuard {
fn drop(&mut self) {
if let Some(cid) = self.cid {
// We need to spawn a task to release the CID since drop is not async
let resource_manager = self.resource_manager.clone();
tokio::spawn(async move {
resource_manager.release_cid(cid).await;
});
}
}
}

/// RAII guard for allocated resources
/// Automatically releases resources when dropped
pub struct ResourceGuard {
Expand Down
19 changes: 16 additions & 3 deletions runner/src/vm_impl/linux.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::protocol::{JobConfig, VM};
use crate::resource_manager::{IpGuard, ResourceGuard, ResourceManager};
use crate::resource_manager::{CidGuard, IpGuard, ResourceGuard, ResourceManager};
use crate::vm::Vm;
use crate::vsock::{self, GUEST_CID};
use crate::vsock;
use cloud_hypervisor_client::apis::client::APIClient;
use cloud_hypervisor_client::apis::configuration::Configuration;
use cloud_hypervisor_client::models::console_config::Mode;
Expand Down Expand Up @@ -34,6 +34,8 @@ pub struct LinuxVm {
_resource_guard: Option<ResourceGuard>,
/// IP guard for automatic IP release (kept alive for RAII cleanup)
_ip_guard: Option<IpGuard>,
/// CID guard for automatic CID release (kept alive for RAII cleanup)
_cid_guard: Option<CidGuard>,
/// The VM identifier
id: String,
/// The runtime directory for VM-related files (as TempDir for auto-cleanup)
Expand Down Expand Up @@ -244,8 +246,18 @@ impl Vm for LinuxVm {

tracing::info!("Allocated IP {} for VM {}", guest_ip, id);

// Allocate CID (Context ID) for vsock communication (required for Linux)
let cid_guard = CidGuard::new(resource_manager.clone())
.await
.ok_or_else(|| eyre::eyre!("Failed to allocate CID for VM {}", id))?;
let cid = cid_guard
.cid()
.ok_or_else(|| eyre::eyre!("CID guard has no CID"))?;

tracing::debug!("Allocated CID {} for VM {}", cid, id);

let vsock_config = VsockConfig {
cid: GUEST_CID as i64,
cid: cid as i64,
socket: vsock_socket_path.to_str().unwrap().to_string(),
iommu: Some(false),
..Default::default()
Expand Down Expand Up @@ -316,6 +328,7 @@ impl Vm for LinuxVm {
config: vm_config,
_resource_guard: Some(resource_guard),
_ip_guard: Some(ip_guard),
_cid_guard: Some(cid_guard),
id,
_run_dir_temp: run_dir_temp,
run_dir,
Expand Down
15 changes: 0 additions & 15 deletions runner/src/vsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,6 @@ use tokio::sync::{Mutex, Notify, mpsc};
use tokio_vsock::{VsockAddr, VsockStream};
use tracing::{error, info};

// The Context Identifier (CID) is a 32-bit address for vsock communication.
// The combination of a CID and a port number uniquely identifies a vsock connection.
//
// There are several special addresses:
//
// -1U32: VMADDR_CID_ANY is used to indicate any CID.
// 0: VMADDR_CID_HYPERVISOR is reserved for the hypervisor.
// 1: VMADDR_CID_LOCAL is the well-known address for local communication (loopback).
// 2: VMADDR_CID_HOST is the well-known address of the host.
//
// Guest CIDs range from 3 to max(2^32 - 1).
Comment thread
domenkozar marked this conversation as resolved.
//
// TODO: if running multiple VMs, this value will be different for each VM.
pub const GUEST_CID: u32 = 3;

/// The CID for the host.
pub const HOST_CID: u32 = tokio_vsock::VMADDR_CID_HOST;

Expand Down