We’re excited to share that Pantavisor is taking its first steps toward upgrading from LXC 3.x to LXC 6.x as the container runtime. Starting now, our Raspberry Pi and Docker/x86_64 appengine builds ship with LXC 6.0.5 by default — and we plan to roll this out across all supported platforms once we’ve gained enough confidence in the field.
Why LXC 6?
Pantavisor has been running on a patched fork of LXC 3.0.4 since the early days. LXC 3.x has served us well, but it’s showing its age:
- Meson build system — LXC 6 moved from autotools to Meson, which makes cross-compilation for embedded targets significantly cleaner
- Modern cgroup v2 — first-class cgroupv2 support and the unified cgroup hierarchy that modern kernels default to
- Improved security — years of upstream hardening, better capability handling, and tighter namespace isolation
- Active maintenance — LXC 6.0 is the current LTS release with ongoing security fixes; LXC 3.x has been EOL for years
- io_uring event loop — optional high-performance event loop (we disable this for embedded, but it’s available for server workloads)
Our LXC Fork: pantavisor/lxc
Pantavisor uses LXC as a library, not as a standalone container manager. This means we need a few custom patches that go beyond what upstream LXC provides. We maintain these in our fork at github.com/pantavisor/lxc.
The LXC 3.x fork: 51 commits, 8 years of history
Our LXC 3.x branch (stable-3.0-BASE-2c5c780762) accumulated 51 custom commits over 8 years from 7 contributors. These patches cover everything from the initial Pantavisor build integration to namespace management, mount handling, and cgroup configuration.
The LXC 6.x fork: 12 clean commits
For the 6.0 rebase, we carefully triaged all 51 patches from the 3.x branch. Many were no longer needed — build system patches (autotools → Meson made 7 patches obsolete), CI infrastructure, merge commits, and fixes that upstream had already incorporated. We consolidated the remaining essential patches into 12 clean commits on top of upstream LXC 6.0.5:
| # | Patch | What it does |
|---|---|---|
| 1 | pv_export.h | Export LXC namespace enum constants for Pantavisor’s container runtime integration |
| 2 | set_container_type() | API to override the container= env var so PID 1 sees pv-<group> instead of lxc |
| 3 | lxc.rootfs.bdev_type | Expose block device type via config API (needed for overlay root filesystem setup) |
| 4 | realpath_x() | Custom realpath that resolves symlinks within a virtual root boundary (FreeBSD-based) |
| 5 | origin=mkdir | Mount option to create source directories on the host before bind-mounting |
| 6 | Escaped quotes in init.cmd | State-machine parser for lxc.init.cmd supporting escaped quotes and backslashes |
| 7 | cgroup prefix lxc/ | Use lxc/<name> cgroup path instead of upstream’s lxc.payload.<name> |
| 8 | Hook command parameters | Allow start hooks to include command-line arguments |
| 9 | Overlay upperdir flexibility | Allow overlay upper/workdir to live outside the container directory |
| 10 | Exports mount support | Preserve /exports mounts and shared propagation for Pantavisor’s inter-container file sharing |
| 11 | SIGCHLD blocking in run_buffer | Prevent Pantavisor from reaping hook child processes before LXC can collect their exit status |
| 12 | Rebase documentation | Full mapping of which 3.x patches were ported, dropped, or consolidated, and why |
What changed in the rebase
Porting from 3.x to 6.x wasn’t a mechanical cherry-pick. The LXC codebase changed substantially:
- Data structures:
struct lxc_listwas replaced with kernel-stylestruct list_headlinked lists - String handling: New helpers like
strnequal(),strequal()replaced rawstrcmppatterns - Mount options: Now uses
struct lxc_mount_optionswith bitfields and a dedicated parserparse_lxc_mount_attrs() - Code reorganization: Functions moved between files (e.g.,
run_buffermoved toutils.c)
Several groups of related patches were consolidated:
- 6 realpath-related commits → 1 clean commit
- 3 init.cmd/quote parsing commits → 1 state-machine implementation
- 2 SIGCHLD/reaping fixes → 1 comprehensive fix
- set_container_type + log capture + pv-root handling → 1 combined patch
Upstreaming Plan
Looking at our 11 functional patches, several are good candidates for upstreaming to the LXC project:
Strong candidates:
- realpath_x() — Useful for any system embedding LXC where mount targets can be symlinks within a container root
- Escaped quotes in init.cmd — General-purpose improvement; the upstream parser doesn’t handle escaped characters
- Hook command parameters — Currently hooks can’t take arguments, which seems like an oversight
- origin=mkdir — Complements the existing
create=diroption; useful beyond Pantavisor
Pantavisor-specific (likely staying in fork):
- set_container_type() — Very specific to Pantavisor’s container identification needs
- pv_export.h — Header for Pantavisor’s namespace integration
- cgroup prefix — Intentional divergence from upstream naming convention
- Exports mount support — Tied to Pantavisor’s inter-container communication model
We’ll be working on preparing these patches for upstream submission in the coming weeks. Our goal is to minimize the delta between our fork and upstream LXC, making maintenance easier and giving back to the LXC community.
How to Try It
Enabled by default (Raspberry Pi and Docker/x86_64)
If you’re building for raspberrypi-armv8 or docker-x86_64, LXC 6.x is now the default. No changes needed — just build as usual:
./kas-container build kas/machines/raspberrypi-armv8.yaml:kas/scarthgap.yaml:kas/bsp-base.yaml:kas/with-lxc-next.yaml:.github/configs/build-base-starter.yaml
Enable on any other platform
Add kas/with-lxc-next.yaml to your KAS config chain:
./kas-container build <your-config>:kas/with-lxc-next.yaml
This appends lxc-next to PANTAVISOR_FEATURES, which switches the LXC dependency from lxc-pv (3.x) to lxc6-pv (6.x).
Verify
After building, check your image includes lxc6-pv:
# In bitbake build environment
bitbake-getvar -r pantavisor RDEPENDS
# Should show lxc6-pv instead of lxc-pv
What’s Next
- Broader rollout: Once we’re confident with Raspberry Pi and Docker builds, we’ll enable lxc-next for all platforms
- Upstream submissions: Prepare and submit patches that benefit the wider LXC community
- cgroup.relative: We recently added
lxc.cgroup.relativesupport on our 3.x branch and plan to port this to 6.x as well - Default promotion: Eventually
lxc-nextwill become the default andlxc-pv(3.x) will be deprecated
We’d love to hear from anyone testing LXC 6.x with Pantavisor — please share your experiences, issues, or questions in this thread!