blob: 7c154446416494127db9fe7d02c45a5ef461fa6a [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VM_TOOLS_CONCIERGE_VM_UTIL_H_
#define VM_TOOLS_CONCIERGE_VM_UTIL_H_
#include <sys/types.h>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <base/files/file_path.h>
#include <base/strings/string_split.h>
#include <base/strings/string_piece.h>
#include <base/time/time.h>
#include <base/optional.h>
#include <brillo/process/process.h>
#include <vm_tools/concierge/usb_control.h>
#include <vm_tools/concierge/balloon_policy.h>
namespace base {
class FilePath;
} // namespace base
namespace vm_tools {
namespace concierge {
class Disk {
public:
struct Config {
bool writable{false};
base::Optional<bool> sparse;
base::Optional<bool> o_direct;
};
Disk(base::FilePath path, bool writable);
Disk(base::FilePath path, const Config& config);
Disk(const Disk&) = delete;
Disk& operator=(const Disk&) = delete;
Disk(Disk&&);
virtual ~Disk();
// Gets the command line argument that needs to be passed to crosvm
// corresponding to this disk.
base::StringPairs GetCrosvmArgs() const;
void EnableODirect(bool enable);
private:
// Path to the disk image on the host.
base::FilePath path_;
// Whether the disk should be writable by the VM.
bool writable_;
// Whether the disk should allow sparse file operations (discard) by the VM.
base::Optional<bool> sparse_;
// Whether the disk access should be done with O_DIRECT by the VM.
base::Optional<bool> o_direct_;
};
// Path to the crosvm binary.
extern const char kCrosvmBin[];
// Uid and gid mappings for the android data directory. This is a
// comma-separated list of 3 values: <start of range inside the user namespace>
// <start of range outside the user namespace> <count>. The values are taken
// from platform2/arc/container-bundle/pi/config.json.
extern const char kAndroidUidMap[];
extern const char kAndroidGidMap[];
// Calculates the amount of memory to give the virtual machine. Currently
// configured to provide 75% of system memory. This is deliberately over
// provisioned with the expectation that we will use the balloon driver to
// reduce the actual memory footprint.
std::string GetVmMemoryMiB();
// Retrieves the physical package ID for |cpu| from the topology information in
// sysfs.
base::Optional<int32_t> GetCpuPackageId(int32_t cpu);
// Retrieves the CPU capacity property for |cpu| from sysfs.
base::Optional<int32_t> GetCpuCapacity(int32_t cpu);
// Calculate an appropriate CPU affinity setting based on the host system's
// CPU clusters and capacity. CPUs will be grouped based on cluster if multiple
// clusters exist, or based on groupings of equal CPU capacity if more than one
// such grouping exists. Otherwise, |nullopt| will be returned.
base::Optional<std::string> GetCpuAffinityFromClusters(
const std::vector<std::vector<std::string>>& cpu_clusters,
const std::map<int32_t, std::vector<std::string>>& cpu_capacity_groups);
// Puts the current process in a CPU cgroup specificed by |cpu_cgroup|, and
// then calls SetPgid(). This function can be called as brillo::ProcessImpl's
// PreExecCallback.
bool SetUpCrosvmProcess(const base::FilePath& cpu_cgroup);
// Sets the pgid of the current process to its pid. This is needed because
// crosvm assumes that only it and its children are in the same process group
// and indiscriminately sends a SIGKILL if it needs to shut them down. This
// function can be called as brillo::ProcessImpl's PreExecCallback.
bool SetPgid();
// Waits for the |pid| to exit. Returns true if |pid| successfully exited and
// false if it did not exit in time.
bool WaitForChild(pid_t child, base::TimeDelta timeout);
// Returns true if a process with |pid| exists.
bool CheckProcessExists(pid_t pid);
// Runs a crosvm subcommand.
void RunCrosvmCommand(std::initializer_list<std::string> args);
void RunCrosvmCommand(std::string command, std::string socket_path);
// Returns balloon stats info retrieved from virtio-balloon device.
base::Optional<BalloonStats> GetBalloonStats(std::string socket_path);
// Attaches an usb device at host |bus|:|addr|, with |vid|, |pid| and an
// opened |fd|.
bool AttachUsbDevice(std::string socket_path,
uint8_t bus,
uint8_t addr,
uint16_t vid,
uint16_t pid,
int fd,
UsbControlResponse* response);
// Detaches the usb device at guest |port|.
bool DetachUsbDevice(std::string socket_path,
uint8_t port,
UsbControlResponse* response);
// Lists all usb devices attached to guest.
bool ListUsbDevice(std::string socket_path, std::vector<UsbDevice>* devices);
// Resizes the disk identified by |disk_index| to |new_size| in bytes.
bool CrosvmDiskResize(std::string socket_path,
int disk_index,
uint64_t new_size);
// Updates |cpu_cgroup|'s cpu.shares to |cpu_shares|.
bool UpdateCpuShares(const base::FilePath& cpu_cgroup, int cpu_shares);
class CustomParametersForDev {
public:
// By default this class would do nothing.
CustomParametersForDev() = default;
// Allow custom parameters on development devices with arcvm_dev.conf.
// Loads custom parameters from a string. Please check
// vm_tools/init/arcvm_dev.conf for the list of supported directives.
explicit CustomParametersForDev(const std::string& data);
// Apply the parsed result of configuration files to |args| as a vector of
// string pairs.
void Apply(base::StringPairs* args);
base::Optional<const std::string> ObtainSpecialParameter(
const std::string& key);
private:
// Command line parameter prefix to crosvm to remove.
std::vector<std::string> prefix_to_remove_{};
// Command line parameters to crosvm to add.
base::StringPairs params_to_add_{};
// Other special handling.
std::map<std::string, std::string> special_parameters_{};
bool initialized_{false};
};
// Creates shared data parameter for crovm.
std::string CreateSharedDataParam(const base::FilePath& data_dir,
const std::string& tag,
bool enable_caches,
bool ascii_casefold,
const std::vector<uid_t>& privileged_uids);
class ArcVmCPUTopology {
public:
ArcVmCPUTopology(uint32_t num_cpus, uint32_t num_rt_cpus);
~ArcVmCPUTopology() = default;
ArcVmCPUTopology(const ArcVmCPUTopology&) = delete;
ArcVmCPUTopology& operator=(const ArcVmCPUTopology&) = delete;
void CreateCPUAffinity();
uint32_t NumCPUs();
uint32_t NumRTCPUs();
void SetNumRTCPUs(uint32_t num_rt_cpus);
const std::string& AffinityMask();
const std::string& RTCPUMask();
const std::string& CapacityMask();
const std::vector<std::string>& PackageMask();
// Unit Testing crud
void AddCpuToCapacityGroupForTesting(uint32_t cpu, uint32_t capacity);
void AddCpuToPackageGroupForTesting(uint32_t cpu, uint32_t package);
void CreateCPUAffinityForTesting();
private:
void CreateTopology();
void CreateAffinity();
bool IsSymmetricCpu();
// Total number of CPUs VM will be configured with
uint32_t num_cpus_;
// Number of RT CPUs
uint32_t num_rt_cpus_;
// CPU mask for RT CPUs
std::string rt_cpu_mask_;
// CPU affinity
std::string affinity_mask_;
// A set of RT CPUs
std::set<uint32_t> rt_cpus_;
// CPU capacity grouping
std::map<uint32_t, std::vector<uint32_t>> capacity_;
// CPU package grouping
std::map<uint32_t, std::vector<uint32_t>> package_;
// CPU capacity mask
std::string capacity_mask_;
// CPU package mask
std::vector<std::string> package_mask_;
};
} // namespace concierge
} // namespace vm_tools
#endif // VM_TOOLS_CONCIERGE_VM_UTIL_H_