From: Dominik Csapak <d.csapak@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [RFC proxmox-perl-rs/qemu-server/qemu-server-rs v3 0/9] pci-handling rewrite (part 1/2/3)
Date: Fri, 6 Nov 2026 14:25:43 +0100 [thread overview]
Message-ID: <20261106132604.2556840-1-d.csapak@proxmox.com> (raw)
# Motivation
We want to extend the PCI layout mechanism to be easily extendable, especially
for NUMA awareness and replicating host-topology (e.g. see bug #7283 [0]).
This is necessary for some performance gains in guests, especially with
high-end hardware where users pay extra for higher performance.
# The Problem
PCI addresses (and hardware layout in general) must be fixed for our qemu
guests, since this is part of the machine state and must be stable for
live-migration suspend/resume, etc.
Currently, these addresses are hardcoded in perl hashes, with a long history of
devs (me included) piling new addresses on top, using whatever address was
free.
This led to a very convoluted and scattered assignment list, without any
underlying structure, which makes it harder the more new devices are added.
(Using a wrong address only surfaces when running some tests or starting a
guest with it)
# My Proposed Solution
So to fix the current situation I propose a plan in multiple phases:
## Phase 1 - untangling perl code to rust (this series)
To extend/switch between multiple PCI layouts, we first must untangle the
current situation and make it easier to see what is actually used.
I did this in rust, by using the type system to represent the PCI layout, and
inferring the addresses from the layout, not the other way around.
That makes it easier to see where there is actually free space and where we can
add new things.
It also highlights how messy the current layout is. (See the legacy layout in
the `pve-qemu-server-pci` crate)
I also introduced here a generic `HardwareConfig` struct that's intended to
hold information useful to more call sites in contrast to passing a lot of
arguments everywhere, similar to the Cfg2Cmd class, but usable in the rust
codebase.
## Phase 2 - extending pci layouts (this series)
This introduces a new layout ("grouped") that can be used in an opt-in manner,
and is vastly more logically constructed, which makes it easy to extend and
reason about.
This part entails restructuring the addr calls in qemu-server's perl code, so
that there is only a single entry point ("address" for example) instead of
splitting between 'print_pci_addr' and 'print_pcie_addr'.
This is folded into the commit to using the rust bindings, since it does not
make sense to recreate the old interface in rust, just to replace it with
the next patches anyway.
This now also creates the commandline for the q35 devices instead
of using 'readconfig' (guarded behind a new machine version).
## Phase 3 - more perl to rust code port (this series)
The HardwareConfig also contains a version comparison, so we can widely reuse
it in many methods, since we need it for the 'addr' interface anyway.
These changes are also folded for the same reason as above.
## Phase 4 - Host and NUMA layouts (the next part)
With all the pieces in place, we can then easily extend the new layout by PCI
switches that are needed for assigning to NUMA nodes and replicating the host
topology for passed through devices.
To answer the question from v2 how this relates to the 'pci-layout' option:
I plan to make this a separate setting on top of the grouped layout instead of
adding more layouts, e.g.:
machine: q35,pci-layout=grouped,hostpci-topology=<flat|numa|host>
* flat (default): every hostpcie device gets its own root port on the root
bus, the layout in this series
* numa: adds a pxb-pcie expander bridge per guest NUMA node and puts the root
ports of that node's devices behind it
* host: additionally replicates the host PCIe switches that more than one
passed through device is behind
The expander bridges go into slots of the grouped layout that are left unused
in this series, so enabling a topology does not move any of the existing
devices, and 'pci-layout' does not need more values for it. qemu-server
provides the NUMA node and the host switches of each device, so nothing has to
be configured per device.
The name and place of the option are not fixed yet, so suggestions are
welcome.
# Notes
* pve-qemu-server-rs is a new git repo, but the crate in it could
easily be integrated somewhere else. Having this as a separate repo
could replace 'qemu-server' at one point though.
* This is an RFC, so comments about the general design/plan are desired.
* Names and crate placement are not fixed, I know that some names I chose are
not optimal, if you do have better names/places, please suggest them.
* Opted to do this in rust for now, since I think that is the best way forward.
If the consensus is to do the layouting changes in perl, or keep some parts in
perl, that's fine with me too and I'll change my efforts accordingly
* @Elias: i did not implement every change:
- the layout type stayed in the types folder (IMO makes more sense)
- chassis_nr stayed the same (number of bridges can't change
dynamically)
- no const fn (i don't think it's possible with a single const fn and
the same short syntax, but if it is, please do show me that)
- didn't rename the pci_ methods (IMO this is fine)
- no thiserror used, IMO not necessary here
changes from v2:
- pve-qemu-server-rs:
* moved some code into later commits where it's necessary
* `HardwareConfig::new` now takes a `HardwareConfigParams` struct, which can
be deserialized directly and rejects unknown keys
* the layout is deserialized directly into `PciLayout`, so an unknown layout
is now an error instead of silently falling back to the legacy one
* hostpcie devices are passed as a list of objects (`{ index => N }`)
instead of plain indices, so they can be extended later without changing
the interface
* use an internal `Arch` enum, so the config can't hold an unknown
architecture
* grouped layout: only set 'multifunction=on' on bridges that share their
slot with other bridges (currently only the net bridges)
* the `Display` implementation of `Device` now prints the configuration ids
(e.g. 'qga0', 'balloon0', 'virtioN') and is exhaustive
* the xhci controller has no index anymore (we can add more ports with hubs)
* document that `version_at_least` records the required pve version, and use
relaxed ordering for it
* check the bridge count with `assert!` instead of `debug_assert!`
* drop the unused anyhow and log dependencies
* code style and doc fixes (`'static` layout lifetime, `match` in
`map_legacy_pci_id`, comments)
- proxmox-perl-rs:
* `new` takes a single hash with the parameters instead of a list of
positional arguments
* `addr` returns undef for devices that are not part of the layout instead
of dying
* use 'this' for the object parameter and add the 'Class method'/'Method'
doc prefixes
* doc fixes
- qemu-server:
* rebased on current master
* construct the HardwareConfig with a parameter hash, and pass the hostpcie
devices as objects
* drop the now unused `PVE::QemuServer::Machine` import from USB.pm
* grouped layout tests: adapt to the bridges without 'multifunction=on'
0: https://bugzilla.proxmox.com/show_bug.cgi?id=7283
pve-qemu-server-rs:
Dominik Csapak (4):
add pve-qemu-server-pci crate for guest PCI address generation
pci: legacy: generate pci bridges
pci: legacy: generate q35 chipset devices and hostpcie root ports
pci: layout: add grouped PCI and PCIe layouts
proxmox-perl-rs:
Dominik Csapak (1):
pve: add bindings for `pve-qemu-server-pci` crate
pve-rs/Cargo.toml | 1 +
pve-rs/Makefile | 1 +
pve-rs/src/bindings/mod.rs | 3 +
pve-rs/src/bindings/pci/hardware_config.rs | 120 +++++++++++++++++++++
pve-rs/src/bindings/pci/mod.rs | 2 +
5 files changed, 127 insertions(+)
create mode 100644 pve-rs/src/bindings/pci/hardware_config.rs
create mode 100644 pve-rs/src/bindings/pci/mod.rs
qemu-server:
Dominik Csapak (4):
pci: use PVE::RS::PCI bindings for addresses and bus devices
tree-wide: use HardwareConfig for the machine version checks
cfg2cmd: q35: generate chipset devices with machine version 11.1+pve1
machine: add 'pci-layout' option
src/PVE/API2/Qemu.pm | 9 +-
src/PVE/QemuServer.pm | 266 +++++++-------
src/PVE/QemuServer/Drive.pm | 7 +-
src/PVE/QemuServer/DriveDevice.pm | 12 +-
src/PVE/QemuServer/Machine.pm | 16 +
src/PVE/QemuServer/PCI.pm | 340 ++----------------
src/PVE/QemuServer/RNG.pm | 6 +-
src/PVE/QemuServer/USB.pm | 59 +--
src/PVE/QemuServer/Virtiofs.pm | 7 +-
src/test/Makefile | 5 +-
src/test/QemuServerTest/CommandLineMocks.pm | 27 ++
.../cfg2cmd/efi-secboot-and-tpm-q35.conf.cmd | 21 +-
src/test/cfg2cmd/q35-grouped-layout.conf | 17 +
src/test/cfg2cmd/q35-grouped-layout.conf.cmd | 47 +++
.../cfg2cmd/q35-grouped-virtiofs-viommu.conf | 14 +
.../q35-grouped-virtiofs-viommu.conf.cmd | 46 +++
src/test/cfg2cmd/q35-ide.conf.cmd | 21 +-
.../cfg2cmd/q35-linux-hostpci-11.1+pve1.conf | 21 ++
.../q35-linux-hostpci-11.1+pve1.conf.cmd | 61 ++++
.../q35-linux-hostpci-driver-keep.conf.cmd | 25 +-
.../q35-linux-hostpci-mapping.conf.cmd | 21 +-
.../q35-linux-hostpci-multifunction.conf.cmd | 21 +-
src/test/cfg2cmd/q35-linux-hostpci-wrong.conf | 16 +
.../cfg2cmd/q35-linux-hostpci-wrong.conf.cmd | 41 +++
...q35-linux-hostpci-x-pci-overrides.conf.cmd | 21 +-
src/test/cfg2cmd/q35-linux-hostpci.conf.cmd | 25 +-
src/test/cfg2cmd/q35-linux-ivshmem.conf.cmd | 21 +-
src/test/cfg2cmd/q35-scsihw2.conf.cmd | 21 +-
src/test/cfg2cmd/q35-simple.conf.cmd | 21 +-
.../cfg2cmd/q35-viommu-intel-aw-bits.conf.cmd | 21 +-
.../q35-viommu-intel-guest-phys-bits.conf.cmd | 21 +-
src/test/cfg2cmd/q35-viommu-intel.conf.cmd | 21 +-
.../q35-viommu-virtio-aw-bits.conf.cmd | 21 +-
src/test/cfg2cmd/q35-viommu-virtio.conf.cmd | 21 +-
src/test/cfg2cmd/q35-win10-hostpci.conf.cmd | 2 +-
.../simple-grouped-virtiofs-viommu.conf | 16 +
.../simple-grouped-virtiofs-viommu.conf.cmd | 45 +++
src/test/cfg2cmd/simple-grouped.conf | 15 +
src/test/cfg2cmd/simple-grouped.conf.cmd | 41 +++
src/test/cfg2cmd/spice-win-grouped.conf | 14 +
src/test/cfg2cmd/spice-win-grouped.conf.cmd | 48 +++
src/test/cfg2cmd/virtiofs-viommu.conf | 16 +
src/test/cfg2cmd/virtiofs-viommu.conf.cmd | 40 +++
src/test/run_pci_addr_checks.pl | 141 --------
44 files changed, 1039 insertions(+), 679 deletions(-)
create mode 100644 src/test/cfg2cmd/q35-grouped-layout.conf
create mode 100644 src/test/cfg2cmd/q35-grouped-layout.conf.cmd
create mode 100644 src/test/cfg2cmd/q35-grouped-virtiofs-viommu.conf
create mode 100644 src/test/cfg2cmd/q35-grouped-virtiofs-viommu.conf.cmd
create mode 100644 src/test/cfg2cmd/q35-linux-hostpci-11.1+pve1.conf
create mode 100644 src/test/cfg2cmd/q35-linux-hostpci-11.1+pve1.conf.cmd
create mode 100644 src/test/cfg2cmd/q35-linux-hostpci-wrong.conf
create mode 100644 src/test/cfg2cmd/q35-linux-hostpci-wrong.conf.cmd
create mode 100644 src/test/cfg2cmd/simple-grouped-virtiofs-viommu.conf
create mode 100644 src/test/cfg2cmd/simple-grouped-virtiofs-viommu.conf.cmd
create mode 100644 src/test/cfg2cmd/simple-grouped.conf
create mode 100644 src/test/cfg2cmd/simple-grouped.conf.cmd
create mode 100644 src/test/cfg2cmd/spice-win-grouped.conf
create mode 100644 src/test/cfg2cmd/spice-win-grouped.conf.cmd
create mode 100644 src/test/cfg2cmd/virtiofs-viommu.conf
create mode 100644 src/test/cfg2cmd/virtiofs-viommu.conf.cmd
delete mode 100755 src/test/run_pci_addr_checks.pl
Summary over all repositories:
49 files changed, 1166 insertions(+), 679 deletions(-)
--
Generated by murpp 0.11.0
next reply other threads:[~2026-11-06 13:26 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 13:25 Dominik Csapak [this message]
2026-11-06 13:25 ` [PATCH pve-qemu-server-rs v3 1/9] add pve-qemu-server-pci crate for guest PCI address generation Dominik Csapak
2026-11-06 13:25 ` [PATCH pve-qemu-server-rs v3 2/9] pci: legacy: generate pci bridges Dominik Csapak
2026-11-06 13:25 ` [PATCH pve-qemu-server-rs v3 3/9] pci: legacy: generate q35 chipset devices and hostpcie root ports Dominik Csapak
2026-11-06 13:25 ` [PATCH pve-qemu-server-rs v3 4/9] pci: layout: add grouped PCI and PCIe layouts Dominik Csapak
2026-11-06 13:25 ` [PATCH proxmox-perl-rs v3 5/9] pve: add bindings for `pve-qemu-server-pci` crate Dominik Csapak
2026-11-06 13:25 ` [PATCH qemu-server v3 6/9] pci: use PVE::RS::PCI bindings for addresses and bus devices Dominik Csapak
2026-11-06 13:25 ` [PATCH qemu-server v3 7/9] tree-wide: use HardwareConfig for the machine version checks Dominik Csapak
2026-11-06 13:25 ` [PATCH qemu-server v3 8/9] cfg2cmd: q35: generate chipset devices with machine version 11.1+pve1 Dominik Csapak
2026-11-06 13:25 ` [PATCH qemu-server v3 9/9] machine: add 'pci-layout' option Dominik Csapak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261106132604.2556840-1-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.