Skip to content
Merged
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
3 changes: 2 additions & 1 deletion doc/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ nvx/
| | |-- protocol/ Control-console codec, NVXS session, and the guest targets that live shares may not take, shared by the host and the guest
| | |-- contract.rs Control-contract versions and release compatibility
| | |-- net/ CIDR parsing and subtraction, and hostname and guest-network forms
| | |-- gpt/ Strict reading of GPT disks whose first partition configures an adapter and whose other partitions hold a root's read-only layers, shared by the host and the guest
| | |-- host/ Artifacts, launch, network and egress-policy lowering, sessions, VM instances, sandbox stores, the sandbox launch profile, and the `nvx-rs` CLI (feature `cli`)
| | |-- testing/ Fake OpenVMM (feature `testing`)
| | |-- guest/ Programs that run in Linux guests, the guest's NVXS connection, the libraries through which any guest init or agent starts a program, collects its children's statuses, settles its executions' cgroups, drives each execution, bind-mounts host mappings below the roots that it names, and assembles and tears down a layered root, and the typed calls through which it runs the time ABI's steps and the reseed (feature `guest`)
| | |-- guest/ Programs that run in Linux guests, the guest's NVXS connection, the libraries through which any guest init or agent starts a program, collects its children's statuses, settles its executions' cgroups, drives each execution, bind-mounts host mappings below the roots that it names, assembles and tears down a layered root, and reads a GPT disk's partition table through its block device, and the typed calls through which it runs the time ABI's steps and the reseed (feature `guest`)
| | `-- bin/ nvx-rs CLI, nvx-fake-openvmm test double, and the guest binaries
| |-- tests/ Fake-OpenVMM instance lifecycle, sandbox store, CLI, NVXS session, guest-binary, and hypervisor managed-lifecycle tests, the store's record fixtures, and the golden fixtures that Python recorded
| |-- build.rs Stages the bundled artifacts (feature `bundled`)
Expand Down
18 changes: 11 additions & 7 deletions nvx-rs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ nvx-rs/
│ │ no dependencies, shared by the host and the guest
│ ├── contract.rs control-contract versions and release-manifest compatibility
│ ├── net/ CIDR parsing and subtraction, and hostname and guest-network forms
│ ├── gpt/ strict reading of GPT disks whose p1 configures an adapter and whose other
│ │ partitions hold a root's read-only layers; no dependencies, shared by the
│ │ host and the guest
│ ├── gpt/ strict reading of GPT disks whose first partition configures an adapter and
│ │ whose other partitions hold a root's read-only layers; no dependencies,
│ │ shared by the host and the guest
│ ├── uuid.rs UUIDs in their canonical text and in GPT's layout; no dependencies, shared
│ │ by the host and the guest
│ ├── hypervisor.rs
Expand All @@ -45,9 +45,10 @@ nvx-rs/
│ ├── guest/ feature `guest`: the programs that run in Linux guests, the guest's NVXS
│ │ connection, the libraries through which a guest init or agent starts a
│ │ program, collects its children's statuses, settles its executions'
│ │ cgroups, bind-mounts host mappings below the roots that it names, and
│ │ assembles and tears down a layered root, and the typed calls through which
│ │ it runs the time ABI's steps and the reseed
│ │ cgroups, bind-mounts host mappings below the roots that it names,
│ │ assembles and tears down a layered root, and reads a GPT disk's partition
│ │ table through its block device, and the typed calls through which it runs
│ │ the time ABI's steps and the reseed
│ └── bin/ nvx-rs, nvx-fake-openvmm, and the guest binaries
├── tests/ fake-OpenVMM, CLI, NVXS session, process-supervision, store, and guest-binary
│ tests, the store's record fixtures, and the golden fixtures that Python
Expand All @@ -65,7 +66,7 @@ nvx-rs/
| `nvx::protocol::share` | The guest targets that a sandbox's live shares may not take, which the host's `sandbox::mount` and the guest's `root` both refuse: `RESERVED_MOUNT_TARGETS`, the trees where the container runtime mounts or binds, `RESERVED_EXACT_MOUNT_TARGETS`, the directories that it creates, `RESERVED_TARGET_CHARACTERS`, and `reservation`, which tells why a target is reserved |
| `nvx::contract` | The OpenVMM microVM ABI, broker protocol, and control-contract revision that the crate speaks, and `manifest_is_compatible` for a release's `SOURCE-MANIFEST.json` |
| `nvx::net` | `Cidr`: IPv4 and IPv6 networks and their subtraction; `is_valid_hostname` and `is_valid_guest_network`, the forms of a VM's hostname and guest address |
| `nvx::gpt` | `Disk::read`: the protective MBR, primary header, and primary partition entry array of a GPT disk, read through a `ReadAt` source that the caller gives and checked strictly, as UEFI specifies them and as Linux requires them, without ever reading the backup: 128-byte entries, at most 1 MiB of them, used entries first and without holes, p1 and 1 to 254 layers, extents in the usable blocks without overlap, and unique GUIDs, with checked arithmetic in the disk's logical blocks. `Expected` adds the disk GUID and the partitions' unique GUIDs and sizes that a caller knows, and `Disk::read_p1` returns p1's opaque bytes, up to a bound and without trailing NUL bytes and whitespace. GUIDs are `nvx::uuid::Uuid`s. It has no dependencies, so the guest and the host's checks of the images that it stages share it |
| `nvx::gpt` | `Disk::read`: the protective MBR, primary header, and primary partition entry array of a GPT disk, read through a `ReadAt` source that the caller gives and checked strictly, as UEFI specifies them and as Linux requires them, without ever reading the backup: 128-byte entries, at most 1 MiB of them, used entries first and without holes, a first partition and 1 to 254 layers, extents in the usable blocks without overlap, and unique GUIDs, with checked arithmetic in the disk's logical blocks. `Expected` adds the disk GUID and the partitions' unique GUIDs and sizes that a caller knows, and `Disk::read_first_partition` returns the first partition's opaque bytes, up to a bound and without trailing NUL bytes and whitespace. GUIDs are `nvx::uuid::Uuid`s. It has no dependencies, so the guest and the host's checks of the images that it stages share it |
| `nvx::uuid` | `Uuid`: a UUID, such as the GUID of a GPT disk or partition or the UUID of a filesystem, in the order of its canonical text, the one text that it displays and parses: 32 lowercase hexadecimal digits in groups of 8, 4, 4, 4, and 12, joined by hyphens. `from_bytes_le` and `to_bytes_le` convert the layout in which GPT and other EFI GUIDs store their first three groups little-endian. It has no dependencies, so the host and the guest share it |
| `nvx::Hypervisor` | KVM, MSHV, or WHP, with its serde form behind the `serde` feature |
| `nvx::host::artifacts` | `Artifacts` (also `nvx::Artifacts`): the OpenVMM executable, guest kernel, and Alpine initramfs, from a release, a repository checkout, the environment, a directory next to the executable, or the bundle. `ArtifactDir` and `Guest`: every artifact of the guests that `nvx.py` runs, the OpenVMM executable, the kernel, the Alpine, Ubuntu, and Azure Linux initramfs images and their package manifests, and the Ubuntu distro layer and its manifest, in a checkout's `build/` and `openvmm/target/release/` or a release's `guest/` and `bin/`, checked in the order and with the messages of `nvx.py`. `ArtifactPaths` lists them all and serializes as JSON |
Expand Down Expand Up @@ -93,6 +94,7 @@ nvx-rs/
| `nvx::guest::time` | x86_64: `TimeAbi`, the steps of NVX time ABI v1 as typed calls in the caller's process, for any guest init or agent: the cold-boot time step and, separately, the start of the time daemon in a child process that the caller supervises, the VM generation ID, a `CaptureRequest` that repairs a `Restore`, and a `RestoreFinish`. A call takes the permission for OpenVMM's ports on the calling thread for each port transaction alone, and fails with `TimeError::PortRelease` if the thread may still hold some of it, which a process that it started would inherit, and from which `nvx::guest::spawn` starts none. No call waits for a child that it did not start. `nvx-time` runs its steps through them |
| `nvx::guest::reseed` | `Seed::read` and `reseed`: a restore's fresh entropy, which starts with its `GenerationId`, and the reseed of the kernel's random number generator with it, in the caller's process. `nvx-reseed` runs them |
| `nvx::guest::root` | The operations of a layered root, for a guest init or agent, whether or not it is PID 1. `bootstrap`: the agent's and the workload's sibling cgroups of a `Layout`, with every process of their parent moved into the agent's, the agent's `memory.low`, and the workload cgroup prepared through `ExecutionCgroup::prepare`, with its `memory.max` and `pids.max`, and user namespaces kept unavailable. `assemble`: the `Assembly`'s block devices, found by their MMIO windows, checked against their expected sizes and flushed, and the `Root` that it mounts, at a runtime directory, a canonical path that no symbolic link leads through, that it holds exclusively until its teardown, where nothing is mounted already: a read-only EROFS image, whose expected `nvx::uuid::Uuid` it checks in its superblock, under an overlay with `metacopy=on,xino=on`, mounted `nosuid,nodev`, whose upper and work directories are on an ext4 scratch mounted `nosuid,nodev` too. `Root::mount_share` and `Root::mount_aggregate`: virtio-fs live shares at targets in the root that it checks, against the targets that `protocol::share` reserves among others, with one aggregate per root, whose children it binds through `mappings::Mapping`. `Root::teardown`: the shares in reverse mount order, then the overlay, the image, and the scratch, with every failed unmount reported. Each failure is a typed `Error`. The operations collect no child's status, change neither the caller's root nor its credentials, start no async runtime, and never power the VM off |
| `nvx::guest::gpt` | `read_disk`: the partition table of a GPT disk, read and checked with `nvx::gpt`'s `Disk::read` through the disk's block device, which the caller opened, at the logical block size and size that `BLKSSZGET` and `BLKGETSIZE64` report, with the caller's `Expected` values, such as the disk GUID that a boot parameter names. It only reads the device, at explicit offsets, so it never moves the file's position. It neither compares the partitions that the kernel created with the table nor asks the kernel to reread the table. Each failure is a typed `DeviceError` |

Lowering functions take the names by which messages refer to their inputs, such
as `EgressRules::name` and `PathList::name`, so callers' messages name their own
Expand Down Expand Up @@ -602,6 +604,8 @@ mount of the host's export and `/` as the roots, and any other guest init or
agent can use them too. Any guest init or agent can also run the steps of
`nvx-time` and `nvx-reseed` in its own process, through the `nvx::guest::time`
and `nvx::guest::reseed` calls, on which both programs run.
Nor is the `gpt` library a program: it reads the partition table of a GPT
disk's block device.

| Binary | Program |
| --- | --- |
Expand Down
12 changes: 6 additions & 6 deletions nvx-rs/src/gpt/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ pub enum GptError {
/// The partition's size, in bytes.
found: u64,
},
/// p1 is larger than the caller's bound.
P1TooLarge {
/// The size of p1, in bytes.
/// The first partition is larger than the caller's bound.
FirstPartitionTooLarge {
/// The size of the first partition, in bytes.
size: u64,
/// The caller's bound, in bytes.
bound: usize,
Expand Down Expand Up @@ -250,7 +250,7 @@ impl fmt::Display for GptError {
Self::PartitionCount(count) => write!(
formatter,
"the disk has {count} partitions, not {MIN_PARTITIONS} through {MAX_PARTITIONS}: \
p1 and at least one layer"
the first partition and at least one layer"
),
Self::Extent {
number,
Expand Down Expand Up @@ -295,9 +295,9 @@ impl fmt::Display for GptError {
formatter,
"partition {number} has {found} bytes, not the expected {expected}"
),
Self::P1TooLarge { size, bound } => write!(
Self::FirstPartitionTooLarge { size, bound } => write!(
formatter,
"p1 has {size} bytes, more than the bound of {bound}"
"the first partition has {size} bytes, more than the bound of {bound}"
),
}
}
Expand Down
Loading
Loading