<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
  <title>Libvirt on blog.yarwood.me.uk</title>
  <link>https://blog.yarwood.me.uk/tags/libvirt/</link>
  <description>Recent content in Libvirt on blog.yarwood.me.uk</description>
  <generator>Hugo -- gohugo.io</generator>
  <language>en</language>
  <lastBuildDate>Thu, 03 Sep 2026 00:00:00 +0000</lastBuildDate>
  
    <atom:link href="https://blog.yarwood.me.uk/tags/libvirt/index.xml" rel="self" type="application/rss+xml" />
  
  
    <item>
      <title>Understanding KubeVirt&#39;s Host Kernel and Userspace Dependencies</title>
      <link>https://blog.yarwood.me.uk/2026/09/03/understanding-kubevirt-host-kernel-userspace-dependencies/</link>
      <pubDate>Thu, 03 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.yarwood.me.uk/2026/09/03/understanding-kubevirt-host-kernel-userspace-dependencies/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;https://blog.yarwood.me.uk/img/KubeVirt_logo.png&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href=&#34;https://kubevirt.io/2026/understanding-kubevirt-host-kernel-userspace-dependencies.html&#34;&gt;KubeVirt blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;KubeVirt runs each VM inside a &lt;code&gt;virt-launcher&lt;/code&gt; pod. QEMU and libvirt are userspace processes scheduled like any other container, with host kernel devices (&lt;code&gt;/dev/kvm&lt;/code&gt;, &lt;code&gt;/dev/vhost-net&lt;/code&gt;, &lt;code&gt;/dev/net/tun&lt;/code&gt;) mapped in. Like any workload that probes kernel device capabilities, a mismatch between the userspace stack and the host kernel can cause failures. What makes the virtualization case distinct is that those probe results feed directly into guest device feature negotiation and live-migration Application Binary Interface (ABI), so a kernel/userspace mismatch can surface not just as startup instability, but as broken live migrations across &lt;code&gt;virt-launcher&lt;/code&gt; versions.&lt;/p&gt;
&lt;p&gt;Upstream KubeVirt builds default &lt;code&gt;virt-launcher&lt;/code&gt; images with Enterprise Linux (EL) userspace and runs CI against EL host kernels. When this EL userspace runs on non-EL host kernels, subtle compatibility assumptions can break in ways upstream CI never sees. A recent issue, &lt;a href=&#34;https://github.com/kubevirt/kubevirt/issues/16386&#34;&gt;kubevirt/kubevirt#16386&lt;/a&gt;, brought this reality into sharp focus.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-anatomy-of-a-regression-issue-16386&#34;&gt;The Anatomy of a Regression: Issue #16386&lt;/h2&gt;
&lt;p&gt;During upgrades from KubeVirt v1.6 to v1.7+ on Ubuntu worker nodes, live migrations failed across thousands of running VMs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qemu-kvm: Features 0x1c0010130afffaf unsupported. Allowed features: 0x10179bfffef
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qemu-kvm: Failed to load virtio-net:virtio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qemu-kvm: error while loading state for instance 0x0 of device &amp;#39;virtio-net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qemu-kvm: load of migration failed: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The bit difference &lt;code&gt;0x1c0000000000000&lt;/code&gt; corresponds to three &lt;code&gt;virtio-net&lt;/code&gt; feature bits for &lt;strong&gt;UDP Segmentation Offload (USO)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bit 54&lt;/strong&gt;: &lt;code&gt;VIRTIO_NET_F_GUEST_USO4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bit 55&lt;/strong&gt;: &lt;code&gt;VIRTIO_NET_F_GUEST_USO6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bit 56&lt;/strong&gt;: &lt;code&gt;VIRTIO_NET_F_HOST_USO&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;how-the-layers-diverged&#34;&gt;How the Layers Diverged&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Host Kernel Support:&lt;/strong&gt; Upstream Linux merged TAP USO (&lt;code&gt;TUN_F_USO4&lt;/code&gt;/&lt;code&gt;USO6&lt;/code&gt;) in &lt;strong&gt;Linux 6.2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QEMU Probe:&lt;/strong&gt; At VM startup, QEMU probes the host TAP backend via &lt;code&gt;ioctl(fd, TUNSETOFFLOAD, ...)&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;kernels &amp;gt;= 6.2&lt;/strong&gt; (e.g. Ubuntu 22.04 HWE, 24.04, 26.04), the probe succeeds. QEMU advertised USO, and modern guests negotiated bits 54–56.&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;kernels &amp;lt; 6.2&lt;/strong&gt; (e.g. stock CentOS Stream 9 / RHEL 9 on kernel 5.14), the ioctl returns &lt;code&gt;-EINVAL&lt;/code&gt;. QEMU silently disabled USO.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Downstream Change:&lt;/strong&gt; In &lt;code&gt;qemu-kvm-9.1.0-20.el9&lt;/code&gt; (shipped in KubeVirt 1.7), patch &lt;code&gt;kvm-virtio-net-disable-USO-for-virt-rhel9.6.patch&lt;/code&gt; (&lt;a href=&#34;https://issues.redhat.com/browse/RHEL-80313&#34;&gt;RHEL-80313&lt;/a&gt;) retroactively disabled USO on &lt;code&gt;pc-q35-rhel9.6.0&lt;/code&gt; machine types to fix RHEL 10 → RHEL 9 migration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Failure:&lt;/strong&gt; Existing VMs running on Ubuntu nodes held negotiated USO bits from KubeVirt 1.6. When migrating to the 1.7 &lt;code&gt;virt-launcher&lt;/code&gt;, the new QEMU rejected the incoming state.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;why-ci-missed-it&#34;&gt;Why CI Missed It&lt;/h3&gt;
&lt;p&gt;Upstream KubeVirt release images are built on &lt;strong&gt;CentOS Stream 9&lt;/strong&gt;, and upstream CI runs on &lt;strong&gt;EL9 host kernels (5.14)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Because CI nodes run kernel 5.14, QEMU&amp;rsquo;s TAP probe always failed. &lt;strong&gt;USO was never enabled in CI&lt;/strong&gt;, so migration tests passed cleanly when the downstream QEMU patch dropped the feature. Only clusters running modern non-EL host kernels encountered the breakage.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-three-way-dependency&#34;&gt;The Three-Way Dependency&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;virt-launcher&lt;/code&gt; is a translation layer between the host node and the guest OS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;┌────────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│                      Guest OS                          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│        (Kernel virtio drivers &amp;amp; negotiated ABI)        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└───────────────────────────▲────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            │ Virtio Features
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;┌───────────────────────────▼────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│              virt-launcher Pod (Container)             │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│       Bundled Userspace: QEMU, libvirt, swtpm...       │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│        (Upstream built on CentOS Stream 9/10)          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└───────────────────────────▲────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            │ ioctls (/dev/kvm, TAP, vhost)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;┌───────────────────────────▼────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│                    Host Node Kernel                    │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   (CentOS Stream, RHEL, Ubuntu, Debian, Flatcar...)   │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└────────────────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compatibility requires alignment across all three boundaries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host Kernel ↔ Userspace:&lt;/strong&gt; Does the host kernel support the ioctl flags QEMU/libvirt probe for?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Userspace ↔ Target Userspace:&lt;/strong&gt; Does a newer QEMU in an updated &lt;code&gt;virt-launcher&lt;/code&gt; accept the device state and feature bitmap of the source QEMU?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Userspace ↔ Guest OS:&lt;/strong&gt; Are virtual hardware features stable across migrations without breaking guest ABI?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;aligned-stack-approaches-across-distributions&#34;&gt;Aligned Stack Approaches Across Distributions&lt;/h2&gt;
&lt;p&gt;Distributions address this by aligning the entire stack, ensuring the host kernel and the containerized virtualization userspace are built from the same distribution base.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Harvester&lt;/strong&gt; (built on SUSE / Rancher) does not run upstream CentOS Stream images on its nodes. Instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host OS:&lt;/strong&gt; Runs on an immutable appliance OS derived from &lt;strong&gt;SLE Micro&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Userspace:&lt;/strong&gt; SUSE builds and ships its own &lt;code&gt;virt-launcher&lt;/code&gt; images in &lt;code&gt;registry.suse.com&lt;/code&gt; using &lt;strong&gt;SLES / SLE Micro&lt;/strong&gt; packages from OBS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;OpenShift Virtualization&lt;/strong&gt; (Red Hat) takes a similar approach within the OpenShift platform:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host OS:&lt;/strong&gt; OpenShift enforces &lt;strong&gt;Red Hat CoreOS (RHCOS)&lt;/strong&gt; as the worker node OS, built from the same RHEL base as the container images.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Userspace:&lt;/strong&gt; Red Hat builds and ships &lt;code&gt;virt-launcher&lt;/code&gt; images from RHEL packages, validated against the same RHEL kernel version running on RHCOS worker nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases, because the host kernel and the containerized hypervisor share the same distribution base, they avoid the impedance mismatch that arises from running userspace built for one kernel generation on a host running a different one.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;improving-transparency-current-initiatives&#34;&gt;Improving Transparency: Current Initiatives&lt;/h2&gt;
&lt;p&gt;We are working to make these boundaries explicit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User Guide Requirements (&lt;a href=&#34;https://github.com/kubevirt/user-guide/pull/1029&#34;&gt;#1029&lt;/a&gt;):&lt;/strong&gt; Documented host kernel and virtualization userspace requirements for cluster operators (now merged).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architectural Gap Tracking (&lt;a href=&#34;https://github.com/kubevirt/kubevirt/issues/19000&#34;&gt;kubevirt#19000&lt;/a&gt;):&lt;/strong&gt; Auditing implicit dependencies between &lt;code&gt;virt-launcher&lt;/code&gt;, &lt;code&gt;virt-handler&lt;/code&gt;, and host kernel capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Support Matrix (&lt;a href=&#34;https://github.com/kubevirt/sig-release/issues/69&#34;&gt;sig-release#69&lt;/a&gt;):&lt;/strong&gt; Automatically publishing a release → userspace/kernel matrix by extracting pinned component NEVRAs (&lt;strong&gt;N&lt;/strong&gt;ame, &lt;strong&gt;E&lt;/strong&gt;poch, &lt;strong&gt;V&lt;/strong&gt;ersion, &lt;strong&gt;R&lt;/strong&gt;elease, &lt;strong&gt;A&lt;/strong&gt;rchitecture) from &lt;code&gt;hack/rpm-deps.sh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;moving-forward-shared-community-ownership&#34;&gt;Moving Forward: Shared Community Ownership&lt;/h2&gt;
&lt;p&gt;Documenting assumptions is essential, but documentation alone does not prevent regressions.&lt;/p&gt;
&lt;p&gt;Upstream maintainers validate release artifacts built on Enterprise Linux userspace and tested on EL host kernels. Upstream cannot realistically absorb the testing matrix and debugging burden of arbitrary host distributions without dedicated capacity.&lt;/p&gt;
&lt;p&gt;If you rely on KubeVirt on non-EL hosts (Ubuntu, Debian, Flatcar, Talos, etc.):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Third-Party CI:&lt;/strong&gt; Provide external CI lanes that test these host distributions against KubeVirt pull requests and releases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aligned Virt Stacks:&lt;/strong&gt; Help maintain or validate alternative &lt;code&gt;virt-launcher&lt;/code&gt; bases where host/userspace alignment is required.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;get-involved&#34;&gt;Get Involved&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Share your thoughts on the &lt;a href=&#34;https://groups.google.com/g/kubevirt-dev&#34;&gt;kubevirt-dev mailing list&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Contribute to documentation in &lt;a href=&#34;https://github.com/kubevirt/user-guide/pull/1029&#34;&gt;kubevirt/user-guide#1029&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Join the weekly &lt;a href=&#34;https://github.com/kubevirt/community#community-meetings&#34;&gt;community meetings&lt;/a&gt; to discuss multi-distro CI and testing.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
  
  </channel>
</rss>
