Skip to content
Closed
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
5 changes: 3 additions & 2 deletions dstack/vmm/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::{
config::{Config, NetworkFilterMode, Networking, NetworkingMode, ProcessAnnotation, Protocol},
logrotate,
netd::{
self, InterfaceIdentity, PrepareMacvtapRequest, PrepareRequest, Request as NetdRequest,
self, InterfaceIdentity, PrepareBridgeRequest, PrepareMacvtapRequest,
Request as NetdRequest,
},
};

Expand Down Expand Up @@ -563,7 +564,7 @@ impl App {
nic_index,
);
let request = match network.mode {
NetworkingMode::Bridge => NetdRequest::Prepare(PrepareRequest {
NetworkingMode::Bridge => NetdRequest::PrepareBridge(PrepareBridgeRequest {
identity: identity.clone(),
bridge: network.bridge.clone(),
mac,
Expand Down
37 changes: 27 additions & 10 deletions dstack/vmm/src/netd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct InterfaceIdentity {
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrepareRequest {
pub struct PrepareBridgeRequest {
#[serde(flatten)]
pub identity: InterfaceIdentity,
pub bridge: String,
Expand All @@ -73,7 +73,7 @@ pub struct PrepareMacvtapRequest {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "operation", rename_all = "snake_case")]
pub enum Request {
Prepare(PrepareRequest),
PrepareBridge(PrepareBridgeRequest),
PrepareMacvtap(PrepareMacvtapRequest),
Remove {
#[serde(flatten)]
Expand Down Expand Up @@ -121,7 +121,7 @@ pub struct PreparedInterface {

pub async fn request(socket: &Path, request: &Request) -> Result<PreparedInterface> {
let operation = match request {
Request::Prepare(_) => "prepare",
Request::PrepareBridge(_) => "prepare_bridge",
Request::PrepareMacvtap(_) => "prepare_macvtap",
Request::Remove { .. } => "remove",
Request::Check { .. } => "check",
Expand Down Expand Up @@ -248,8 +248,8 @@ async fn read_request(stream: &mut UnixStream) -> Result<Request> {
fn handle_request(libvirt_uri: &str, request: Request) -> Result<(String, Option<String>)> {
let _lock = OperationLock::acquire()?;
match request {
Request::Prepare(request) => {
prepare_interface(libvirt_uri, &request).map(|tap| (tap, None))
Request::PrepareBridge(request) => {
prepare_bridge(libvirt_uri, &request).map(|tap| (tap, None))
}
Request::PrepareMacvtap(request) => prepare_macvtap(
libvirt_uri,
Expand Down Expand Up @@ -362,8 +362,8 @@ impl Drop for OperationLock {
}
}

fn prepare_interface(libvirt_uri: &str, request: &PrepareRequest) -> Result<String> {
validate_prepare(request)?;
fn prepare_bridge(libvirt_uri: &str, request: &PrepareBridgeRequest) -> Result<String> {
validate_prepare_bridge(request)?;
let tap = tap_name(&request.identity);
// A failed VMM start may leave a deterministic resource behind. Replacing
// it makes prepare idempotent without accepting a caller-selected TAP.
Expand Down Expand Up @@ -430,7 +430,7 @@ fn delete_binding(uri: &str, tap: &str) -> Result<()> {
bail!("virsh failed to delete binding {tap}: {}", error.trim())
}

fn binding_xml(request: &PrepareRequest, tap: &str) -> String {
fn binding_xml(request: &PrepareBridgeRequest, tap: &str) -> String {
let owner_uuid = stable_uuid(&request.identity);
let owner_name = format!(
"dstack:{}:{}:{}",
Expand Down Expand Up @@ -472,7 +472,7 @@ fn stable_uuid(identity: &InterfaceIdentity) -> Uuid {
Uuid::from_bytes(bytes)
}

fn validate_prepare(request: &PrepareRequest) -> Result<()> {
fn validate_prepare_bridge(request: &PrepareBridgeRequest) -> Result<()> {
validate_identity(&request.identity)?;
validate_name("bridge", &request.bridge, 15, "_.-")?;
if !Path::new("/sys/class/net")
Expand Down Expand Up @@ -670,7 +670,7 @@ mod tests {

#[test]
fn binding_xml_escapes_values() {
let request = PrepareRequest {
let request = PrepareBridgeRequest {
identity: identity("instance<&", "vm", 0),
bridge: "br0".into(),
mac: "02:00:00:00:00:01".into(),
Expand Down Expand Up @@ -719,6 +719,23 @@ mod tests {
assert!(value.get("identity").is_none());
}

#[test]
fn bridge_prepare_has_a_dedicated_operation() {
let request = Request::PrepareBridge(PrepareBridgeRequest {
identity: identity("instance", "vm", 0),
bridge: "br0".into(),
mac: "02:00:00:00:00:01".into(),
qemu_uid: 1000,
filter: "clean-traffic".into(),
parameters: BTreeMap::new(),
});
let value = serde_json::to_value(request).unwrap();
assert_eq!(value["operation"], "prepare_bridge");
assert_eq!(value["instance_id"], "instance");
assert_eq!(value["bridge"], "br0");
assert!(value.get("identity").is_none());
}

#[tokio::test]
async fn disconnected_client_is_confined_to_one_connection() {
let (mut server, client) = UnixStream::pair().unwrap();
Expand Down