1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! libmicrovmi is a cross-platform unified virtual machine introsection interface, following a simple design to keep interoperability at heart.
//!
//! Click on this [book 📖](https://wenzel.github.io/libmicrovmi/) to find our project documentation.
//!
//! The library's entrypoint is the [init](fn.init.html) function.

#![allow(clippy::upper_case_acronyms)]

pub mod api;
pub mod capi;
mod driver;
pub mod errors;

#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;

use enum_iterator::IntoEnumIterator;

use api::params::DriverInitParams;
use api::DriverType;
use api::Introspectable;
#[cfg(feature = "kvm")]
use driver::kvm::Kvm;
#[cfg(feature = "mflow")]
use driver::memflow::Memflow;
#[cfg(feature = "virtualbox")]
use driver::virtualbox::VBox;
#[cfg(feature = "xen")]
use driver::xen::Xen;
use errors::MicrovmiError;
#[cfg(feature = "kvm")]
use kvmi::create_kvmi;

/// libmicrovmi initialization entrypoint
///
/// This function will initialize a libmicrovmi driver and call the hypervisor VMI API.
/// It returns a `Box<dyn Introspectable>` trait object, which implements the [Introspectable](api/trait.Introspectable.html) trait.
///
/// For complete documentation on driver init params, please check [DriverInitParams](struct.DriverInitParams.html) struct.
///
/// # Arguments
/// * `driver_type`: optional driver type to initialize. If None, all compiled drivers will be initialized one by one. The first that succeeds will be returned.
/// * `init_params`: optional driver initialization parameters
///
/// # Examples
/// ```no_run
/// use microvmi::init;
/// // 1 - attempt to init all drivers, without any init parameters
/// let drv = init(None, None);
///
/// // 2 - add parameters: vm_name
/// // a `vm_name` parameter is required for multiple drivers: Xen, KVM, VirtualBox
/// use microvmi::api::params::{DriverInitParams, CommonInitParams};
/// let init_params = DriverInitParams {
///     common: Some(CommonInitParams { vm_name: String::from("windows10")}),
///     ..Default::default()
/// };
/// let drv = init(None, Some(init_params));
///
/// // 3 - add parameters: KVM specific params
/// // KVM requires an additional unix socket to be specified
/// // and specify the KVM driver only
/// use microvmi::api::params::KVMInitParams;
/// use microvmi::api::DriverType;
/// let init_params = DriverInitParams {
///     common: Some(CommonInitParams { vm_name: String::from("windows10")}),
///     kvm: Some(KVMInitParams::UnixSocket {path: String::from("/tmp/introspector")}),
///     ..Default::default()
/// };
/// let drv = init(Some(DriverType::KVM), Some(init_params));
/// ```
pub fn init(
    driver_type: Option<DriverType>,
    init_params: Option<DriverInitParams>,
) -> Result<Box<dyn Introspectable>, MicrovmiError> {
    info!("Microvmi init");
    match driver_type {
        None => {
            // for each possible DriverType
            for drv_type in DriverType::into_enum_iter() {
                // try to init
                match init_driver(drv_type, init_params.clone()) {
                    Ok(driver) => {
                        return Ok(driver);
                    }
                    Err(e) => {
                        debug!("{:?} driver initialization failed: {}", drv_type, e);
                        continue;
                    }
                }
            }
            Err(MicrovmiError::NoDriverAvailable)
        }
        Some(drv_type) => init_driver(drv_type, init_params),
    }
}

/// Initialize a given driver type
/// return None if the requested driver has not been compiled in libmicrovmi
fn init_driver(
    driver_type: DriverType,
    init_params_option: Option<DriverInitParams>,
) -> Result<Box<dyn Introspectable>, MicrovmiError> {
    let _init_params = init_params_option.unwrap_or(DriverInitParams {
        ..Default::default()
    });
    #[allow(clippy::match_single_binding)]
    match driver_type {
        #[cfg(feature = "kvm")]
        DriverType::KVM => Ok(Box::new(Kvm::new(create_kvmi(), _init_params)?)),
        #[cfg(feature = "mflow")]
        DriverType::Memflow => Ok(Box::new(Memflow::new(_init_params)?)),
        #[cfg(feature = "virtualbox")]
        DriverType::VirtualBox => Ok(Box::new(VBox::new(_init_params)?)),
        #[cfg(feature = "xen")]
        DriverType::Xen => Ok(Box::new(Xen::new(_init_params)?)),
        #[allow(unreachable_patterns)]
        _ => Err(MicrovmiError::DriverNotCompiled(driver_type)),
    }
}