Gavial 0.1.0-beta.1 release notes

Gavial runs IA-64 (Itanium) operating systems, unmodified, on ordinary x86-64 Linux servers. It emulates an HP Integrity-class server: the guest boots from its own disk through the loader on its EFI System Partition, as it would on hardware. Each guest runs unprivileged in its own Podman container as a systemd service, and the operators you choose manage guests with one command, gctl, without root access.

This is the first beta, an invited release for evaluation. It covers the scope below. Tell us what works and what does not: support@kestosystems.com, and SUPPORT.md describes what to collect.

document for
INSTALL.md preparing a host, installing, the first guest, upgrading
INSTALLING-A-GUEST.md installing an operating system by hand from DVD images
MIGRATING-A-SERVER.md moving a physical HP-UX server into a guest with a recovery tape
GCTL.md gctl, the management tool, and every one of its commands
SUPPORT.md what to collect when something goes wrong
SUBSCRIPTIONS.md the subscription Gavial requires

Scope

in this beta
Guest operating systems HP-UX 11.23 and HP-UX 11.31. Linux: Debian 7 is the version tested.
Guest CPUs One CPU per guest, in the betas and in 0.1.0. A guest moved from a multi-core server runs on one CPU, with no changes inside it. Multi-CPU guests are planned for 1.0.0.
Hosts x86-64 Linux only: Red Hat Enterprise Linux 10 and AlmaLinux 10, on a CPU with AVX2 (x86-64-v3); recommended, AMD EPYC with Zen 3 or Intel Xeon with Golden Cove cores or newer, at 4 GHz or more (INSTALL.md). AlmaLinux 10 is being verified during this beta. Rocky Linux 10 is expected to work but has not been tested. Ubuntu, Debian and other distributions are not supported.
OpenVMS (preview) OpenVMS I64 V8.4 installs from its DVD onto a guest disk, and the installed system boots to a login (INSTALLING-A-GUEST.md). It is a preview: other OpenVMS releases have not been tried.
Guest disks A guest starts from a raw disk image, for example one taken with dd from a real Integrity server, or from a new blank disk onto which you install an operating system by hand from DVD images (ISO files) in the guest's CD drive, changing discs during the install. See INSTALLING-A-GUEST.md. Besides that first disk, a guest can have up to seven data disks (gctl disk).
Guest shutdown gctl shutdown and a host shutdown press the guest's ACPI power button. HP-UX 11.23 and 11.31 handle it as a power failure and do not run their /sbin/rc shutdown scripts (known issue 5). A guest agent that runs the guest's own shutdown -h is planned for 0.1.0, the first release.
Backup Not a Gavial function, by design: back up guests with your storage (array or SAN snapshots of the filesystem that holds /var/lib/gavial) or with the hypervisor that runs the Gavial host (a snapshot or backup of the host VM). Such a snapshot is consistent for a running guest: every write the guest was told is complete is on the host's disk (see "Disk writes survive a host crash" under Highlights), so to the guest a restore looks like a power cut, which its filesystems recover from. That does not hold for a guest set to --disk-sync=off. Back up /etc/gavial/ and /etc/gavial-network.conf at the same time: a guest's settings are there, not with its disks, and a restore needs both from the same moment (GCTL.md lists every path). gctl export keeps a stopped guest as one file.

Highlights

Known issues

  1. Programs run slower for their first minutes. A CPU-bound program started cold, or the first large network transfer into a guest, runs noticeably slower for its first minutes than once it is warm. Time repeated runs, not the first one.

  2. Some workloads are markedly slower than others. Relative to typical workloads, some kinds of computation run much slower under Gavial. Data compression with xz/LZMA is one example. Measure your own workload before you size for it.

  3. Timers in the guest's firmware expire at once. Before the operating system starts, a timer the firmware sets runs out immediately, so a key cannot interrupt the HP-UX loader's autoboot countdown. To reach its HPUX> prompt (for boot -is, say), have Gavial type the command at the next start with gctl args <inst> '--input=\nboot vmunix -is\n': see Typing at the HP-UX loader prompt. (Gavial's own 5-second wait after its splash, before the firmware starts, is a different timer: a key does skip that one.) For a system whose disk will not boot at all, start the guest once from the recovery DVD: gctl start <inst> --boot-from cdrom.

  4. A rollback to a --vmstate snapshot taken more than an hour earlier leaves the guest's clock behind by that time, until NTP or the next boot corrects it. One taken more recently catches up within seconds. (A plain snapshot's rollback leaves the guest stopped, and its next boot takes the host's time.)

  5. The power button does not run the guest's shutdown scripts on HP-UX 11.23 or 11.31 (see Guest notes), which handle it as a power failure. A guest agent that runs the guest's own shutdown is planned for 0.1.0. A guest that does not power off within its shutdown timeout (10 minutes unless set with gctl set <inst> --startup down=SECONDS, or gctl shutdown --timeout) of gctl shutdown, gctl reboot or gctl destroy --keep-disk is powered off hard.

  6. gctl send cannot log in to a guest whose root account has a password. Use gavial-console <inst> --send '<command>' --password-file <file> instead. After send, the console stays logged in as root, and any member of the gavial group can attach to it. See GCTL.md.

  7. Why a snapshot, an import or a live change was refused is only in the system journal, which ordinary group members cannot read by default (gctl names the unit). See INSTALL.md. gctl support includes the journal when the account may read it, and says in its README when it could not.

  8. A long boot with long silences. A boot of an installed system to its login prompt takes from a few minutes (Debian) to about half an hour (HP-UX), depending on the host. The first boot after an HP-UX install from DVD is much longer, hours (INSTALLING-A-GUEST.md). Some boot steps print nothing for minutes. gctl stats <inst> --watch shows that the guest is executing.

  9. The EFI boot settings do not choose what boots. Gavial keeps a guest's EFI boot settings, what setboot shows and changes on HP-UX, and they survive restarts, but its firmware does not use them to choose what to boot: it boots the loader on the guest's own first disk, or the disc or tape that gctl start --boot-from names. So a primary path set to another disk, an alternate path, and setboot -b off change nothing about which device boots (and setboot -b off never leaves a guest waiting at a prompt). To boot from the disc or a tape once, use gctl start --boot-from.

  10. Installing from DVD images has had less use than starting from a disk image. Tell us how an install goes. In this release:

    • By default every guest gets a CD drive, and its disc can be changed while the guest runs. A guest created with --no-cdrom has none, and a drive cannot be added to a running guest: give it one with gctl set <inst> --cdrom <iso> and gctl reboot <inst>.
    • Only ISO 9660 images are accepted (every bootable installation DVD is one).
  11. An image whose clock was set to 2000 ignores the host's time at boot. HP-UX compares the time Gavial supplies with the time recorded in its filesystems. When they are decades apart, as in an image installed while its clock read 2000, it prints time-of-day register time is out-of-range and keeps the filesystem's date. Set the date once inside the guest (date MMDDhhmmYYYY as root); later boots then take the host's time.

  12. Data disks have these limits in this release:

    • A data disk can be added while the guest runs, but it is made, blank or cloned, and the guest sees it, only at the guest's next start: there is no hot-plug. The guest's OS must then be told about it (on HP-UX, ioscan -fnC disk and insf -e). A disk is removed with the guest stopped.
    • gctl disk <inst> remove <N> deletes the disk. Its copies in the guest's snapshots stay, but a rollback never brings a removed disk back.
    • A disk cannot be resized. Give it the size it will need.
    • A Linux guest names disks by the order it finds them, so adding a disk with a lower number can rename the others: mount by UUID= or LABEL=.
    • A guest with data disks can only be migrated to a host whose Gavial has them too; gctl checks before sending anything.
  13. The gvtape package for moving a server into Gavial (MIGRATING-A-SERVER.md) is a beta procedure. On HP-UX 11.23 a recovery image written through it restores to a login, and so does a recovery tape from a physical rx2620's own drive. On HP-UX 11.31 it installs, loads and writes and reads a tape, on a physical rx2620 too, but an 11.31 restore has not been run. Not yet tested: writing a recovery image through it on physical hardware, and the whole procedure in one run from start to finish. Try it on a test server first.

  14. OpenVMS I64 is a preview. From the start of the DVD to the end of the install takes one to two hours, depending on the host, most of it the installer checking the signatures on its kits, and the first boot from the disk runs AUTOGEN and restarts once. OpenVMS has not yet been tried with more than one network adapter. A large read can occasionally fail with %SYSTEM-F-CTRLERR, fatal controller error, after which OpenVMS runs mount verification on the disk; repeating the command usually succeeds. Seen when reading big library files (for example with LIBRARY/EXTRACT).

  15. dnf remove gavial prints a warning about /var/lib/gavial when that directory is a filesystem of its own, as step 1 of INSTALL.md recommends: warning: directory /var/lib/gavial: remove failed: Device or resource busy. It is harmless. The directory is meant to stay: it holds your guests' disks, and the removal says so on the next lines.

  16. dnf remove gavial leaves an empty /usr/share/gavial directory. It is harmless; remove it with sudo rmdir /usr/share/gavial if you wish.

  17. An idle HP-UX guest keeps one host core busy. When a guest's operating system tells the processor it has nothing to do, the host core rests too. Linux does this, so an idle Linux guest costs the host little. HP-UX 11.23 and 11.31 do not, so an HP-UX guest at its login prompt, with nothing running, uses about one host core, as a busy one does: plan one core for each HP-UX guest (INSTALL.md). The default, --idle=pal, rests the host core only when the guest asks the processor to halt, which Linux does and HP-UX does not. gctl args <inst> --idle=sleep also guesses from what the guest executes that it is idle, so an idle HP-UX guest uses about an eighth of a core instead; it takes effect on a running guest at once. But that guess is wrong for a busy guest whose work is mostly inside its operating system's kernel (many processes starting, heavy system-call use), which then runs slower, in our tests up to about eight times. Use it only for guests that are mostly idle. To return to the default: gctl args <inst> --remove --idle (the other flags stay as they were).

  18. A Linux guest logs Oops: timer tick before it's due a few times after boot. For about the first ten minutes after a Debian guest boots, its kernel occasionally reports a timer interrupt that arrived a hair before the clock it reads had reached the deadline (itc equals itm in the message), about once every forty seconds, then stops. The guest's clock is unaffected: over 24 hours of measurement it stayed within milliseconds of the host's, busy and idle. The lines are console noise, to be removed in a later release; HP-UX guests do not print them.

Good to know

These are not problems, but they can surprise someone used to another platform:

Guest notes

HP-UX 11.23 and 11.31

Linux (Debian 7)

Installing Gavial

This guide takes a Linux host from nothing to a running IA-64 guest. You need root on the host for steps 1 to 7. From step 8 on, any member of the gavial group can do the work without sudo.

For what this beta supports, read the release notes first. For every gctl command, see GCTL.md. To install a guest's operating system from DVD images rather than start from a disk image, see INSTALLING-A-GUEST.md after step 7.

Requirements

requirement
operating system Red Hat Enterprise Linux 10, x86-64. AlmaLinux 10 uses the same package and is being verified during this beta. Rocky Linux 10 is expected to work but has not been tested. Ubuntu, Debian and other distributions are not supported.
CPU Minimum: x86-64-v3 (AVX and AVX2, with FMA, BMI1/BMI2, F16C, LZCNT and MOVBE): Intel Xeon E5 v3 ("Haswell", 2014), AMD EPYC 7001 (2017) or newer. Gavial does not start without it, and gctl doctor checks it. Recommended for good guest performance: see Recommended CPUs.
container engine Podman 4.0 or later, rootful. The package installs it as a dependency.
service manager systemd, with cgroup v2 (the default)
guest storage /var/lib/gavial on one XFS filesystem with reflink, or on btrfs. ext4 does not work.
network a Linux bridge for the guests, created by you (see step 5)
storage tools lvm2, installed as a dependency. The package suggests, but does not install, device-mapper-multipath, lvm2-lockd and sanlock, for shared SAN storage in a later release.
snapshots with the running state criu, for snapshots with the running state (gctl snapshot --vmstate). The package recommends it, and dnf installs recommendations by default.

Rootful Podman, unprivileged guests. Podman runs as root, so that one copy of the Gavial runtime serves every user on the host. Inside each guest's container, the emulator runs as an unprivileged user (uid 10001) with every capability dropped, no-new-privileges, a read-only image and the guest's own network namespace.

AlmaLinux 10 uses the same package, the same repository, the same setup package and the same steps as RHEL 10, and is being verified during this beta. Where this guide says RHEL, it means both. AlmaLinux also ships a build for older CPUs (x86-64-v2); Gavial still needs an x86-64-v3 CPU, whichever build the host runs.

The CPU check. The Gavial runtime needs AVX2. On a physical host this is the CPU model. In a virtual machine it is the CPU type the hypervisor presents, and many hypervisors hide AVX2 by default. Set the VM's CPU type to host or x86-64-v3. To check:

/lib64/ld-linux-x86-64.so.2 --help | grep 'x86-64-v3'

The line must say supported. Gavial is an emulator, not a hypervisor, so a host VM does not need nested virtualization.

Each guest's processor runs on one host core at a time, so a guest is as fast as one core of the host is. What matters is the speed of a single core: its generation and its highest clock speed, more than how many cores the host has.

absolute minimum x86-64-v3: the AVX and AVX2 instructions, with FMA, BMI1/BMI2, F16C, LZCNT and MOVBE. Intel Xeon E5 v3 ("Haswell") or AMD EPYC 7001 or newer. Without them Gavial does not start; for a virtual machine, see "The CPU check" above.
recommended, AMD EPYC with Zen 3 cores or newer (EPYC 7003 "Milan", 9004 "Genoa", 4004 and later) in a high-clock model, 4 GHz or more maximum clock: for example the AMD EPYC 74F3. Measured on Zen 3.
recommended, Intel Xeon with Golden Cove cores or newer, expected to perform about as well per core as Zen 3: 4th-generation Xeon Scalable ("Sapphire Rapids") and later, Xeon 6 with P-cores ("Granite Rapids"), 4 GHz or more maximum clock. Not yet tested.

Sizing. These measurements are a starting point for your own:

1. Prepare the storage

Do this before you install the package. The package creates its directories under /var/lib/gavial with particular owners and permissions, and a filesystem mounted over them afterwards would hide them.

Everything under /var/lib/gavial must be on one filesystem. Guest disks, snapshots and imports are reflink copies: instant, and sharing space until written. A reflink cannot cross from one filesystem to another.

The package checks this before it installs anything. A first install stops and says what is wrong when the filesystem that holds /var/lib/gavial is not XFS with reflink or btrfs, when a reflink copy fails in it, when /var/lib/gavial is listed in /etc/fstab but not mounted, or when it is on a mount that is not in /etc/fstab. Fix that and install again. An upgrade only warns, so it never stops a host that runs guests.

If the filesystem that holds /var/lib is already XFS with reflink, or btrfs, there is nothing to do. A default RHEL install uses XFS with reflink. To check:

df --output=fstype,target /var/lib
xfs_info "$(findmnt -n -o TARGET --target /var/lib)" | grep -o 'reflink=[01]'

(xfs_info takes a mount point, so the second command asks for the one that holds /var/lib: on a default RHEL install that is /.)

Otherwise, give /var/lib/gavial its own XFS filesystem. This example uses a spare disk, /dev/sdX. Replace it with yours: mkfs erases the disk.

sudo mkfs.xfs -m reflink=1 /dev/sdX
sudo mkdir -p /var/lib/gavial
echo "UUID=$(sudo blkid -s UUID -o value /dev/sdX) /var/lib/gavial xfs defaults 0 0" | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount /var/lib/gavial
xfs_info /var/lib/gavial | grep -o 'reflink=[01]'

The last command must print reflink=1. Put every mount in /etc/fstab: a mount made by hand disappears at the next reboot, and gctl doctor reports it as a failure.

Podman keeps Gavial's runtime image under /var/lib/containers. Make sure that filesystem has at least a few GB free. After an upgrade, the previous version's image stays there until no guest uses it.

If you installed the package before preparing the storage, reinstall it after mounting (sudo dnf reinstall gavial) to recreate its directories.

2. Add the package repository

The repository is https://packages.kestosystems.com. It serves packages over HTTPS, and only to subscribers: dnf sends your subscription token as the repository password. Its certificate is a public one, so the host's own trust store checks it and nothing extra is installed for it. Your beta invitation contains the rest of what this step needs:

The repository and every package in it are signed by Gavial's release key:

40B1 C6DE 95F3 F5C0 64C7  AF9B 654F A615 B821 3BFE

Accept a key only if its fingerprint is this one. It is also in your invitation, so you can compare the two.

With the setup package

Your invitation includes Gavial's setup package, gavial-0~setup-1.el10.x86_64.rpm. Check its SHA-256 against the invitation, then install it, giving the full path of your token file in GAVIAL_TOKEN_FILE:

sudo GAVIAL_TOKEN_FILE=$PWD/token.txt dnf install ./gavial-0~setup-1.el10.x86_64.rpm

Before it installs anything it checks the token with the repository, and it refuses a token that is missing or not accepted. It then writes the configuration shown below, installs the token as the host's subscription (/etc/gavial/subscription, as gctl subscription set does), and prints the next command. It does not change or delete token.txt. Gavial itself is installed by an upgrade, ready to run guests:

sudo dnf upgrade gavial

Until then, gctl and the other Gavial commands only print that command.

By hand

Fetch the release key from the repository (your token is the password), and check its fingerprint against the one above before you install it. The token reaches curl on its standard input, so it never appears in the list of running processes:

sed -e '/^#/d' -e '/^[[:space:]]*$/d' -e 's/.*/user = "ANY-NAME:&"/' token.txt | curl -fsS -K - -o RPM-GPG-KEY-gavial https://packages.kestosystems.com/keys/gavial-release.asc
gpg --show-keys RPM-GPG-KEY-gavial
sudo install -m 0644 RPM-GPG-KEY-gavial /etc/pki/rpm-gpg/RPM-GPG-KEY-gavial

The repository file holds your token, so it stays mode 0600:

sudo install -m 0600 /dev/null /etc/yum.repos.d/gavial.repo
sudoedit /etc/yum.repos.d/gavial.repo
[gavial]
name=gavial
baseurl=https://packages.kestosystems.com/el10/x86_64/
enabled=1
username=ANY-NAME
password=YOUR-TOKEN
repo_gpgcheck=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-gavial
metadata_expire=5m

username can be any name without spaces. The server logs it, so the host's name is a good choice.

sudo dnf makecache --repo gavial
sudo dnf info gavial

The repository's metadata is signed (repo_gpgcheck=1), and so is every package (gpgcheck=1), both by the release key. dnf asks you to accept the key the first time it reads the repository. Accept it only if the fingerprint matches.

If dnf reports 401 Unauthorized or 403 Forbidden, see SUBSCRIPTIONS.md. When you renew your subscription, sudo gctl subscription set puts the new token in the repository configuration too.

3. Install the package

sudo dnf install gavial

Straight from the package file

If you were sent the Gavial package itself, install it directly instead of steps 2 and 3. Check its SHA-256 against the one you were sent with it, then install it, giving the full path of your token file in GAVIAL_TOKEN_FILE:

sudo GAVIAL_TOKEN_FILE=$PWD/token.txt dnf install ./gavial-0.1.0~beta.1-1.x86_64.rpm

It does what the setup package does, and installs Gavial in the same step: it checks the token with the repository, writes the repository configuration of step 2 (so that sudo dnf upgrade gavial works later), and installs the token as the host's subscription after checking it on the host. It does not change or delete token.txt.

No internet access is needed. If the host cannot reach the repository, the package says so, writes its configuration anyway, and installs normally: the subscription is checked on the host, and the Gavial runtime is inside the package. Its dependencies (Podman, LVM and the others) come from the host's own RHEL or AlmaLinux repositories, which can be a local mirror or the installation DVD. A token that does not pass the check changes nothing, and the package tells you why; the install itself goes ahead. With a valid token file, run the install again as dnf reinstall, with GAVIAL_TOKEN_FILE, as the message says: that connects the repository and installs the subscription.

The package:

The package contains no guest disk images. You add those in step 8.

4. Let users manage guests

Membership of the gavial group is what lets a user manage guests: create, start, stop, snapshot, attach to consoles, move to another host. No sudo is involved. Add each operator:

sudo usermod -aG gavial alice

The user must log out and back in for the membership to take effect. Check with:

id -nG

Note: group members can attach to every guest's console, so they are effectively the guests' console operators. Add only people you would give that access.

When a start is refused, gctl start and gctl status show the reason to any group member. When the host does not let a user start one of Gavial's services at all (not in the group in this login, or the package's permission rule missing), gctl says permission denied and why. Why a snapshot, an import or a live change was refused is only in the system journal, which a group member cannot read by default. If your operators should see those reasons themselves, also add them to the systemd-journal group, which lets them read the whole system journal.

5. Network bridges

Guests are bridged. Each guest network adapter is a port on a Linux bridge that you create on the host, typically on a network interface dedicated to guests. The bridge passes raw Ethernet frames: any protocol, broadcast and multicast, and the guest's own MAC address. An adapter can be put in one VLAN, untagged towards the guest, or be a VLAN trunk that carries several VLANs tagged to the guest. Gavial filters nothing and assigns no addresses. Each guest sets its own IP address, and network segmentation is your network firewall's job.

Create the bridge with NetworkManager, so that it survives a reboot. This makes a bridge br1 with the interface eth1 as its uplink; the bridge has no address of its own:

sudo nmcli connection add type bridge con-name br1 ifname br1 bridge.stp no ipv4.method disabled ipv6.method disabled
sudo nmcli connection add type ethernet con-name br1-uplink ifname eth1 port-type bridge controller br1
sudo nmcli connection up br1

If guest adapters will use VLANs (--vlan) or trunks (--trunk), the bridge must be VLAN-aware, and its uplink must carry every VLAN a guest uses, tagged: each access VLAN and each VLAN of each trunk. Gavial sets up the guests' ports on the bridge; the uplink port is yours. For guests using VLAN 100 (access) and a trunk of VLANs 10, 20 and 30, create the two connections with these settings instead:

sudo nmcli connection add type bridge con-name br1 ifname br1 bridge.stp no bridge.vlan-filtering yes ipv4.method disabled ipv6.method disabled
sudo nmcli connection add type ethernet con-name br1-uplink ifname eth1 port-type bridge controller br1 bridge-port.vlans "10, 20, 30, 100"
sudo nmcli connection up br1
bridge vlan show dev eth1          # eth1 lists 1 (PVID, untagged), 10, 20, 30, 100

(bridge-port.vlans "10-30, 100" gives a range at once. To change the list later: sudo nmcli connection modify br1-uplink bridge-port.vlans "...", then sudo nmcli connection up br1-uplink.) The switch port that eth1 is plugged into must be a trunk carrying the same VLANs tagged. A frame in a VLAN the uplink does not carry reaches the bridge and goes no further, with no error anywhere. To see which VLANs a guest's own port carries, run bridge vlan show on the host while the guest runs: Gavial's ports are the ones named gv...h.

Do not give guests the bridge the host itself is managed through.

One VLAN on an interface the host also uses. When guests need a single VLAN that arrives tagged on the host's own interface (here eno1, VLAN 4), make a VLAN interface of it the bridge's only uplink. The host's own connection on eno1 is not touched; the bridge has no address of its own:

sudo nmcli connection add type bridge con-name br4 ifname br4 bridge.stp no ipv4.method disabled ipv6.method disabled
sudo nmcli connection add type vlan con-name br4-uplink ifname eno1.4 vlan.parent eno1 vlan.id 4 port-type bridge controller br4
sudo nmcli connection up br4

Guest adapters on br4 are then in VLAN 4, untagged towards the guest, with no --vlan needed. The switch port must carry VLAN 4 tagged.

If the host is itself a virtual machine, its hypervisor must let the guests' MAC addresses through the host's network adapter: turn off any MAC filtering or MAC spoofing protection on that adapter. For VLANs and guest trunks, the adapter must also carry those VLANs tagged: no VLAN tag on the adapter itself, and a VLAN-aware virtual switch whose VLANs include them.

Allow the bridge. /etc/gavial-network.conf lists the bridges that guests may join, separated by commas. The first bridge is where an adapter that names no bridge goes. The file must be owned by root and writable by root only. A commented example is installed at /usr/share/gavial/gavial-network.conf.example.

echo 'GAVIAL_BRIDGES=br1' | sudo tee /etc/gavial-network.conf
sudo chmod 0644 /etc/gavial-network.conf

Without this file, guests still get their network adapters, but the adapters are connected to nothing.

Keep the host firewall out of bridged traffic. If the br_netfilter kernel module is loaded, bridged guest frames pass through the host's own firewall rules. Turn that off, and keep it off across reboots:

sudo tee /etc/sysctl.d/90-gavial-bridge.conf >/dev/null <<'EOF'
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-ip6tables = 0
EOF
sudo sysctl --system

A sysctl.d file is applied at boot, and these two settings exist only while the br_netfilter module is loaded. If something loads it later (container tools often do), both come up as 1 and bridged guest traffic goes through the host's firewall again. This udev rule applies them each time the module loads:

echo 'ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/net/bridge"' | sudo tee /etc/udev/rules.d/99-gavial-bridge.rules
sudo udevadm control --reload

Gavial connects each adapter to its bridge with the kernel's traffic-control modules sch_ingress, cls_matchall and act_mirred. gctl doctor checks that they are available. If one is missing, install your kernel's extra modules package.

6. Install your subscription

Gavial requires a subscription to run guests: the token you gave the repository in step 2. The setup package has already installed it, and so does a direct install with GAVIAL_TOKEN_FILE (step 3), so on such a host there is nothing to do here. On a host whose repository you set up by hand, install it once, as root:

sudo gctl subscription set /path/to/token.txt

Check it with gctl subscription get (no root needed), and remove it with sudo gctl subscription delete. SUBSCRIPTIONS.md explains what a subscription is and how to install and renew it. A renewal is the same sudo gctl subscription set: it also replaces the token in the repository configuration from step 2.

7. Check the host

sudo gctl doctor

The doctor checks the CPU, Podman, the Gavial services and image, polkit and the group, the storage and its mounts, free space, the bridges and firewall settings, SELinux, the subscription and the guests defined, and changes nothing. Each problem is marked FAIL or WARN with the fix on the next line. Fix every FAIL before you go on. Run as an ordinary group member (without sudo), it skips the checks that need root.

SELinux stays enforcing: Gavial works with it.

8. Import a disk image and create a guest

From here on, work as a member of the gavial group.

A guest runs from a raw disk image, the format dd produces. It can be a disk imaged from a real Integrity server, or one you were supplied. An image in another format must be converted to raw first, for example a qcow2 or VMDK file with qemu-img (from the qemu-img package):

qemu-img convert -O raw disk.qcow2 disk.raw

No disk image? Install the operating system by hand instead, from its installation DVDs as ISO files, onto a new blank disk: INSTALLING-A-GUEST.md walks through it, changing discs included.

Gavial boots the loader it finds on the image's EFI System Partition: \EFI\HPUX\HPUX.EFI, otherwise \EFI\BOOT\BOOTIA64.EFI, otherwise the one EFI application in a directory under \EFI. If there are several such applications and neither of the first two, Gavial refuses to guess and the guest does not start. gctl start says why.

Check the image against the sha256 you were given:

sha256sum /srv/images/web1.raw

Import it and create a guest in one step:

gctl import /srv/images/web1.raw web1 --memory 2048 --bridge br1

This copies the image into the image store as web1 and defines a guest web1, with 2048 MB of memory and its first network adapter on br1. The copy shows its progress. If the file is already on the same filesystem as /var/lib/gavial, the copy is instant. Add --vlan N to put the adapter in a VLAN, or --trunk N,N,... to carry several VLANs tagged to the guest (see GCTL.md).

To make several guests from one image, add the image once and create each guest from it:

gctl importdisk /srv/images/base.raw base
gctl create web2 base --memory 2048
gctl create web3 base --memory 2048

Each guest gets its own disk, cloned from the image at its first start, and keeps it from then on.

A guest can also have up to seven data disks beside that one, each a new blank disk or a clone of another image, made at its next start:

gctl disk web1 add 1 --size 100G

Note: each data disk answers on a SCSI target fixed by its number for the life of the guest (disk 1 is target 1, disk 2 is target 3, and so on), because HP-UX names a disk by its hardware path. See GCTL.md.

To add network adapters (up to four), change memory, or pass extra flags, see GCTL.md.

A disk imaged from real hardware

An operating system installed on a real server may look for its devices at the hardware paths they had on that server: the boot disk's controller, the console port, the first network adapter. If Gavial presents them somewhere else, the guest can fail to find its root disk or its console. It may report this as a volume-manager or root-mount error, even though the disk is fine.

Gavial can place each device where the installed system expects it. For a disk imaged from an HP Integrity rx2620's internal drive bay, set these flags before the first start:

gctl args web1 --mpt-path=0/1/1/1 --disk-target=2 --pci-console=0/6/1/0 --nic-path=0/1/2/0

With these flags the boot disk is target 2, as in the server's bay. The CD drive stays on its own target, 15.

The server's EFI boot settings do not come with the disk: the guest's first boot makes a boot entry for the disk it boots from, so setboot shows a primary boot path. Set an alternate path, or any other boot setting the server had, with setboot as on the server; the settings are kept, but do not yet choose what boots (known issue 9 in the release notes).

For another server model, contact support (support@kestosystems.com) with the original system's hardware listing.

9. Start the guest and attach to its console

gctl start web1 --console

This starts the guest and attaches your terminal to its serial console, so you watch the boot. Ctrl-] detaches and leaves the guest running. To attach again at any time:

gctl terminal web1

You do not miss the boot by attaching late: the console replays its most recent output (up to about 1 MB) first.

A boot takes a while. A boot of an installed system to its login prompt takes from a few minutes (Debian) to about half an hour (HP-UX), depending on the host. The first boot after an HP-UX install from DVD is much longer, hours: see INSTALLING-A-GUEST.md. Some steps of a boot run for minutes with no console output. To see that the guest is executing:

gctl stats web1 --watch

A new sample every 10 seconds means the guest is running.

Once the guest is up, configure its network address inside the guest, as you would on the real server. Its first network adapter is adapter 0 in gctl nic web1.

To shut the guest down:

gctl shutdown web1

gctl shutdown presses the guest's power button. HP-UX 11.23 and 11.31 handle that as a power failure: their processes get SIGTERM and 10 seconds, and their /sbin/rc shutdown scripts do not run. For those scripts, shut HP-UX down from inside (shutdown -h -y 0). gctl stop is a hard power-off. See GCTL.md for the difference and its consequences.

Starting guests when the host boots

Mark a guest to start when the host boots, and give it a place in the start order:

gctl set db1 --onboot yes --startup order=1,up=60     # first, then wait 60 s
gctl set web1 --onboot yes --startup order=2
gctl set db1 --startup order=1,up=60,down=1800        # and give it 30 min to shut down
gctl set web1 --onboot no                             # no longer on boot

At boot, the gavial-onboot service starts every marked guest, the lowest order first; guests without an order start after the ordered ones, by name. up= is how many seconds to wait after a guest starts before the next one (for example, to let a database come up before its application servers). Members of the gavial group set this; no root access is needed. A guest that was migrated to another host is never started, and one that fails to start does not stop the others: journalctl -u gavial-onboot lists what happened.

The package enables the gavial-onboot service. To turn start on boot off for the whole host: sudo systemctl disable gavial-onboot.

When the host shuts down, systemd stops each running guest the way gctl shutdown does: it presses the power button and waits up to the guest's shutdown timeout, down= (10 minutes unless set; at most an hour). The guests are stopped at the same time, not one after another: the start order (order=, up=) applies only to starts. Host shutdown can therefore take as long as the longest of the guests' shutdown timeouts. This includes the hypervisor's "Shut Down" button when the host is itself a virtual machine. For an HP-UX 11.23 or 11.31 guest this is the power-fail path described in step 9: no shutdown scripts run. (Measured on the reboot of a host that is itself a virtual machine: an HP-UX 11.31 guest synced its disks and powered itself off in 2 minutes.)

Before host maintenance, shut down from inside any HP-UX guest whose applications need their own shutdown scripts: as root in the guest, shutdown -h -y 0. The guest powers off and its service ends; start it again afterwards with gctl start <inst>. The same applies before gctl reboot and before removing Gavial.

Upgrading

sudo dnf upgrade gavial

An upgrade does not stop running guests. Each running guest keeps the Gavial version it started with, and the upgrade names them:

gavial: guest web1 keeps running the previous version until it restarts (gctl reboot web1)

To move a guest to the new version, restart it from gctl when convenient:

gctl reboot web1

gctl reboot shuts the guest down with the power button, so for an HP-UX guest whose applications need their shutdown scripts, shut it down from inside first (shutdown -h -y 0) and then gctl start it.

A reboot from inside the guest restarts it in place on the version it is already running. Only gctl reboot, or a gctl shutdown followed by gctl start, moves it to the new version. To see which version each running guest uses, and which ones wait for a restart:

gctl versions

The previous version's runtime image is kept while a guest still runs on it. It is removed at the next package install or upgrade after no guest uses it.

Removing Gavial

sudo dnf remove gavial

Removing the package shuts down every running guest first, each with the power button. This can take several minutes. It removes Gavial's runtime image, but not /var/lib/gavial, which holds your guests' disks, snapshots and images. Delete that yourself when you no longer need them.

Your configuration stays as well, so that a reinstall finds it. dnf remove gavial leaves:

To remove Gavial completely, delete those too and run sudo groupdel gavial. Export first any guest you want to keep (gctl export <inst> FILE).

Installing a guest from DVD

This guide installs an operating system by hand onto a new, blank guest disk, from the installation DVDs as ISO image files, the way you would on a real server with a DVD drive. The example installs HP-UX 11.23 from two DVDs, including the change to the second disc part-way through.

Any member of the gavial group can do all of it, without sudo. The host must be set up first (INSTALL.md, steps 1 to 7). For every command used here, see GCTL.md.

Installing from DVD images has had less use than starting from a disk image. See known issue 10 in the release notes.

What you need

1. Import the DVD images

Add each disc to the host's ISO store under a short name:

sha256sum /srv/iso/hpux-1123-dvd1.iso /srv/iso/hpux-1123-dvd2.iso
gctl importiso /srv/iso/hpux-1123-dvd1.iso hpux-dvd1
gctl importiso /srv/iso/hpux-1123-dvd2.iso hpux-dvd2
gctl isos
  hpux-dvd1                    4.2 GiB
  hpux-dvd2                    3.9 GiB

importiso works like importdisk: the file is copied into /var/lib/gavial/incoming/ with its progress shown, then a root service moves it into the store and checks it. From the same filesystem the copy is instant. Every guest on the host can use the ISOs in the store, and several guests can use the same one at the same time.

2. Create a guest with a blank disk

Give create a disk size instead of an image, and put the first disc in its drive:

gctl create hpux1123 --disk-size 40G --cdrom hpux-dvd1 --memory 2048 --bridge br1
created hpux1123 (a blank 40G disk, 2048MB, hpux-dvd1 in its CD drive); start it with: gctl start hpux1123 --console

The disk itself is made at the guest's first start.

Install onto this one disk. A separate disk for a data volume group is added after the install, with gctl disk hpux1123 add 1 --size 100G (a data disk can be added before the first start too, and is made at that start, but an install with data disks attached has not been tested). Data disk N always has its own fixed SCSI target (disk 1 on target 1, disk 2 on target 3; the table is in GCTL.md), so the hardware paths the installed system records stay valid when disks are added later.

3. Start it and attach to its console

gctl start hpux1123 --console

Gavial boots the guest's disk when the disk has a loader on it, and otherwise the disc in the drive. A blank disk has none, so the guest boots the DVD. The console shows gavial: the disk has no loader -- booting the CD, then HP's loader reads the DVD's AUTO file and starts the installer by itself after its autoboot countdown:

AUTO ==> boot :IINSTALL
Seconds left till autoboot -     10  9  8  7  6  5  4  3  2  1  0
AUTOBOOTING...

On Gavial this countdown runs out at once and a key cannot stop it (unlike Gavial's own 5-second wait after its splash, earlier): the guest firmware's timers expire as soon as they are set (known issue 3 in the release notes). The installer starts by itself, which is all an install needs. (To type at the loader's HPUX> prompt later, for a single-user boot, see Typing at the HP-UX loader prompt.)

(Or start the guest with gctl start hpux1123 and attach later with gctl terminal hpux1123; the console replays what you missed.) Ctrl-] detaches and leaves the guest running.

Answer the installer's questions as you would on a real server, and install onto the guest's blank disk, the only disk the guest has; data disks come after the install (gctl disk <inst> add, step 5).

An installation takes hours under Gavial, and some of its steps print nothing for a long time. HP-UX waits for every disk write to reach the host's disk; to skip that while installing, add --disk-sync=off to the guest's flags before the first start, and take it out once the system is installed; the guest's other flags stay as they were (see GCTL.md):

gctl args hpux1123 --add --disk-sync=off       # before the first start
gctl args hpux1123 --remove --disk-sync        # once the system is installed

To see that the guest is working:

gctl stats hpux1123 --watch

A new sample every 10 seconds means it is executing.

4. Change to the second disc

When the installer asks for the next disc, leave it waiting and, from a second shell on the host, put that disc in the drive:

gctl set hpux1123 --cdrom hpux-dvd2
inserted hpux-dvd2 into hpux1123 (live)

The disc changes at once, in the running guest. Then go back to the console and answer the installer's prompt (usually by pressing Return) so it reads the new disc. If you had detached, gctl terminal hpux1123 attaches again.

gctl set --cdrom also saves the choice for the guest's next start, so a reboot keeps the same disc in the drive.

5. After the install

At the end, the installer reboots the guest. This is a reboot inside the guest; the guest's service keeps running. The disk now has a loader, so the guest boots from its disk, even though a disc is still in the drive. Let this first boot finish: it configures the new system and then reboots it once more. The second boot asks the system's first-time questions (host name, time zone, root password and network), as on a real server, and then gives you a login prompt.

The first boot takes hours under Gavial, and most of it is one step: the console prints CIM Repository is being built - please be patient and then nothing for a long time while HP-UX compiles its management repository. Measured for HP-UX 11.23 from the September 2004 DVD with Ignite's defaults, through gctl on a RHEL 10 host with a Zen 3 core at 4.4 GHz (see Recommended CPUs), with five other guests running on the host: the install 2 hours 58 minutes, then the first boot 3 hours 32 minutes. A slower core takes longer. The guest is working, not stuck: gctl stats <inst> --watch shows it executing. Do not reset the guest during this step.

Then take the disc out:

gctl set hpux1123 --cdrom none
ejected the disc from hpux1123 (live)

The drive stays, empty, for a later disc (patches, more software). To remove the drive itself from the guest's next start:

gctl set hpux1123 --delete cdrom

The boot settings. Gavial keeps the guest's EFI boot settings, what setboot shows and changes on HP-UX, as a server's NVRAM does. When none of them points at the disk the guest boots from (one just installed, or one whose disk moved to another SCSI target), its next boot adds an entry for that disk first in the boot order and keeps the others, so setboot shows a primary boot path and setboot -b on|off and setboot -p work as on a server. The settings are kept, but they do not yet choose what boots: the guest boots the loader on its own disk, or the disc or tape that gctl start --boot-from names (known issue 9 in the release notes). The settings are part of every snapshot, and travel with clone, export, import and migrate (see GCTL.md).

Keep a snapshot of the freshly installed system, to come back to:

gctl shutdown hpux1123
gctl snapshot hpux1123 installed
gctl start hpux1123

Installing OpenVMS I64 (preview)

OpenVMS I64 V8.4 installs from its DVD the same way: import the ISO, create a guest with a blank disk and the disc in its drive, and start it with its console attached.

OpenVMS is a preview in this beta. It has been installed from the V8.4 DVD and booted from its disk; other releases have not been tried. From the start to the end of the install takes one to two hours, depending on the host, most of it the installer checking the signatures on its kits. A large read can occasionally fail with CTRLERR (see known issue 14 in the release notes).

gctl importiso /srv/iso/OpenVMS-I64-V84.iso openvms-v84
gctl create vms1 --disk-size 40G --cdrom openvms-v84 --memory 2048
gctl start vms1 --console

The DVD boots to the installation menu:

Please choose one of the following:
    1)  Upgrade, install or reconfigure OpenVMS I64 Version V8.4
    ...
Enter CHOICE or ? for help: (1/2/3/4/5/6/7/8/9/?)

Choose 1, then:

The installer asks Answer
INITIALIZE or to PRESERVE? INITIALIZE (a blank disk)
Enter device name for target disk DKA0, the guest's first disk
Enter volume label your choice; the default is I64SYS
ODS-2 or ODS-5? 5
create or validate boot options? No: Gavial boots \EFI\VMS\VMS_LOADER.EFI from the disk by itself
Password for SYSTEM account your choice
member of an OpenVMS Cluster? No
SCSNODE, SCSSYSTEMID, DECnet your choice
the time zone, the TDF your choice
register any Product Authorization Keys? your licences, now or later
the optional products your choice; TCP/IP Services gives the guest networking

When the install has finished and the menu comes back, choose 9 to shut the system down. OpenVMS does not power the guest off: it stops at SYSTEM SHUTDOWN COMPLETE and P00>>>. Power it off then (the system is already shut down), empty the drive, and start the guest again: it boots from its disk.

gctl stop vms1
gctl set vms1 --cdrom none
gctl start vms1 --console

The first boot from the disk runs AUTOGEN and restarts the system by itself; the second boot comes up for good. Press Return on the console for the Username: prompt. Without licences loaded, OpenVMS allows logins on the console only.

The installed system answers the power button: gctl shutdown vms1 runs an orderly OpenVMS SHUTDOWN and powers the guest off. HP-UX 11.23 and 11.31 differ: they treat the button as a power failure and run no shutdown scripts; see GCTL.md.

Making more guests from the installed system

A snapshot is readable by the gavial group, so it can become an image in the image store, from which gctl create makes new guests in seconds:

gctl importdisk /var/lib/gavial/snapshots/hpux1123/installed.raw hpux1123-base
gctl create web1 hpux1123-base --memory 2048

Each new guest is then a copy of the installed system, including its host name and network settings: change those inside each guest.

installed.raw is the first disk. If the guest has data disks, the snapshot holds each as installed.disk<N>.raw: import those too and give each new guest the same disk numbers, so every disk is on the target the installed system expects:

gctl importdisk /var/lib/gavial/snapshots/hpux1123/installed.disk1.raw hpux1123-base.disk1
gctl disk web1 add 1 --image hpux1123-base.disk1

When something goes wrong

what you see what it means
... is running WITHOUT a CD drive ... a drive cannot be added while it runs The guest was created with --no-cdrom, and a drive cannot be added while it runs. The drive is saved for its next start: gctl reboot <inst>.
the running guest's disc was NOT changed The change was refused; the reason is in the journal of the service named in the message (journalctl -u gavial-cdrom@...). The setting is saved for the next start either way.
no ISO '...' in the store Import it first (gctl importiso), or check the name with gctl isos.
... is not an ISO 9660 image The file is not a disc image in ISO 9660 format (for example, a raw disk image: those are gctl importdisk).
The guest does not start after create --cdrom ... An ISO that is not in the store stops the start. gctl doctor names such guests. gctl start prints why a start was refused, and gctl status <inst> shows it later.
disk N is SCSI target T, which GAVIAL_ARG=--cdrom-target=T gives the CD drive The guest's extra flags moved its drive onto a data disk's target. Move the drive to the free target the message names.
The guest boots the DVD again after the install The install did not put a loader on the disk. Check the installer's log on the console.

To delete an ISO from the store when the install is done, use gctl deliso <name>. It is refused while a guest still has that ISO in its drive (gctl set <inst> --cdrom none takes it out).

gctl: the management tool

gctl is Gavial's management tool: it manages the guests on one host, from creating them to their consoles, disks, snapshots and migration. This page covers every one of its commands in the first beta (0.1.0-beta.1). It follows the gctl shipped in the package, and gctl help prints the same commands in brief.

Before you start

The words. A guest is an emulated server with its own disks; gctl calls one an instance where it names it (<inst>). An image is a disk image in the host's store from which guests are created; the Gavial runtime image is the Podman container image the package installs, which every guest runs in. A disk is a guest's hard disk; a disc is what is in its CD drive (an ISO file). A guest is running or stopped (gctl list); migrated means it was moved to another host and stays down here.

Who can run it. Any member of the gavial group can run gctl, without sudo. Gavial has no daemon, and gctl is not setuid. Each guest is a systemd service, gavial@<inst>, and the package's polkit rule lets the gavial group start and stop Gavial's own services and nothing else. Every start is checked by a root-side validator before the guest runs. If you are not in the group, gctl warns you and privileged actions are refused. To add a user, see INSTALL.md.

Tab completion. The package installs bash completion for gctl (/usr/share/bash-completion/completions/gctl): Tab completes the commands and their options, and the names on this host: guests, images, ISOs, a guest's snapshots, its disk and adapter numbers, and the Gavial flags gctl args accepts. A new shell picks it up (it needs the bash-completion package, which is usually installed).

Names.

allowed characters notes
guest (instance) A-Z a-z 0-9 _ - images, incoming, snapshots, iso, tape and checkpoints are reserved (directories of the store)
snapshot A-Z a-z 0-9 _ -
disk image A-Z a-z 0-9 _ . - a bare name, never a path
ISO A-Z a-z 0-9 _ . - a bare name, never a path; not none (the empty drive)

Why a command was refused. A bridge this host does not allow is refused when you type it (create, import, nic), with the bridges it does allow. So is any bridge while /etc/gavial-network.conf itself is malformed (for example GAVIAL_BRIDGES separated by spaces, not commas): the refusal gives the validator's own reason, e.g. /etc/gavial-network.conf: line 1: not a bridge name, and until the administrator fixes the file no guest starts. When a start is refused, gctl start prints the reason, and gctl status shows it later: how it ended: ... and the validator's own words. You do not need to read the system journal for that. When the validator refuses a snapshot, an import or a live change, the reason is only in the system journal: gctl names the unit to look at (for example journalctl -u gavial-disk@web1). By default only root and members of the systemd-journal (or adm) group can read the system journal. If you manage guests day to day, ask your administrator for that access, or ask them to read the reason for you. When the host does not let you start that unit at all, gctl says permission denied and why (for example, the gavial group is not yet in your login session), and there is nothing in the journal.

Guests: create, start, stop

list

gctl list

Shows every guest defined on this host, with its state and the image it was created from, or (blank 40G) for one created with a blank disk. The state is running, stopped, starting, stopping or failed, or migrated for a guest that has been moved to another host. When a running guest started on an older Gavial than the one now installed, a last line says so and points to gctl versions.

versions

gctl versions

Shows the Gavial version installed on the host and the version each running guest started on. Upgrading the package does not touch a running guest: it keeps running the version it started on until it restarts. Such a guest shows the pending update and how to take it, here after an upgrade from beta 1 to a later beta:

installed: gavial 0.1.0-beta.2

INSTANCE             STATE      VERSION
web1                 running    0.1.0-beta.1 -> 0.1.0-beta.2  update pending: gctl reboot web1
db1                  running    0.1.0-beta.2
test1                stopped    -- (starts on 0.1.0-beta.2)

gctl reboot <inst> takes the update (a clean shutdown, then a start on the installed version).

create

gctl create <inst> <image> [--memory MB] [--bridge BR] [--vlan N] [--trunk N,N,...] [--mac MAC] [--diag LEVEL] [--cdrom ISO|--no-cdrom]
gctl create <inst> --disk-size SIZE [--cdrom ISO|--no-cdrom] [the same options]

Defines a new guest <inst> from the image <image> in the image store, or, with --disk-size and no image, with a new blank disk to install an operating system onto from its CD drive (see INSTALLING-A-GUEST.md). To see the images, run gctl images. create writes the guest's settings and nothing else. The guest gets its own disk at its first start.

option default meaning
--memory MB 1024 guest memory in MB. Give an HP-UX or OpenVMS guest at least 2048 (HP-UX 11.31: 3072), the sizes they are tested with; a Debian guest runs in 1024. gctl sets no upper limit: the host needs the guest's memory plus about 2 GB, and gctl doctor warns about a guest that does not fit.
--bridge BR the first bridge the administrator allows the host bridge that network adapter 0 is connected to
--bridge none leave adapter 0 unplugged (the guest sees it, with no link), as gctl nic can later
--vlan N untagged put adapter 0 in VLAN N (1-4094), untagged towards the guest. With --trunk, this is the trunk's native VLAN.
--trunk N,N,... not a trunk make adapter 0 a VLAN trunk: carry these VLANs (1-4094, up to 64, comma-separated, no spaces) tagged to the guest (see VLANs and trunks)
--mac MAC a random, locally administered address adapter 0's MAC address, xx:xx:xx:xx:xx:xx
--diag LEVEL log what the guest records about itself: off, log or trace (see diag)
--cdrom ISO an empty drive put the ISO ISO from the ISO store in the guest's CD drive (see the CD drive)
--no-cdrom (a drive) give the guest no CD drive. A drive cannot be added to a running guest: to give it one later, gctl set <inst> --cdrom <iso> and gctl reboot <inst>.
--disk-size SIZE (an image) instead of an image: a new blank disk of SIZE, from 1G to 2047G (digits and M, G or T; a bare number means G; 1T is the only T size in that range, so give a bigger disk in G). It is sparse, so it uses no space until the guest writes to it.

The MAC address is written into the settings. It stays the same when the guest moves to another host, and it must be unique on your network.

gctl create web1 hpux-base --memory 2048 --bridge br1 --vlan 100
gctl start web1
gctl create router1 debian7 --bridge br1 --trunk 10,20,30
gctl create hpux1123 --disk-size 40G --cdrom hpux-dvd1 --memory 2048

create refuses a name that is already taken and an image that does not exist. It also refuses, when you type them, a VLAN outside 1-4094, a trunk list that is malformed (an empty item, a space, a VLAN listed twice, more than 64) or that contains the --vlan VLAN, a MAC address that is not unicast (the first byte must be even) or is all zeros, --vlan or --trunk together with --bridge none, an ISO that is not in the store, a disk size out of range, and --disk-size together with an image.

start

gctl start <inst> [--console] [--boot-from disk|cdrom|tape] [--tape NAME]

Starts the guest. With --console, gctl attaches to the guest's console as soon as it exists, so you watch the whole boot. Ctrl-] detaches and leaves the guest running. The boot screen is drawn for the size of your terminal (gctl reboot --console does the same); the guest's own console stays 80 x 25.

If the guest stops while it is starting, gctl says so and shows why: the service's result and Gavial's own last lines from that run, for example gavial: --mpt-path=0/1/1/0 is taken .... You do not need to read the system journal for this. Without --console, gctl watches the first few seconds of the start for the same reason.

The first start of a new guest makes its disks: a reflink clone of its image for the boot disk, and one for each data disk. gctl prints a line for each disk it made, for example web1: disk 0 made now: cloned from image 'base' (0.0 s). On a reflink filesystem this takes well under a second. Every later start boots whatever the guest left on its disks.

Booting from another device once. --boot-from overrides the boot order for this start only, as EFI's BootNext does on real hardware:

The override applies to the first boot of that start. A reboot from inside the guest goes back to the normal order: the disk if it has a loader, otherwise the disc, otherwise the tape. So after you repair the disk from the recovery shell, rebooting boots the repaired disk. The guest's settings are not changed: gctl config shows the same thing before and after. On a running guest, use gctl reboot <inst> --boot-from cdrom.

gctl set web1 --cdrom hpux1123-0609-d1
gctl start web1 --boot-from cdrom --console

A recovery tape for one run. --tape NAME puts tape NAME from the tape store (see importtape) in the guest's tape drive for this run only, and boots it, as --boot-from tape does. This is how a recovery tape made with Ignite-UX is restored into a guest (a P2V move, see MIGRATING-A-SERVER.md):

gctl create server1 --disk-size 137G --no-cdrom
gctl start server1 --tape server1-recovery --console

Ignite boots from the tape and restores the system onto the guest's disk. Its reboot at the end is a reboot inside the guest: the tape is still in the drive, but the disk now has a loader, so the guest boots the restored system. The tape stays in the drive until the guest stops; the next start has no tape, and the guest's settings never name one. The drive gets the first SCSI target the guest leaves free, trying 3, 4, 5, 6, 8, 9, 10 to 15, then 1 and 2, and skipping every target already taken (the boot disk on 0, the controller on 7, the CD drive on 15, any data disk): target 3 for a guest with only its first disk. To choose it, add --tape-target=N to the guest's gctl args; a start with a target that is taken is refused. On a running guest, use gctl reboot <inst> --tape NAME.

At every boot the console shows the Gavial splash, then waits 5 seconds. Press any key to boot at once. This wait is Gavial's own, before the guest's firmware starts. The guest then boots from its own disk, as it would on hardware. (The HP-UX loader's autoboot countdown that follows is a different timer, and on Gavial a key cannot stop it: see known issue 3 in the release notes. To type at the loader's HPUX> prompt, see Typing at the HP-UX loader prompt.) The guest's clock follows the host's clock from the first moment of the boot.

A guest that was migrated to another host does not start here: its MAC addresses would be on the network twice. See migrate.

Typing at the HP-UX loader prompt

To boot HP-UX in single-user mode (boot -is), in LVM maintenance mode (boot -lm) or with any other loader command, have Gavial type the command for you: on Gavial a key cannot stop the loader's autoboot countdown (known issue 3 in the release notes). Gavial's --input= flag holds keystrokes that the guest reads before any others, at the first boot of the next start: the first key stops the countdown, and the rest are typed at the HPUX> prompt. \n is Enter.

Add it to the guest's flags with gctl args --add, which keeps the flags it already has:

gctl args hpux1131 --add '--input=\nboot vmunix -is\n'
gctl start hpux1131 --console

The console shows the command typed, and HP-UX comes up in single-user mode:

HPUX> boot vmunix -is
Launching /stand/vmunix

A reboot from inside the guest boots as usual. The flag stays saved, though, and the guest's next gctl start types the command again, so when the work is done take it out again; the guest's other flags stay:

gctl args hpux1131 --remove --input

shutdown

gctl shutdown <inst> [--timeout SECONDS]

Presses the guest's ACPI power button, then waits for the guest to power itself off. That usually takes a few minutes. gctl waits up to the guest's shutdown timeout: --timeout for this one shutdown (10 to 3600 seconds), otherwise the guest's own down= (gctl set <inst> --startup down=SECONDS, see set), otherwise 10 minutes. If the guest has not powered off by then, Gavial powers it off hard: for the guest, a power cut. The same timeout applies when the host shuts down, to gctl reboot, and to gctl destroy --keep-disk.

The power button is not the same as the guest's own shutdown command. The guest's operating system decides what the button does. HP-UX 11.23 and 11.31 treat it as a power failure: each sends every process SIGTERM, waits 10 seconds, sends SIGKILL to what is left, then syncs, unmounts its filesystems and powers off, without running the /sbin/rc shutdown scripts that shutdown -h runs. No setting inside HP-UX changes this. A guest agent that runs the guest's own shutdown instead is planned for Gavial 0.1.0, the first release. See the release notes for each supported guest. If an application must be stopped by its own script, stop it inside the guest first, or shut the guest down from inside. The guest then powers off and its service ends by itself.

A guest that does not respond to the power button is powered off hard when its shutdown timeout ends. This can be a guest that is still booting, or one whose operating system ignores the button. Shut such a guest down from inside instead.

stop

gctl stop <inst>

A hard power-off, now. The guest gets no shutdown and loses anything it had not written to disk. Use it for a hung guest. For a guest that is working, use gctl shutdown.

reboot

gctl reboot <inst> [--console] [--boot-from disk|cdrom|tape] [--tape NAME]

shutdown followed by start: the power button, a wait of up to the guest's shutdown timeout, then a fresh start. A stopped guest is simply started.

gctl reboot is also how a guest picks up a new Gavial version after an upgrade (see INSTALL.md). A reboot from inside the guest restarts it in place on the version it is already running.

With --console on a running guest, gctl attaches at once, so you see the guest go down and then come back up. Ctrl-] detaches, and the reboot carries on without you.

reset

gctl reset <inst>

A hard reset of a running guest: power off with no guest shutdown, then power on. reset refuses a guest that is not running.

reset never touches the disk; to start over from the image, use reimage.

toc

gctl toc <inst> [--yes]

A TOC (transfer of control), the guest's equivalent of the TC command on an HP Integrity server's management processor. Use it on a hung guest when support needs a crash dump of it. The guest crashes at once: HP-UX prints a TOC message, writes a crash dump to its dump device and reboots, and at that boot savecrash saves the dump to /var/adm/crash/crash.N. Anything the guest had not written to disk is lost, as with stop.

toc asks before it acts. In a script, add --yes. It refuses a guest that is not running. See SUPPORT.md for the whole procedure.

status

gctl status <inst>

Shows the service's state, and then the guest's own last words: the reason Gavial gave when this guest last stopped. The unit state alone cannot tell you whether the guest is healthy.

If your account can read the system journal, that reason comes from there. Otherwise gctl shows the record the service writes whenever a guest stops unexpectedly, or its start is refused: how it ended: stop <time> result=<result> ... and the last lines from that run (refused before the guest started when the start was refused before gavial ran). If the guest has not stopped that way, you see (none found -- not stopped yet, or this account cannot read the system journal).

support

gctl support <inst> [FILE] [--runs N] [--since TIME] [--no-logs]

One archive for a support case, <inst>-support-<stamp>.tar.gz in the current directory unless you name FILE: gctl versions, the host check (doctor), the guest's status, config, nic, args and stats --all, its last N run directories under /var/log/gavial/<inst>/ (default 2; Gavial keeps 5; the logs and any flight-recorder dumps), and the system journal of its services, as far as your account may read it. README.txt inside lists what is there and what was not readable, with the sudo journalctl command that adds the journal. --since takes a full UTC timestamp (2026-09-28T08:00:00Z) and limits the journal to that time on. --no-logs leaves the run directories out: they hold the guest's console transcript. The archive never holds a disk, a snapshot or an image. See SUPPORT.md.

destroy

gctl destroy <inst> [--keep-disk] [--yes]

Deletes a guest: its settings, its disks (its data disks too) and all its snapshots.

The image goes too when it was made for the guest. A guest created by gctl import, or moved here by gctl migrate, owns the image it came with, and destroy deletes that image as well. A disk is never shared: no other guest can be created from that image or attach it (use clone or disk move). An image added with importdisk belongs to no guest: every guest created from it gets its own reflink copy, and destroy never deletes it.

Who did what: the host journal

Every gctl command that changes something writes one line to the host's journal before it acts, naming the user (the real user when run with sudo):

journalctl -t gctl
user alice (uid 1001): shutdown web1
user alice (uid 1001): destroy test3 --yes

Commands that only show things (list, status, config and the like) are not logged. Two things never reach the log: a subscription token (only the fact that subscription set ran) and the text of a gctl send command (only its length). A line records what was asked; the command's own output says how it went.

Disk images and disks

A guest runs from a raw disk image, the format that dd produces. Everything happens in two places:

images

gctl images

Lists everything in the store: the disk images, the disc images (ISOs) for the CD drive, and the recovery tapes. For each it shows the space it uses on disk (STORED), its full size (SIZE), and what it is (TYPE), read from the image itself:

  DISK IMAGE               STORED    SIZE      TYPE
  debian7                  970M      16G       Linux disk (GPT: EFI, basic data, Linux swap)
  rx2620-1123              15G       137G      HP-UX disk (GPT: EFI, HP-UX, HP service)
  rx2620-vgmedia           100G      137G      HP-UX LVM data disk (whole-disk physical volume)

  ISO                                SIZE      TYPE
  hpux1123-0609-d1                   3.3G      bootable disc (El Torito), label HP_SW
  hpux1123-0609-d2                   1.9G      data disc, label HP_SW

  TAPE                     STORED    SIZE      TYPE
  server1-recovery         2.7G      2.7G      Ignite-UX recovery tape (ANSI labels)

An HP-UX or Linux disk can be a guest's boot disk. An LVM data disk has no partition table and no boot loader: attach it as a data disk (gctl disk <inst> add N --image <name>). blank means the first MiB is zeros, and unknown means none of these signatures was found. A big gap between STORED and SIZE means a sparse image.

clone

gctl clone <inst> <new-inst>

Makes an independent copy of a stopped guest: a new guest <new-inst> with its own reflink copy of every disk (instant, sharing blocks until either guest writes), the same settings, and new MAC addresses. The two are independent: either can be destroyed, rolled back or changed without touching the other. Its EFI boot settings are copied too. Snapshots are not.

gctl shutdown web1
gctl clone web1 web1-test
gctl nic web1-test 0 --bridge none      # until its host name and IP are changed
gctl start web1-test --console

The clone runs a copy of the same system, with the same host name and IP addresses. Keep the two off one network until you change them.

import

gctl import <file|[user@]host:/path> <name> [--memory MB] [--bridge BR] [--vlan N] [--trunk N,N,...] [--mac MAC] [--diag LEVEL] [--cdrom ISO|--no-cdrom]

Adds <file> to the image store as <name> and creates a guest called <name> from it, with the same options as create. (A guest archive made by gctl export is imported the same way, with its own settings: see import of an archive.) Start it next:

gctl import /srv/images/web1.raw web1 --memory 2048
gctl start web1 --console

Check the image's sha256 against the value you were given before you import it.

importdisk

gctl importdisk <file|[user@]host:/path> <name>
gctl importdisk <image.garchive> [NAME] [--threads N]

A disk image is at most 2047 GiB, the same limit as create --disk-size: the emulated SCSI controller addresses no more, so a larger file is refused.

Adds <file> to the image store as <name> and creates no guest. The file can also be an archive made by exportdisk; its name is then optional. Create guests from the image afterwards:

gctl importdisk /srv/images/hpux-base.raw hpux-base
gctl create web1 hpux-base
gctl create web2 hpux-base

Importing from another machine

import, importdisk, importiso and importtape accept a source on another machine, written as for scp:

gctl import admin@rx2620-backup.example.com:/images/web1.raw web1 --memory 2048
gctl importiso admin@fileserver:/iso/hpux-1123-dvd1.iso hpux-dvd1

A whole disk of a running machine

The source can also be a disk device, to image a real server's disk directly, with no image file on that machine:

gctl importdisk root@rx2620:/dev/rdsk/c1t2d0 rx2620-root
gctl importdisk root@rx2620:/dev/rdsk/c2t0d0 rx2620-depots

reimage

gctl reimage <inst> [--yes]

Throws away the guest's disks and starts over from its image. The guest's snapshots are kept. On a terminal, gctl asks you to type the guest's name. Anywhere else, you must give --yes. The guest must be stopped.

The disk becomes a fresh clone of the image. Changing the image a guest refers to (the GAVIAL_IMAGE line in its settings) does not replace an existing disk. reimage does.

Its EFI boot settings start over too: they go back to the ones its image came with (an imported or migrated guest's), or, for an image that brought none, the next boot makes a default boot entry for the new disk.

For a guest created with --disk-size, reimage gives it a new blank disk of that size: whatever was installed on it is gone.

Note: reimage resets every disk of the guest, its data disks too: each goes back to what it was made from, a new blank disk or a fresh clone of its image. All of them are reset, or none is.

Removing an image

gctl delimage <name>

Deletes the image <name> from the store (gctl images lists them), through a root service, as deliso does for an ISO. It is refused while any guest uses the image, running or stopped, and gctl names those guests:

Destroy those guests first, or remove the data disk with gctl disk <inst> remove <N>. An image made for one guest by gctl import or gctl migrate is deleted with that guest by gctl destroy; delimage is for the images you imported yourself, such as templates you no longer use.

Data disks

Besides its first disk, a guest can have up to seven data disks, numbered 1 to 7. Each is either a new blank disk of a size you choose, or a clone of an image in the store. It is made at the guest's next start, as /var/lib/gavial/<inst>/disk<N>.raw, and is the guest's own from then on, like its first disk.

gctl disk <inst>                          # list
gctl disk <inst> add <N> --size SIZE      # a new blank disk
gctl disk <inst> add <N> --image IMAGE    # a clone of an image in the store
gctl disk <inst> remove <N> [--yes]       # remove and DELETE it
gctl disk <inst> move <N> <inst2> [<M>]   # give it to another guest

For example, to give an HP-UX guest a 100 GB disk for a volume group:

gctl disk web1 add 1 --size 100G
gctl reboot web1
$ gctl disk web1
DISK  TARGET  SOURCE
0     0       image hpux2004
1     1       blank 100G
3     4       image db-data
cd    15      CD drive, ISO hpux-dvd1

A disk's SCSI target is fixed for the life of the guest. HP-UX names a disk by its hardware path, c<N>t<TARGET>d0, the first time it sees it, and records that name in /etc/lvmtab, /etc/fstab and every volume group on it. So disk N always answers on the same target, whatever other disks the guest has:

disk 0 1 2 3 4 5 6 7
SCSI target 0 1 3 4 5 6 8 9

Target 7 is the disk controller itself, target 15 the CD drive, and target 2 is kept for the boot disk of a disk imaged from an rx2620's internal bay, so no data disk uses any of them. Removing a disk moves no other disk. A later disk of the same number is a new disk on the old target: to the guest it looks like a disk swapped in the same slot. Do not renumber a disk to "tidy up" a gap. Gaps are fine.

A Linux guest names disks by the order it finds them (sdb, sdc, ...), so adding a disk with a lower number can rename the others there. Mount by UUID= or LABEL=, or use /dev/disk/by-path/, which holds the target.

A guest whose extra flags move a device. A disk imaged from an rx2620's internal bay runs with gctl args ... --disk-target=2 (see args): the first disk on target 2, where no data disk ever goes. The CD drive can be moved too, with --cdrom-target=N; targets 10 to 15 are never given to a data disk. gctl refuses an args change that moves the drive or the first disk onto a data disk's target, and a data disk on a target the guest's flags give the drive or the first disk, naming a free target.

Installation media and the CD drive

By default a guest gets a CD drive, to install an operating system by hand from its installation DVDs, or to read any other disc. The discs are ISO files in the host's ISO store, /var/lib/gavial/iso/. Only root can write there; members add ISOs through gctl importiso, which hands the file to a root service that moves it in and checks it, as for disk images. For the whole walkthrough of an install, see INSTALLING-A-GUEST.md.

importiso

gctl importiso <file|[user@]host:/path> <name>

Adds the disc image <file> to the ISO store as <name> (the store adds .iso; a name typed with .iso has it dropped).

gctl importiso /srv/iso/hpux-1123-dvd1.iso hpux-dvd1

deliso

gctl deliso <name>

Deletes the ISO <name> from the ISO store (gctl isos lists them), through the same kind of root service. It is refused while any guest has that ISO in its drive, running or stopped, because that guest could not start without it: take the disc out first with gctl set <inst> --cdrom none.

importtape

gctl importtape <file|[user@]host:/path> <name>

Adds a recovery tape image to the tape store as <name> (the store adds .tap). The image is a .tap tape image file, the format the gvtape driver writes on an HP-UX server (MIGRATING-A-SERVER.md) and the format a real tape read off a drive is kept in.

gctl importtape root@server1:/var/tmp/recovery.tap server1-recovery

Restore a tape into a guest with gctl start <inst> --tape <name> (see start). Remove one with gctl deltape <name>.

deltape

gctl deltape <name>

Deletes a tape from the tape store, with the carry made for it (<name>.carry, .carry.list and .carrydisk) if it has one. The store is root's, so a root service does the deletion, as for deliso. A tape is in a guest's drive for one run only, so no guest's settings name it and nothing refuses the deletion; a guest that was started with the tape keeps reading it until that run ends.

p2v

gctl p2v install [user@]server
gctl p2v capture [user@]server <tape-name> [--dir DIR] [--carry-skipped | --skip-listed]
gctl p2v remove [user@]server
gctl p2v check [user@]server
gctl p2v carry [user@]server <tape-name>
gctl p2v restore-carry <tape-name> [user@]guest

For a move off a physical HP-UX server with an Ignite-UX recovery tape. The step-by-step guide is MIGRATING-A-SERVER.md; this is the reference. Every subcommand runs from the Gavial host, as a member of the gavial group, over ssh. gctl help lists them.

A tape's name is a bare name (A-Z a-z 0-9 _ . -, not none), and a name already in the tape store is refused.

gctl runs ssh as you, with your ~/.ssh/config, so the server and the guest need root logins your ssh key reaches. check reads every name in the root volume group, which takes minutes on a large one. fbackup's message cannot open the dates file is harmless: that file only matters for incremental backups, and a carry is always a full one.

isos

gctl isos

Lists the ISOs in the store, with their sizes. Any guest on the host can use any of them, and several guests can use one at the same time.

Removing an ISO. Use deliso.

The CD drive

By default every guest gets a CD drive, empty unless it was created with --cdrom, so a disc can go in while it runs. A guest created with --no-cdrom has none, and a drive cannot be added to a running guest: it gets one with gctl set <inst> --cdrom <iso> and gctl reboot <inst>. The drive is read-only and answers as SCSI target 15 on the guest's disk controller (the first disk is target 0; data disks are on the targets in Data disks).

command does
gctl set <inst> --cdrom <iso> put <iso> in the drive: at once in a running guest, and at every later start
gctl set <inst> --cdrom none eject the disc (the drive stays, empty)
gctl set <inst> --delete cdrom remove the drive, from the next start
gctl config <inst> shows GAVIAL_CDROM, and for a running guest the disc in its drive now

Snapshots

A snapshot saves a guest's disks and its EFI boot settings (not its memory) under a name: one snapshot holds every disk the guest has, its data disks too, and the boot settings (what setboot shows on HP-UX) as they were when it was taken. The guest must be stopped, and the validator refuses the operation otherwise. Snapshots are reflink clones: taking one takes seconds and costs no space until the disks change.

gctl shutdown web1
gctl snapshot web1 before-patch
gctl start web1
command does
gctl snapshot <inst> <snap> save every disk and the boot settings as <snap>; the guest must be stopped (for a running guest, --vmstate, below)
gctl listsnapshot <inst> list the snapshots: name, when taken, SIZE (the first disk's full size), USED (the space only that snapshot holds: what delsnapshot frees; a block that only snapshots share counts in none), VMSTATE (whether it holds the running state too) and the disks it holds (0,1,3)
gctl rollback <inst> <snap> [--yes] put every disk and the boot settings back to <snap>. The guest must be stopped, and stays stopped: start it with gctl start. It asks [y/N] first (--yes skips the question, and is needed without a terminal): what the disks held since the snapshot is lost (take another snapshot first to keep it). The snapshot is kept.
gctl delsnapshot <inst> <snap> delete a snapshot, every disk of it and its boot settings

A guest that has never started has no disk of its own yet, so there is nothing to snapshot.

With data disks, a snapshot and a rollback are all or nothing: if any disk cannot be saved or restored, none is. Three cases are left alone on purpose, and gctl says so:

The files are /var/lib/gavial/snapshots/<inst>/<snap>.raw for the first disk, <snap>.disk<N>.raw for data disk N and <snap>.efivars for the boot settings.

If an operation is refused, gctl names the journal unit that holds the reason (gavial-disk@...). The most common reason is a guest that is still running.

Snapshots with the running state (--vmstate)

A snapshot of a running guest can keep its running state as well as its disks:

gctl snapshot web1 at-login --vmstate   # the guest pauses (13 s at 2.5 GB in use) and runs on
gctl rollback web1 at-login             # back to that moment: memory, CPU and disks

Settings

Each guest's settings are one file, /etc/gavial/<inst>.conf. The gctl commands below edit it for you. A change applies at the guest's next start. For a running guest, that means gctl reboot <inst>. The exceptions:

config

gctl config <inst>

Prints the settings file. The keys are:

key set by meaning
GAVIAL_IMAGE create, import the image the guest's disk was cloned from
GAVIAL_DISK_SIZE create --disk-size instead of GAVIAL_IMAGE: the size of the blank disk made at the first start
GAVIAL_DISK<N>_SIZE, GAVIAL_DISK<N>_IMAGE gctl disk <inst> add data disk N (1-7): a new blank disk of that size, or a clone of that image. One of the two per disk. See Data disks.
GAVIAL_CDROM --cdrom the CD drive: an ISO's name in the store, or none (empty). No line: no drive.
GAVIAL_MEM --memory memory in MB
GAVIAL_DIAG --diag, gctl diag off, log or trace
GAVIAL_ARG gctl args one extra Gavial flag per line
GAVIAL_NIC<n>_BRIDGE, _VLAN, _TRUNK, _MAC create, gctl nic network adapter n (0-3). _VLAN is the untagged VLAN, _TRUNK the tagged ones, e.g. GAVIAL_NIC0_TRUNK=10,20,30

You can also edit the file yourself. The validator accepts only these keys, one KEY=value per line, with no quoting. Do not put a comment after a value: the rest of the line is the value. Exactly one of GAVIAL_IMAGE and GAVIAL_DISK_SIZE must be set.

After the file, config adds comment lines listing each disk and the CD drive with the SCSI target the guest sees it on, for example # disk 1: SCSI target 1, blank 100G. For a running guest with a CD drive, it also adds a line naming the disc in its drive now. The output still reads as a settings file.

set

gctl set <inst> [--memory MB] [--diag off|log|trace] [--cdrom ISO|none] [--delete cdrom]
         [--onboot yes|no] [--startup [order=N][,up=SECONDS][,down=SECONDS]|none]

Changes settings for the next start and prints the file. For network adapters, use nic.

--onboot yes starts the guest when the host boots, and --startup order=N[,up=SECONDS] places it in the start order: the lowest order first, guests without one after them, and up= seconds of waiting after this guest before the next. down=SECONDS (10 to 3600) is the guest's shutdown timeout: how long a shutdown waits for it to power off before it is powered off hard (10 minutes unless set). The three go together: --startup replaces all of them, and --startup none clears them. See INSTALL.md. For extra Gavial flags, use args.

gctl set web1 --memory 4096
gctl reboot web1

--cdrom ISO|none puts a disc in the guest's CD drive, or ejects it. It saves the choice for the next start and, if the guest is running, changes the disc at once, printing what it did:

inserted hpux-dvd2 into hpux1123 (live)
ejected the disc from hpux1123 (live)
hpux1123: not running; hpux-dvd2 will be in its drive at the next start

A guest created with --no-cdrom gets its drive at its next start: while it runs, gctl saves the setting, says so and exits 0; gctl reboot <inst> then starts it with the drive. If the live change itself is refused, gctl names the journal unit with the reason (gavial-cdrom@...); the setting is saved either way. --delete cdrom removes the drive from the next start. See the CD drive.

args

gctl args <inst>                    # show
gctl args <inst> --add FLAG...      # add, or replace a flag of the same name; the rest kept
gctl args <inst> --remove FLAG...   # remove, by name (--idle removes --idle=sleep)
gctl args <inst> [--] FLAG...       # set the whole list
gctl args <inst> --clear            # clear

Extra flags passed to Gavial when this guest starts, one per argument. These are the same flags the Gavial program itself takes.

Example: boot a disk imaged from an HP Integrity rx2620's internal bay, with each device at the hardware path that the installed system expects (see INSTALL.md):

gctl args web1 --mpt-path=0/1/1/1 --disk-target=2 --pci-console=0/6/1/0 --nic-path=0/1/2/0

Example: let a guest's disk writes stay in the host's memory instead of waiting for the host's disk. By default, when the guest asks for its data to be on the disk (HP-UX asks for every write), Gavial writes it through to the host's disk before it answers. --disk-sync=off skips that, which makes writes faster, but a host crash or power cut can then lose writes the guest was told are on its disk. Use it only where that does not matter, for example while installing a guest you would install again after a crash. It applies at the next start:

gctl args web1 --disk-sync=off
gctl reboot web1

To remove it, set the guest's flags again without it (gctl args web1 shows them), or, if it is the only one, gctl args web1 --clear; then gctl reboot web1.

Network adapters

A guest has one to four network adapters, numbered 0 to 3. The guest sees them in that order: adapter 0 is its first network interface. Each adapter is a port on a Linux bridge that the host administrator created and allowed (see INSTALL.md). An adapter can be in one VLAN, untagged towards the guest, or be a VLAN trunk that carries several VLANs tagged. Gavial filters nothing and assigns no addresses. The guest configures its own IP address, as it would on hardware.

The host side of each adapter takes its bridge's MTU. Jumbo frames inside the guest have not been tested: keep the guest's interfaces at the standard 1500-byte MTU.

nic

gctl nic <inst>                                        # list
gctl nic <inst> <N> [--bridge BR|none] [--vlan V|none] \
                    [--trunk V,V,...|none] [--mac MAC]  # add or change adapter N
gctl nic <inst> <N> --remove                           # remove adapter N
option meaning
--bridge BR connect the adapter to bridge BR, which must be one the administrator allows
--bridge none leave the adapter unplugged (the guest sees it, with no link)
--vlan V put the adapter in VLAN V (1-4094), untagged. On a trunk, V is the native VLAN. The bridge must be VLAN-aware.
--vlan none remove the VLAN (untagged)
--trunk V,V,... make the adapter a trunk carrying these VLANs tagged (1-4094, up to 64). The bridge must be VLAN-aware.
--trunk none stop being a trunk
--mac MAC set the adapter's MAC address
--remove remove the adapter
gctl nic web1 1 --bridge br1 --vlan 200
gctl reboot web1
gctl nic web1

Like create, nic refuses a VLAN outside 1-4094, a malformed trunk list, a native VLAN that is also in the trunk, and a MAC address that is not unicast or is all zeros, and it refuses a VLAN or a trunk on an adapter that is unplugged (--bridge none).

VLANs and trunks

An adapter's bridge port is one of three kinds. --vlan is always the VLAN the guest sees untagged; --trunk lists the VLANs it sees tagged:

you give the port what the guest does
neither on the bridge's own untagged VLAN nothing: plain Ethernet
--vlan 100 an access port in VLAN 100 nothing: its frames are VLAN 100's, untagged
--trunk 10,20,30 a trunk: VLANs 10, 20 and 30 tagged, nothing untagged creates a VLAN interface per VLAN (Linux: eth0.10; HP-UX: lanadmin -V)
--trunk 10,20 --vlan 5 a trunk with a native VLAN: 10 and 20 tagged, 5 untagged uses the plain interface for VLAN 5 and a VLAN interface per tagged one
gctl nic web1 0 --vlan 100                    # access port, VLAN 100
gctl nic router1 0 --trunk 10,20,30           # trunk, all tagged
gctl nic router1 1 --bridge br2 --trunk 10,20 --vlan 5   # trunk + native VLAN 5
gctl nic router1 1 --trunk none               # back to an access port in VLAN 5

Console

Each guest has one serial console. Several people can attach at the same time, and everything any of them types reaches the guest. On attach, the console first replays its most recent output, up to about 1 MB, so output produced while nobody was attached is not lost unless there was more than that.

Anyone in the gavial group can attach to any guest's console. If a console is left logged in, for example as root, the next person to attach gets that session. Log out when you finish, and keep this in mind when you decide who joins the group.

terminal

gctl terminal <inst>

Attaches your terminal to the guest's console. Ctrl-] detaches, and the guest keeps running. When the guest stops, the console closes and gctl exits.

send

gctl send <inst> <command...>

Runs one command in the guest's shell through the console, prints its output, and exits with the command's own exit status.

gctl send web1 uname -a
gctl send web1 'ps -ef | grep inetd'

How it works, and its limits:

exit status meaning
the command's own the command ran
2 usage error, a line too long, or a newline in the command
3 the console is not there (the guest is not running) or it closed
4 no shell prompt within 3 minutes, or the guest asked for a password
124 the command did not finish within the timeout (it may still be running)

Monitoring and diagnostics

stats

gctl stats <inst> [--now] [--watch] [--lines N | --all] [--since TIME] [--until TIME] [--sum]

Shows how a running guest is doing, without root access. While a guest runs, Gavial records a sample every 10 seconds. By default stats prints the last 12 samples:

UTC       Mbundles/s   JIT%    offered       ran   aged   irq/s cpl  ip
19:38:11       11.28   66.7   +3670016  +1835008     +0       0   0  0x101ac00
column meaning
UTC when the sample was taken
Mbundles/s how fast the guest executed over the last interval, in millions of IA-64 instruction bundles per second. A guest that is idle also executes (its idle loop), so a high rate does not by itself mean the guest is busy.
JIT% a warm-up indicator: it rises as a workload warms up, and a low value on a busy guest means its work is still warming up.
the rest interrupt rate and details for support
option meaning
--now take a sample at once, then print
--watch (or -f) keep printing new samples as they arrive. Ctrl-C ends it.
--lines N print the last N samples
--all print every sample since the guest started
--since TIME, --until TIME only samples in this window. TIME is a full UTC timestamp such as 2026-09-27T20:41:41Z. The table shows only the time of day.
--sum one line for the whole window: its average rate and JIT%, and the total work done. Use it to time a job.
gctl stats web1 --since 2026-09-27T20:41:00Z --until 2026-09-27T21:10:00Z --sum

If the newest sample is more than 35 seconds old, stats warns you that the guest is not running or not executing.

diag

gctl diag <inst>                  # show the level
gctl diag <inst> off|log|trace    # set it

Chooses what a guest records about itself in /var/log/gavial/<inst>/:

level records
off nothing beyond the system journal
log (the default) a log with the Gavial build and settings, the console transcript and the end-of-run report. It costs nothing measurable.
trace log plus every access to the guest's disk controller. Capped at about 1 GB per run. Use it when support asks.

Setting a level saves it for the next start and, if the guest is running, changes it at once without a restart. Each start of a guest writes a new directory, named by its UTC start time, and the newest 5 are kept. To read a log, or a flight recorder dump written beside it, use gtrace. See SUPPORT.md.

gctl diag web1 trace
gctl diag web1 log

Archiving a guest or an image

Backup is not a Gavial function, by design. Back up running guests with your storage (array or SAN snapshots of the filesystem that holds /var/lib/gavial) or with the hypervisor that runs the Gavial host (a snapshot or backup of the host VM). Every write a guest was told is complete is on the host's disk, so such a snapshot restores like a power cut, which the guest's filesystems recover from (not for a guest set to --disk-sync=off, see args). export below is for moving or keeping a stopped guest, not for scheduled backups.

What a host backup must hold. A guest is its disks and its settings, which are kept apart. To be able to restore guests, back up all of these together:

path holds
/etc/gavial/ each guest's settings (<inst>.conf: memory, MAC addresses, bridges, VLANs, data disks, extra flags), the <inst>.migrated mark of a guest moved to another host, and the subscription (subscription)
/etc/gavial-network.conf the bridges guests may use
/var/lib/gavial/ each guest's disks and EFI boot settings (<inst>/), the image, ISO and tape stores, snapshots, and the running state of --vmstate snapshots (checkpoints/)

/var/log/gavial/ (the guests' logs) is useful for support but not needed to restore a guest. The repository settings (/etc/yum.repos.d/gavial.repo, /etc/gavial-repo/) come back from your invitation (see INSTALL.md), and the Gavial runtime from the package. A --vmstate snapshot can resume only on the container image it was taken on, which is kept in root's podman storage, not in /var/lib/gavial (see Snapshots).

To restore: install the Gavial package, put the paths above back with their owners and modes, and run sudo gctl doctor. There is nothing else to register: gctl finds the guests by their files in /etc/gavial, so gctl list shows them again, and a guest marked --onboot yes starts at the next host boot.

A stopped guest can be kept as one compressed file and made again later, on this host or another one: its disks (the data disks too), the disc in its CD drive and its settings. Guest disks are mostly empty space and text, so the file is far smaller than the disks: a 40 GB disk holding 6.1 GB of data became a 1.0 GB archive (measured on an HP-UX 11.23 guest). One image of the image store is kept the same way with exportdisk.

export

gctl export <inst> [FILE] [--level 0-9] [--threads N] [--no-iso] [--no-verify] [--remove-source]

Writes the stopped guest <inst> to FILE, by default <inst>.garchive in the current directory. The guest stays here and is not changed. The archive holds the guest's EFI boot settings too, and import puts them back. An archive written by a newer Gavial can hold a part this one does not know: import names it and leaves it out.

gctl shutdown web1
gctl export web1 /backup/web1.garchive

To free the guest's space here afterwards: gctl destroy <inst> (which also deletes its snapshots). Or let export do it: with --remove-source, once the archive has been checked, gctl destroys the guest as gctl destroy <inst> --yes would, its snapshots included. It cannot be combined with --no-verify.

gctl export web1 /backup/web1.garchive --remove-source

import of an archive

gctl import <FILE> [NAME] [--new-mac] [--threads N]

Makes the guest in an archive again, under its own name or as NAME. gctl recognises an archive by its contents, so the command is the same import that adds a raw disk image.

gctl import /backup/web1.garchive            # as web1
gctl import /backup/web1.garchive web1-test --new-mac
gctl start web1-test

exportdisk

gctl exportdisk <image> [FILE] [--level 0-9] [--threads N] [--no-verify]

Writes one image of the image store (see gctl images) to FILE, by default <image>.garchive in the current directory: a base image that guests are created from, or a data disk image, that no export of a guest carries. The image stays here and is not changed.

gctl exportdisk hpux-base /backup/hpux-base.garchive
gctl importdisk /backup/hpux-base.garchive            # as hpux-base
gctl importdisk /backup/hpux-base.garchive hpux-base2

gctl importdisk FILE [NAME] adds it to the image store again, under its own name or as NAME. gctl import FILE [NAME] [create options] adds it and creates a guest from it, as for a raw disk image. gctl reads the archive's manifest to tell an image's archive from a guest's, and refuses the wrong one for the command with the command to use. A damaged or incomplete archive is refused, with nothing imported.

Moving a guest to another host

migrate

gctl migrate <inst> [user@]host [--as NAME] [--remove-source] [--no-compress]

Moves a stopped guest to another Gavial host: its disks as they are now (its data disks too), its EFI boot settings, and every setting it has: memory size, network adapters (MAC addresses kept), extra flags, diagnostics level, start-at-boot settings (--onboot, --startup) and CD drive. You need no root on either host, but you must be a member of gavial on both hosts and be able to log in to the target with ssh. Both hosts should run the same Gavial version: nothing checks it, the archive format is the same across the beta, and a guest that arrives on an older Gavial may carry an extra flag that version does not have, which its first start refuses by name (gctl start shows it; gctl args <inst> --remove takes the flag out). If the target cannot receive the guest, gctl tells you before sending anything. The way back for a guest marked migrated here is to delete that mark: rm /etc/gavial/<inst>.migrated.

gctl shutdown web1
gctl migrate web1 ops@host-b
ssh ops@host-b gctl start web1

What happens:

  1. gctl opens one ssh connection, so you get one password prompt at most.

  2. It asks the target first whether its Gavial can receive, whether the name is free, and whether there is room for the data. If any answer is no, nothing is sent.

  3. It takes a snapshot of the guest's disks and streams the snapshot, the settings and a small manifest as one sparse stream. Only the data travels: a 137 GB disk holding 15 GB of data sends about 15 GB, and less again because the stream is compressed when both hosts have zstd installed (--no-compress sends it plain, for a network faster than the CPU). A progress line shows how far it is, over all the disks.

  4. The target checks the settings and imports the disks into its image store: the first disk as the image <name>, data disk N as the image <name>.disk<N>. The guest is created there under the same name, or under --as NAME, with each data disk a clone of its image, on the same target as before.

  5. On this host, the temporary snapshot is deleted and the guest is marked migrated: gctl list shows it as migrated, and gctl start refuses it so that its MAC addresses are never on the network twice. Delete it with gctl destroy <inst> when you are satisfied. To keep using it here instead, remove the mark:

    rm /etc/gavial/<inst>.migrated

What does not move: the guest's snapshots, its logs, the image it was first created from, and the ISO in its CD drive (the target needs its own copy, and gctl warns when it has none). A guest that has never started has no disk of its own yet, so its image is sent instead, with the boot settings that image came with; one created with a blank disk (--disk-size) that has never started has nothing to send, and gctl refuses it. On the target the disk becomes an image, so a guest that began blank arrives as one made from an image. A data disk added since the guest last started has no file yet: its setting travels as it is, and it is made at the first start on the target (a clone needs its image there too; gctl warns if it is missing).

receive

The target side of migrate: migrate runs it on the target over ssh, and you never run it yourself.

Host check

doctor

gctl doctor
sudo gctl doctor

Checks whether this host is ready to run guests, and changes nothing. It checks the CPU, Podman, the Gavial services and helpers, the image, polkit, the group, the guest storage filesystem, its directories (the image and ISO stores among them) and its mounts, free space, the network bridges and host firewall settings, SELinux, the subscription (a FAIL from the first day of its grace period), and the guests defined, including a CD drive that names an ISO the store does not have, a data disk cloned from an image the store does not have, and whether root's podman storage has room for a --vmstate snapshot of the guest with the most memory (vmstate room). Each line is ok, WARN, FAIL, skip or info, and a problem comes with the fix on the line after it. Run as a member, the checks that need root are skipped. Run with sudo to get all of them. The exit status is 1 if anything failed.

--version

gctl --version

Prints the version of the installed Gavial package, the commit it was built from, and the copyright, for example:

gavial 0.1.0-beta.1 (rc.11), commit 9079372a280e
Copyright (c) 2026 Kesto Systems Oy. All rights reserved.
Support: support@kestosystems.com

A version reads x.y.z-beta.N for a beta, the release it leads up to and the beta's number, and x.y.z for a release (0.1.0). (rc.N) after it marks a release candidate: the N-th build of that beta before it is final, built as the release it may become. The package files spell a beta with ~ in place of the -, and the candidate in the package's release field, as 0.1.0~beta.1-0.rc11 (the final beta is 0.1.0~beta.1-1): the ~ is what makes rpm sort a beta below its release, and the 0. what sorts a candidate below the final one. Quote the first line in a support request (gctl support includes it). No group membership is needed.

The host's subscription

subscription

gctl subscription get
sudo gctl subscription set <token|FILE>
sudo gctl subscription delete

The host's subscription, which every guest needs to start (see SUBSCRIPTIONS.md).

Each guest reads the subscription when it starts. None of the three touches a running guest: a guest started before a delete keeps running. An expiry stops no guest at all, now or at its next start: after the grace period only new guests, clones, imports and data disks are refused (see SUBSCRIPTIONS.md).

Where things are kept

path what who can write
/etc/gavial/<inst>.conf a guest's settings the gavial group
/etc/gavial-network.conf the bridges guests may use root
/var/lib/gavial/images/<image>.raw the image store root (through gctl import)
/var/lib/gavial/iso/<name>.iso the ISO store: discs for guests' CD drives root (through gctl importiso)
/var/lib/gavial/tape/<name>.tap the tape store: recovery tapes for gctl start --tape root (through gctl importtape)
/var/lib/gavial/incoming/ where imports are staged the gavial group
/var/lib/gavial/<inst>/disk.raw a guest's own (first) disk the guest
/var/lib/gavial/<inst>/disk<N>.raw a guest's data disk N the guest
/var/lib/gavial/<inst>/efivars a guest's EFI boot settings (its NVRAM: what setboot writes on HP-UX), one file, made at its first boot. Snapshots, clone, export and migrate take it along. To reset them, delete the file with the guest stopped: the next boot makes a default boot entry the guest
/var/lib/gavial/snapshots/<inst>/<snap>.raw a guest's snapshots (<snap>.disk<N>.raw beside it: its data disks; <snap>.efivars: its EFI boot settings) root (through gctl snapshot)
/var/lib/gavial/images/<name>.efivars the EFI boot settings that came with an imported or migrated guest, copied into it at its first start root (through gctl import)
/var/log/gavial/<inst>/ a guest's logs and live samples (readable by the group); cdrom in it names the disc in a running guest's drive the guest (and root, for diag and cdrom)
/run/gavial-console/<inst>/console.sock a running guest's console the gavial group can connect

Moving an HP-UX server into Gavial (P2V)

This guide moves a running HP-UX 11.23 or 11.31 Integrity server into a Gavial guest with HP's own recovery tool, Ignite-UX (make_tape_recovery), and Gavial's virtual tape drive for HP-UX, gvtape. On the server, gvtape looks like a tape drive, but what Ignite writes to it goes into a file: an image of a recovery tape. Gavial then boots that image as a tape, and Ignite restores the system onto the guest's disk, the same way it would onto new hardware.

Nothing is installed on the server except the small gvtape package, and the server keeps running throughout. You need no tape drive and no Ignite server.

This is a beta procedure. Read Before you start and try it on a test server before a production one. What has been tested: on HP-UX 11.23 virtual machines, gvtape installs and loads without a reboot, Ignite writes a recovery image through it (make_tape_recovery), and Gavial boots that image and Ignite restores the system to a login prompt; a recovery tape made on a physical rx2620's own tape drive restores to a login prompt too. On HP-UX 11.31, gvtape loads and passes its tape tests in a virtual machine, and on a physical two-CPU rx2620 it installs and loads without a reboot and writes and reads a tape; an 11.31 restore has not been run. Not yet tested: writing a recovery image through gvtape on physical hardware; the steps below in one run from start to finish, though each part has been tested on its own; and writing the image to an NFS-mounted file.

Before you start

On the server:

On the Gavial host:

Things the restored system keeps from the server: its host name, IP addresses, NFS mounts and everything else in its configuration. Until the server is switched off, give the new guest no bridged network adapter (step 4); otherwise both answer on the same IP address and connections to the server break.

1. Install gvtape on the server

Everything in steps 1 to 3 runs from the Gavial host, as a member of the gavial group, over ssh to the server as root with your ssh key. The commands are gctl p2v's: install, capture and remove in these steps; check and carry each do one part of capture on its own, and restore-carry is in step 5. GCTL.md is the reference for all six. Your ssh client must be able to log in to the server as root; give it any options the server's sshd needs in your ~/.ssh/config, as for any other ssh session to that server:

gctl p2v install root@server1

It copies the gvtape depot from the Gavial package to the server's /var/tmp, installs it with swinstall, which picks the build for the server's release (11.23 or 11.31), checks that the module is loaded, and removes the copy. The install loads the gvtape kernel module into the running kernel. No reboot, and no other software is touched. It also creates the tape device files and keeps the module loaded after a reboot. On the server, kcmodule gvtape shows it loaded, and lsdev -d gvtape shows the driver.

2. Write the recovery image, and bring it to the Gavial host

gctl p2v capture root@server1 server1-recovery

capture:

  1. checks that gvtape is loaded and Ignite-UX is installed;
  2. checks that Ignite can archive every file of the root volume group (vg00). Ignite's archive format cannot hold some paths: a file or directory name over 100 characters, a path over 255, a symbolic link pointing to a path over 100, a file of 8 GiB or more. Ignite leaves them out of the recovery tape with only a warning in its log. If the check finds any, capture lists them and writes nothing, unless you choose:
    • --carry-skipped: keep exactly those entries with HP-UX's own fbackup, which has none of Ignite's limits. A hard-linked file's every name is kept, so the link comes back. The archive streams over ssh, is compressed on the Gavial host, and is kept in the tape store with the tape. The restored system puts them back by itself (step 5).
    • --skip-listed: write the tape without them. The list stays on the server in /var/tmp/gvtape-recovery.check.
  3. checks that the server's /var/tmp has room for the image: the data in the root volume group, plus a tenth, plus 1 GiB. Give another directory with --dir, for example a spare disk's filesystem (an NFS mount has not been tested yet);
  4. writes the tape: make_tape_recovery -A, which archives the whole root volume group, not only the operating system files, through gvtape into /var/tmp/gavial-server1-recovery.tap. It takes as long as reading the data;
  5. copies the image to the Gavial host's tape store as server1-recovery, reading it whole and refusing a copy that was cut short. It adds the small label Ignite expects (Ignite writes it only on HP's own tape driver) and says so;
  6. deletes the image on the server.

gctl p2v check root@server1 makes only the check of point 2: nothing is installed or written on the server. gctl p2v carry root@server1 server1-recovery makes only the carry, for a tape written another way.

By hand, without gctl: on the server, /usr/local/bin/gvtape-recovery /var/tmp/recovery.tap makes the check and writes the image (-i writes it without the entries the check lists, -n only checks, and a spare disk's block device with -o takes the place of the file). Copy the image to the Gavial host and add it with gctl importtape <file> server1-recovery.

3. When the server is done

gctl p2v remove root@server1 removes gvtape from the server and unloads the module. Keep it until the restore has worked.

4. Restore it into a guest

The image is in the tape store (gctl images lists it). Create a guest with a blank disk at least as big as the server's boot disk:

gctl create server1 --disk-size 137G --memory 4096 --no-cdrom
gctl nic server1 0 --bridge none            # until the old server is off

Server hardware paths. The recovery tape records where the server's boot disk was, and Ignite restores to that path. For an rx2620's internal disk, give the guest the same layout:

gctl args server1 --mpt-path=0/1/1/1 --disk-target=2 --pci-console=0/6/1/0 --nic-path=0/1/2/0

Start it with the tape in its drive, on its console. The tape is there for this run only; the guest's settings never name it:

gctl start server1 --tape server1-recovery --console

The guest boots HP's loader from the tape, starts Ignite, and Ignite restores the system with no questions:

Booting from Tape
AUTO ==> boot IINSTALL
...
* Archive extraction from tape is beginning. Please wait.

A restore takes hours under Gavial (a 137 GB rx2620 disk: about 6 hours). To see that it is working, gctl stats server1 --watch in another shell shows a new sample every 10 seconds. At the end Ignite reboots the guest, which now boots from its disk and reaches Console Login:.

5. After the restore

Data volume groups

make_tape_recovery -A covers the root volume group. Large data volume groups are better moved as disks: gctl importdisk reads a disk from the server over ssh and adds it to the image store, and gctl disk <inst> add N --image <name> attaches it to the guest. After the restore, vgimport the volume group in the guest as you would after moving disks to new hardware. See GCTL.md and GCTL.md.

When something goes wrong

What you see Why What to do
kcmodule -v gvtape does not say loaded the module did not load kcmodule -B gvtape=loaded; send /var/adm/syslog/syslog.log to support
gvtape-recovery: N entries Ignite would leave out of the recovery tape those paths do not fit Ignite's archive format rename or move them and run again, or -i to go on without them (see step 2)
make_tape_recovery: "a previous make_sys_image process may be hung" an earlier run was killed if that process is gone, remove /var/tmp/ign_configure/make_sys_image_flag<PID>
gvtape-recovery: the gvtape module is not loaded the module is not loaded see the first line
the restore says "The archive is empty" the image lacks Ignite's archive label import it again with gctl importtape, which adds the label
the restore stops asking for a disk, or reports none the guest's disk is not where the tape says give the guest the server's layout (step 4)
the guest boots the installer from a CD instead a disc is in the guest's drive gctl set server1 --delete cdrom, then start again

Gavial subscriptions

Gavial needs a subscription to run guests and to make new ones. A subscription is a small signed text token that names your organisation, the subscription type and the date it runs until. It is not tied to a machine: the same token works on every host you run Gavial on.

A token looks like this (one line, a few hundred characters):

gavial1.dj0xO2tpZD1kNjQ1NDJlZDA0MjM5YTYy....Gm4c1Q2x...

It is signed by us, so it cannot be edited: change one character and Gavial rejects it.

Installing it

A host set up with Gavial's setup package already has its subscription: the setup package installs the token you give it (INSTALL.md). To install one by hand, or a renewed one, run this on a host with the Gavial package, as root:

sudo gctl subscription set 'gavial1.dj0x...'      # the token itself
sudo gctl subscription set /path/to/token.txt     # or a file holding it

set checks the token first and refuses one that is not current (damaged, not issued by us, or past its grace period), so a mistyped or expired token never replaces a working one. (On a host other people log in to, prefer the file form: a token typed on the command line is visible to them in ps while the command runs.) Then:

gctl subscription get       # whose it is, its type, and until when
gctl doctor                 # includes the same line, among the host checks
sudo gctl subscription delete

Each guest reads the subscription when it starts. Installing a new one does not touch running guests; they pick it up at their next start.

The guest's boot screen also shows whose subscription it is and until when, under the copyright line, and gctl subscription get shows it on the host.

When it runs out

An expiry never stops your guests. Your existing guests keep running and keep starting, however long ago the subscription ended: after a host reboot, with --onboot, after gctl reboot, and after a rollback to a snapshot with its running state. What a lapsed subscription stops is new guests and disks:

When Existing guests New guests, clones, imports and data disks
more than 30 days before the end date start allowed
the last 30 days start, with a warning of the days left allowed
up to 30 days after the end date (grace period) start, with a loud warning allowed; gctl doctor warns
more than 30 days after the end date start, with a loud warning refused until you renew

After the grace period, these are refused, each with the reason and nothing changed: gctl create, gctl clone, gctl import, gctl importdisk, gctl disk <inst> add, and receiving a guest with gctl migrate. A guest that was created but never started counts as new: its first start makes its disk, and that start is refused too.

Everything else keeps working, so you can run, protect and repair what you have: starting, stopping and rebooting guests, snapshots and rollbacks, gctl export, changing a guest's settings and flags, and adding installation DVDs and recovery tapes.

To renew, install the new token with sudo gctl subscription set; nothing needs restarting.

Without a valid subscription no guest starts. A host with no subscription installed, or one whose token is damaged, was not issued by us, or was issued "in the future" by more than a day (usually a sign that the host's clock is wrong), starts no guest at all. The message says which.

Repositories

Gavial's package repositories need the subscription too. dnf sends your token as the repository password (INSTALL.md step 2 sets that up), and the repository accepts a current token: until its end date and through the grace period. A host gets updates exactly as long as it may make new guests.

dnf reports meaning fix
401 Unauthorized no token reached the server, or what reached it is not a token /etc/yum.repos.d/gavial.repo must have username= and password= lines. The token is one line, exactly as issued.
403 Forbidden the token has expired and its grace period is over, or it is damaged or not issued by us install your renewed token in the same file
404 Not Found the repository has no such file: your host asked for a package or index that is not there (for example while a release is being published) run sudo dnf clean metadata and try again; if it persists, contact support (support@kestosystems.com)
a certificate error the host does not trust the repository's public certificate the host's clock must be right, and its trust store current (sudo update-ca-trust); a proxy that intercepts HTTPS must let packages.kestosystems.com through untouched
500 Internal Server Error a problem on the repository server contact support (support@kestosystems.com)

dnf shows only the status. To see the reason, run gavial-subscription status token.txt on the host: it tells you whether the token has expired, is damaged, or was not issued by us.

When you renew, install the new token with one command:

sudo gctl subscription set token.txt

It installs the token for guests and replaces the repository password with it in /etc/yum.repos.d/gavial.repo. The repository accepts a new token at once. gctl changes only a root-owned regular file there and keeps every other line; if the file is missing, or holds no password, it says so and changes nothing.

In the repository, a lapsed subscription stops downloads: installed packages and guests are not touched, and existing guests keep starting (see When it runs out).

Where it lives

The host's subscription is /etc/gavial/subscription, owned by root and readable by the gavial group (mode 0640). Write it with sudo gctl subscription set, not an editor: the guests' units only accept a file root wrote.

The file holds the token on one line; blank lines and lines starting with # are ignored.

To see what Gavial would decide without starting anything (exit 0: the subscription is current, so new guests can be made; 1: it is missing, not valid, or past its grace period):

gctl subscription get

The same verdict for a token file that is not installed yet, with the details:

gavial-subscription status token.txt

Collecting information for support

When a guest misbehaves, the evidence is usually already on the host. Every guest records itself by default, and you need no root access to read most of it. This page lists what to collect, how to read it, and what to check before you send it anywhere.

Where to send it: support@kestosystems.com, with the archive from gctl support attached and the times in UTC. The reply comes to the address you write from.

In the examples the guest is web1. Replace it with yours.

The short list

For most problems, send two things to support@kestosystems.com:

  1. what you did, what happened, what you expected, and when, in UTC (date -u);
  2. one archive from gctl support:
gctl support web1

That writes web1-support-<stamp>.tar.gz in the current directory with everything the sections below describe: the versions, the host check, the guest's state, settings and live samples, its last two run directories (the logs and any flight-recorder dumps) and the system journal where your account may read it. README.txt inside lists what is there and what your account could not read, with the command that adds it (the journal needs root; run the printed sudo journalctl ... and send its output too).

gctl support web1 --runs 5                        # every run Gavial still keeps
gctl support web1 --since 2026-09-28T08:00:00Z    # the journal from that time (UTC)
gctl support web1 --no-logs                       # without the run logs (the console transcript)
gctl support web1 /tmp/case-1234.tar.gz           # name the file

Read Before you send anything first: the run logs and the journal contain the guest's console transcript. The archive never holds a disk, a snapshot or an image.

The sections below say what each part is and how to read it, and how to collect any of it by hand.

Gavial keeps each guest's logs for its last 5 starts only. If a problem happened a few restarts ago, collect its logs before you start the guest again.

1. Versions

The installed package:

rpm -q gavial

After an upgrade, a guest keeps running on the version it started with until you run gctl reboot. The installed package therefore does not tell you which version a running guest uses. This does:

gctl versions

Each log also records the Gavial build it came from (see gtrace --summary).

2. The host check

sudo gctl doctor > doctor.txt

The doctor reports the CPU, Podman, the Gavial services, storage, mounts, free space, bridges, firewall settings, SELinux and the defined guests. It changes nothing. Without sudo it skips the checks that need root, so run it with sudo when you can.

3. The guest's state and settings

gctl list
gctl status web1
gctl config web1
gctl nic web1
gctl args web1

gctl status shows the service state and the guest's own last words: the reason Gavial gave when the guest last stopped. gctl reads that reason from the system journal when your account can; otherwise it shows the record the service writes whenever a guest stops (see GCTL.md), so sudo is not needed. Run journalctl itself with sudo (step 6 of the short list) for the full log.

How a guest's service ends:

what happened service state
gctl shutdown, gctl stop, or the guest powered itself off inactive
Gavial stopped on an error of its own failed
the guest could not be started at all (for example the runtime image is missing) failed
the validator refused the start (for example a bad setting, or a bridge that is not allowed) failed; gctl start printed the reason and gctl status shows it

4. Live samples

While a guest runs, Gavial writes a sample every 10 seconds: how fast the guest is executing and a few details for support. Any member of the gavial group can read them:

gctl stats web1 --all > stats-web1.txt

The raw samples are in /var/log/gavial/web1/status, since the guest last started, and status.1. To sum up a time window, for example the time a job took:

gctl stats web1 --since 2026-09-28T09:00:00Z --until 2026-09-28T09:30:00Z --sum

If the newest sample is more than 35 seconds old, the guest has stopped or is no longer executing. That is itself worth reporting.

5. The guest's logs

Each guest records itself in /var/log/gavial/<inst>/, which the gavial group can read:

/var/log/gavial/web1/
  diag                  the diagnostics level: off, log or trace
  status, status.1      the live samples (section 4)
  20260928T081502Z/     one directory per start, named by its UTC start time
    run.log.zst         the log
    run.log.idx         its index
    run-1.log.zst       a new log, started when the level was changed on the running guest
    flightrec-*.frec.zst  flight recorder dumps, if any were written (below)
  20260928T101944Z/
  ...

The newest 5 run directories are kept. At the default level, log, a run's log holds:

At the trace level the log is split into numbered segments (run.log.000.zst, run.log.001.zst, ...). The first segment and the newest 4 are kept.

Reading a log with gtrace

gtrace reads a log without unpacking it to disk. Give it the log's base name, run.log, whether the log is one file or several segments.

gtrace --summary /var/log/gavial/web1/20260928T081502Z/run.log

--summary is the first thing to run. It prints the Gavial build, the command line and the machine, the span of the run, the line counts, any gaps, and whether the log ended cleanly. A log without a clean end was cut short: Gavial was killed, the host lost power, or the guest is still running.

to run
read the console transcript as the guest wrote it gtrace --console-raw .../run.log
keep lines containing a string gtrace -F 'panic' .../run.log
keep lines matching a regular expression gtrace -g 'panic' .../run.log
drop matching lines instead add -v
show only the last N matches gtrace --tail 200 .../run.log
stop after N matches gtrace -n 50 .../run.log
count matches gtrace -c -F 'panic' .../run.log
follow a running guest's log gtrace -f --console-raw .../run.log

gtrace --help lists every option.

Flight recorder dumps: gtrace reads them too

Gavial keeps a short record of the guest's recent history in memory: address translations, interruptions and context changes. When the guest panics, Gavial writes that record to a file in the run directory, named flightrec-<UTC time>-<number>-<reason>.frec.zst, and the guest carries on. With the diagnostics level off, the file goes to /var/log/gavial/web1/ itself. You need to do nothing to turn this on.

gtrace reads a dump as well as a log; it tells the two apart by their contents. It prints first why the dump was written, the processor state and address translations at that moment and the last lines of the guest's console, each of these lines starting with #. Then come the recorded events, oldest first, one line each in the same form as the lines of a log, so the options above select events from a dump just as they select lines from a log.

gtrace /var/log/gavial/web1/20260928T081502Z/flightrec-*.frec.zst | less
to run
see only why the dump was written and what it holds gtrace --summary .../flightrec-....frec.zst
show only the newest N events gtrace --tail 200 .../flightrec-....frec.zst
show only some kinds of event gtrace --rings tlb,irq .../flightrec-....frec.zst
leave out the processor state and console gtrace --no-state .../flightrec-....frec.zst
show only the events, without the # lines gtrace --no-preamble .../flightrec-....frec.zst
read a run's log and its dump together gtrace .../run.log .../flightrec-....frec.zst

If a run directory has a dump, send it with the run (below): support reads it with the same tool.

Packing a run for support

gctl support web1 packs the newest run directories (two by default, --runs 5 for every one Gavial keeps) with everything else this page lists. To pack one run by hand:

tar -C /var/log/gavial/web1 -czf web1-20260928T081502Z.tar.gz 20260928T081502Z

6. The system journal

Each guest's service writes its messages to the system journal: Gavial's own messages, its stop reason, and a copy of the guest's console output. Reading the journal needs root, or membership of the systemd-journal group.

sudo journalctl -u gavial@web1 --since '2026-09-28 08:00 UTC' --no-pager > journal-web1.txt

journalctl reads a time without a zone as the host's local time; UTC at the end keeps it in the same time base as gctl stats --since and the logs.

When a start, a snapshot, an import, a diagnostics change, a disc change or a live flag change (gctl args on a running guest) is refused, the reason is in the journal of the service that refused it. (When gctl says permission denied instead, the service never ran: the message says why.)

sudo journalctl -u gavial@web1 -u gavial-net@web1 --since today --no-pager
sudo journalctl -u 'gavial-disk@*' -u 'gavial-import@*' -u 'gavial-diag@*' \
    -u 'gavial-importiso@*' -u 'gavial-importtape@*' -u 'gavial-deliso@*' -u 'gavial-delimage@*' \
    -u 'gavial-cdrom@*' -u 'gavial-args@*' -u 'gavial-checkpoint@*' --since today --no-pager

7. Recording more: the trace level

If support asks for a trace, raise the guest's diagnostics level. This works on a running guest, with no restart, so you can raise it just before you repeat the problem:

gctl diag web1 trace

Reproduce the problem, then put the level back:

gctl diag web1 log

Each level change on a running guest starts a new log file in the same run directory (run-1.log.zst, run-2.log.zst, ...). The level is also saved in the guest's settings, so a guest left at trace stays at trace after a restart. trace records every access to the guest's disk controller and costs up to about 1 GB of disk per run. Do not leave it on longer than you need.

To see the current level:

gctl diag web1

8. A crash dump from a hung guest

When an HP-UX guest hangs, a crash dump shows what its kernel was doing. On an HP Integrity server you would get one with the management processor's TC command. For a guest, use gctl toc.

Before you need it, check that the guest has a dump device and room to save a dump. Log in to the guest as root:

crashconf -v          # "DEVICE ... /dev/vg00/lvol2": the dump device (by default, the swap)
bdf /var/adm/crash    # room for the dump: up to the "Total pages included in dump" x 4 KB

When the guest hangs:

gctl terminal web1    # optional, in a second window: watch the dump being written
gctl toc web1

The console shows the TOC and the dump being written, then the guest reboots:

INIT occurs.
INIT: Begin crashdump.
*** The dump will be a SELECTIVE dump:  287 of 2047 megabytes.
*** Dumping: 100% complete (287 of 287 MB)  (device /dev/dsk/c0t0d0 )
INIT[0]: OS_INIT ends. Resetting the system.

The dump waits 10 seconds for a key before it starts (a key there lets you change the dump type). Do not press anything.

During that boot, savecrash copies the dump from the dump device to /var/adm/crash/crash.N. When the guest is up again, log in and check:

ls -l /var/adm/crash/

Send support the whole crash.N directory, with the guest's log directory for the run that hung (section 5). If the guest is not running HP-UX yet (still in its firmware or boot loader), toc does nothing and the guest's log says so.

Before you send anything

The logs and the journal contain the guest's console transcript. That is everything the guest printed on its console, including whatever was typed at its prompts and echoed back: host names, addresses, user names, paths, command lines, and any secret that was typed where the guest echoes input. Read the transcript before you send it:

gtrace --console-raw /var/log/gavial/web1/20260928T081502Z/run.log | less

Where the transcript must not leave your site, you can keep it out of future logs. --log-no-console stops a guest's log from recording the console. It takes effect at the guest's next start, and it does not remove the console from the system journal. --add keeps the guest's other flags as they were:

gctl args web1 --add --log-no-console
gctl reboot web1

What else the collected items contain:

item contains
gctl doctor host name, file system layout, bridge and interface names, guest names
gctl config, gctl nic, gctl args memory size, bridges, VLANs, MAC addresses, extra flags
gctl stats, status execution rates and counters only
run logs, journal the console transcript (above), Gavial's settings and messages
flight recorder dumps the last lines of the console, and the guest's processor state and memory addresses
a crash dump (crash.N) the guest kernel's memory: its processes, their arguments and open files, and buffered data

Never send a guest's disk, a snapshot or an image unless support asks for it. They hold the guest's entire file system.