mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm, vm-migration: validate protocol version at start
Validate the sender's migration protocol version when handling the initial Start request. Read the version from the Start command header, accept only the supported version window n-1..=n, and reject unsupported versions with Error. A rejected Start moves the receiver to the aborted state. This keeps compatibility one-way, from older protocol versions to newer ones, and leaves later version-based branching on the receiver side. Log the protocol version on both sender and receiver to make the active migration path visible. On-behalf-of: SAP leander.kohler@sap.com Signed-off-by: Leander Kohler <leander.kohler@cyberus-technology.de>
This commit is contained in:
committed by
Rob Bradford
parent
b27faaaa45
commit
51bd9d24f3
@@ -91,6 +91,7 @@ use std::mem::size_of;
|
||||
use std::ops::RangeInclusive;
|
||||
use std::{mem, slice};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vm_memory::ByteValued;
|
||||
@@ -226,6 +227,26 @@ impl Request {
|
||||
&self.command_headers
|
||||
}
|
||||
|
||||
/// Returns the sender protocol version from a `Start` request if it is supported.
|
||||
pub fn sender_protocol_version(&self) -> Result<u16, MigratableError> {
|
||||
assert_eq!(
|
||||
self.command(),
|
||||
Command::Start,
|
||||
"sender_protocol_version() must only be called for Start requests",
|
||||
);
|
||||
|
||||
// The protocol version is stored in the first two header bytes, the remaining bytes are ignored.
|
||||
let sender_version = u16::from_le_bytes([self.command_headers[0], self.command_headers[1]]);
|
||||
if !supported_protocol_versions().any(|version| version == sender_version) {
|
||||
let supported_versions = supported_protocol_versions().join(", ");
|
||||
return Err(MigratableError::MigrateReceive(anyhow!(
|
||||
"Migration protocol version {sender_version} doesn't match supported versions: {supported_versions}"
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(sender_version)
|
||||
}
|
||||
|
||||
pub fn read_from(fd: &mut dyn Read) -> Result<Request, MigratableError> {
|
||||
let mut request = Request::default();
|
||||
fd.read_exact(Self::as_mut_slice(&mut request))
|
||||
@@ -522,7 +543,9 @@ impl MemoryRangeTable {
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_tests {
|
||||
use crate::protocol::{Command, MemoryRange, MemoryRangeTable, Request};
|
||||
use crate::protocol::{
|
||||
CURRENT_PROTOCOL_VERSION, Command, MemoryRange, MemoryRangeTable, Request,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_start_request_ignores_residual_command_headers_bytes() {
|
||||
@@ -538,6 +561,18 @@ mod unit_tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sender_protocol_version_rejects_unsupported_version() {
|
||||
let request = Request {
|
||||
command: Command::Start,
|
||||
command_headers: [255, 0, 0, 0, 0, 0],
|
||||
length: 0,
|
||||
};
|
||||
|
||||
const { assert!(CURRENT_PROTOCOL_VERSION < 255) };
|
||||
request.sender_protocol_version().unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_memory_range_table_from_dirty_ranges_iter() {
|
||||
let input = [0b1111_1110_1110, 0b1_0000];
|
||||
|
||||
@@ -937,7 +937,11 @@ impl Vmm {
|
||||
let state_name = state.variant_name();
|
||||
match state {
|
||||
Established => match req.command() {
|
||||
Command::Start => Ok(Started),
|
||||
Command::Start => {
|
||||
let migration_protocol_version = req.sender_protocol_version()?;
|
||||
debug!("Using migration protocol {migration_protocol_version}");
|
||||
Ok(Started)
|
||||
}
|
||||
c => invalid_command(state_name, c),
|
||||
},
|
||||
Started => match req.command() {
|
||||
@@ -1420,6 +1424,7 @@ impl Vmm {
|
||||
Request::start(),
|
||||
MigratableError::MigrateSend(anyhow!("Error starting migration")),
|
||||
)?;
|
||||
debug!("Using migration protocol {CURRENT_PROTOCOL_VERSION}");
|
||||
|
||||
// Send config
|
||||
let vm_config = vm.get_config();
|
||||
|
||||
Reference in New Issue
Block a user