syntax = 'proto3';

package vmservice;
option go_package = "github.com/Microsoft/hcsshim/internal/vmservice";

import "google/protobuf/empty.proto";
import "google/protobuf/struct.proto";

service VM {
    // CreateVM will create the virtual machine with the configuration in the
    // CreateVMRequest. The virtual machine will be in a paused state power wise
    // after CreateVM. ResumeVM can be called to transition the VM into a running state.
    rpc CreateVM(CreateVMRequest) returns (google.protobuf.Empty);

    // TeardownVM will release all associated resources from the VM and unblock the WaitVM call.
    rpc TeardownVM(google.protobuf.Empty) returns (google.protobuf.Empty);

    // PauseVM will, if the virtual machine power state is in a running state, transition
    // the state to paused. This is the same state power wise that the VM should be in after
    // an initial CreateVM call.
    rpc PauseVM(google.protobuf.Empty) returns (google.protobuf.Empty);

    // ResumeVM is used to transition a vm to a running state. This can be used to resume a VM that
    // has had PauseVM called on it, or to start a VM that was created with CreateVM.
    rpc ResumeVM(google.protobuf.Empty) returns (google.protobuf.Empty);

    // WaitVM will block until the VM is either in a halted state or has had all of it's resources freed
    // via TeardownVM.
    rpc WaitVM(google.protobuf.Empty) returns (google.protobuf.Empty);

    // InspectVM is used to inspect virtual machine state. The query of what to inspect
    // is passed in as a string and the response can be of any form.
    rpc InspectVM(InspectVMRequest) returns (InspectVMResponse);

    // CapabilitiesVM will return what capabilities the virtstack supports. This includes
    // what guest operating systems are supported, what resources are supported, and if hot
    // add/hot remove of a resource is supported.
    rpc CapabilitiesVM(google.protobuf.Empty) returns (CapabilitiesVMResponse);

    // PropertiesVM will take in a list of properties that the virtstack will return
    // statistics for (memory, processors).
    rpc PropertiesVM(PropertiesVMRequest) returns (PropertiesVMResponse);

    // ModifyResource is a generic call to modify (add/remove/update) resources for a VM.
    // This includes things such as block devices, network adapters, and pci devices.
    rpc ModifyResource(ModifyResourceRequest) returns (google.protobuf.Empty);

    // VMSocket is an abstraction around a hypervisor socket transport to facilitate communication
    // between virtual machines and the host they are running on. The supported transports are
    // HvSocket and Vsock.
    rpc VMSocket(VMSocketRequest) returns (google.protobuf.Empty);

    // Quit will shutdown the process hosting the ttrpc server.
    rpc Quit(google.protobuf.Empty) returns (google.protobuf.Empty);
}

message DirectBoot {
    string kernel_path = 1;
    string initrd_path = 2;
    string kernel_cmdline = 3;
}

message UEFI {
    string firmware_path = 1;
    string device_path = 2;
    // Optional data to include for uefi boot. For Linux this could be used as the kernel
    // commandline.
    string optional_data = 3;
}

message MemoryConfig {
    uint64 memory_mb = 1;
    bool allow_overcommit = 2;
    bool deferred_commit = 3;
    bool hot_hint = 4;
    bool cold_hint = 5;
    bool cold_discard_hint = 6;
    uint64 low_mmio_gap_in_mb = 7;
    uint64 high_mmio_base_in_mb = 8;
    uint64 high_mmio_gap_in_mb = 9;
}

message ProcessorConfig {
    uint32 processor_count = 1;
    uint32 processor_weight = 2;
    uint32 processor_limit = 3;
}

message DevicesConfig {
    repeated SCSIDisk scsi_disks = 1;
    repeated VPMEMDisk vpmem_disks = 2;
    repeated NICConfig nic_config = 3;
    repeated WindowsPCIDevice windows_device = 4;
}

message VMConfig {
    MemoryConfig memory_config = 1;
    ProcessorConfig processor_config = 2;
    DevicesConfig devices_config = 3;
    SerialConfig serial_config = 4;
    oneof BootConfig {
        DirectBoot direct_boot = 5;
        UEFI uefi = 6;
    }
    WindowsOptions windows_options = 7;
    // Optional k:v extra data. Up to the virtstack for how to interpret this.
    map<string, string> extra_data = 8;
}

// WindowsOptions contains virtual machine configurations that are only present on a Windows host.
message WindowsOptions {
    uint64 cpu_group_id = 1;
}

message SerialConfig {
    message Config {
        uint32 port = 1;
        // Unix domain socket to relay serial console output to.
        string socket_path = 2;
    }
    repeated Config ports = 3;
}

message CreateVMRequest {
    VMConfig config = 1;
    // Optional ID to be used by the VM service in log messages. It's up to the
    // virtstack to make use of this field. Useful for debugging to be able to
    // correlate events for a given vm that the client launched.
    string log_id = 2;
}
message InspectVMRequest {
    string query = 1;
    uint32 recursion_limit = 2;
}

message InspectVMResponse {
    google.protobuf.Value result = 1;
}

message MemoryStats {
    uint64 working_set_bytes = 1;
    uint64 available_memory = 2;
    uint64 reserved_memory = 3;
    uint64 assigned_memory = 4;
}

message ProcessorStats {
    uint64 total_runtime_ns = 1;
}

message PropertiesVMRequest {
    enum PropertiesType {
        Memory = 0;
        Processor = 1;
    }
    repeated PropertiesType types = 1;
}

message PropertiesVMResponse {
    MemoryStats memory_stats = 1;
    ProcessorStats processor_stats = 2;
}

message CapabilitiesVMResponse {
    enum Resource {
        Vpmem = 0;
        Scsi = 1;
        Vpci = 2;
        Plan9 = 3;
        VMNic = 4;
        Memory = 5;
        Processor = 6;
    }

    message SupportedResource {
        bool Add = 1;
        bool Remove = 2;
        bool Update = 3;
        Resource resource = 4;
    }

    enum SupportedGuestOS {
        Windows = 0;
        Linux = 1;
    }
    repeated SupportedResource supported_resources = 1;
    repeated SupportedGuestOS supported_guest_os = 2;
}

message HVSocketListen {
    string service_id = 1;
    // Expected that the listener is a unix domain socket. These
    // are supported on Windows as of 1809/RS5.
    string listener_path = 2;
}

message VSockListen {
    uint32 port = 1;
    string listener_path = 2;
}

message VMSocketRequest {
    ModifyType type = 1;
    oneof Config {
        HVSocketListen hvsocket_list = 2;
        VSockListen vsock_listen = 3;
    }
}

enum ModifyType {
    ADD = 0;
    REMOVE = 1;
    UPDATE = 2;
}

enum DiskType {
    SCSI_DISK_TYPE_VHD1 = 0;
    SCSI_DISK_TYPE_VHDX = 1;
    SCSI_DISK_TYPE_PHYSICAL = 2;
}

message SCSIDisk {
    uint32 controller = 1;
    uint32 lun = 2;
    string host_path = 3;
    DiskType type = 4;
    bool read_only = 5;
}

message VPMEMDisk {
    string host_path = 1;
    DiskType type = 2;
    bool read_only = 3;
}


message NICConfig {
    string nic_id = 1; // GUID
    string port_id = 2; // GUID
    string mac_address = 3; // 12-34-56-78-9A-BC
    string switch_id = 4; // GUID
    // Optional friendly name for the adapter. Might be useful to show up in logs.
    string nic_name = 5;
}

message WindowsPCIDevice {
    // e.g. PCIP\\VEN_10DE&DEV_13F2&SUBSYS_115E10DE&REV_A1\\6&17F903&0&00400000
    string instance_id = 1;
}

message ModifyMemoryRequest {
    uint64 memory_mb = 1;
}

message ModifyProcessorRequest {
    // Index of the processor to add/remove
    uint32 processor_index = 1;
}

message ModifyProcessorConfigRequest {
    uint32 processor_weight = 1;
    uint32 processor_limit = 2;
}

message ModifyResourceRequest {
    ModifyType type = 1;
    oneof resource {
        ModifyProcessorRequest processor = 2;
        ModifyProcessorConfigRequest processor_config = 3;
        ModifyMemoryRequest memory = 4;
        SCSIDisk scsi_disk = 5;
        VPMEMDisk vpmem_disk = 6;
        NICConfig nic_config = 7;
        WindowsPCIDevice windows_device = 8;
    }
}