]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: support setting guest hostname/fqdn using DHCP on passt-backed interfaces
authorEnrique Llorente via Devel <devel@lists.libvirt.org>
Fri, 30 May 2025 12:21:23 +0000 (14:21 +0200)
committerLaine Stump <laine@redhat.com>
Wed, 10 Sep 2025 17:12:41 +0000 (13:12 -0400)
This commit introduces support for configuring hostnames in virtual
machines (VMs) using DHCP via an interface backed by the passt
transport. This is done with the new 'hostname' and 'fqdn' (Fully
Qualified Domain Name) attributes in the <backend> subelement of
<interface>. The values set in these attributes are added to the passt
commandline for the interface (with the --hostname and --fqdn
options), and passt will then send the settings to the guest by adding
options to the DHCP response when the interface is started - for IPv4,
hostname will be sent in option 12, or the FQDN will be sent in option
81, and for IPv6 the FQDN will be sent using option 39.

This will enable a management application to easily configure guest
hostnames without intervening in the guest's disk image (as long as
the guest uses DHCP for it's network interface configuration).

Here is an example of setting the hostname and fqdn for a guest (in
practice, you would only use one or the other, since according to the
RFC if option 81 is sent to the guest, option 12 should not be sent).

   <interface type='vhostuser'>
     <backend type='passt' hostname='bob' fqdn='bob.example.com'/>
     ...

Resolves: https://issues.redhat.com/browse/RHEL-79806
Signed-off-by: Enrique Llorente <ellorent@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
docs/formatdomain.rst
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/domain_validate.c
src/conf/schemas/domaincommon.rng
src/qemu/qemu_passt.c
tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
tests/qemuxmlconfdata/net-user-passt.xml
tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml
tests/qemuxmlconfdata/net-vhostuser-passt.xml

index b327ff87a75a955bb13bc4448511be20c6a54e09..f50dce477fdc4b9c1f93d70e7e89f76bc3f635a6 100644 (file)
@@ -5468,19 +5468,26 @@ host towards the rest of the network, it will always appear as if it
 came from the host's IP.
 
 There are a few other options that are configurable only for the passt
-backend.  For example, the ``<backend>`` attribute ``logFile`` can be
-used to tell the passt process for this interface where to write its
-message log, and the ``<source>`` attribute ``dev`` can tell it a
-particular host interface to use when deriving the routes given to the
-guest for forwarding traffic upstream.  Due to the design decisions of
-passt, when using SELinux on the host, it is recommended that the log
-file reside in the runtime directory of the user under which the passt
-process will run, most probably ``/run/user/$UID`` (where ``$UID`` is
-the UID of that user), e.g. ``/run/user/1000``. Be aware that libvirt
-does not create this directory if it does not already exist to avoid
-possible, however unlikely, issues with orphaned directories or
-permissions, etc. The logfile attribute is meant mostly for debugging,
-so it shouldn't be set under normal circumstances.
+backend.  For example, the ``<backend>`` subelement's attribute
+``logFile`` can be used to tell the passt process for this interface
+where to write its message log (:since:`since 9.0.0`)[\*], while the
+``hostname`` attribute is used to set the hostname sent to the guest
+in a DHCPv4 response (using option 12) (:since:`since 11.8.0`), and
+``fqdn`` sets the "fully qualified domain name" sent to the guest in
+DHCPv4 response option 81 and DHCPv6 response option 39 (:since:`since
+11.8.0`).  Also, the ``<source>`` subelement attribute ``dev`` can
+tell passt a particular host interface to use when deriving the routes
+given to the guest for forwarding traffic upstream.
+
+[\*] *Due to the design decisions of passt, when using SELinux on the
+host, it is recommended that the log file reside in the runtime
+directory of the user under which the passt process will run, most
+probably ``/run/user/$UID`` (where ``$UID`` is the UID of that user),
+e.g. ``/run/user/1000``. Be aware that libvirt does not create this
+directory if it does not already exist to avoid possible, however
+unlikely, issues with orphaned directories or permissions, etc. The
+logfile attribute is meant mostly for debugging, so it shouldn't be
+set under normal circumstances.*
 
 Additionally, when passt is used, multiple ``<portForward>`` elements
 can be added to forward incoming network traffic for the host to this
@@ -5514,7 +5521,7 @@ ports **with the exception of some subset**.
    <devices>
      ...
      <interface type='user'>
-       <backend type='passt' logFile='/run/user/$UID/passt-domain.log'/>
+       <backend type='passt' hostname='bob' logFile='/run/user/$UID/passt-domain.log'/>
        <mac address="00:11:22:33:44:55"/>
        <source dev='eth0'/>
        <ip family='ipv4' address='172.17.5.4' prefix='24'/>
@@ -6657,7 +6664,7 @@ setting guest-side IP addresses with ``<ip>`` and port forwarding with
    ...
    <devices>
      <interface type='vhostuser'>
-       <backend type='passt'/>
+       <backend type='passt' fqdn='bob.example.com'/>
        <mac address='52:54:00:3b:83:1a'/>
        <source dev='enp1s0'/>
        <ip address='10.30.0.5' prefix='24'/>
index 8c0bf6392559acff22945989cdac479959f31b8d..281846dfbe1f3080bb3b11d2c78c649e409080bf 100644 (file)
@@ -2919,6 +2919,8 @@ virDomainNetDefFree(virDomainNetDef *def)
     g_free(def->backend.tap);
     g_free(def->backend.vhost);
     g_free(def->backend.logFile);
+    g_free(def->backend.hostname);
+    g_free(def->backend.fqdn);
     virDomainNetTeamingInfoFree(def->teaming);
     g_free(def->virtPortProfile);
     g_free(def->script);
@@ -9804,6 +9806,8 @@ virDomainNetBackendParseXML(xmlNodePtr node,
     }
 
     def->backend.logFile = virXMLPropString(node, "logFile");
+    def->backend.hostname = virXMLPropString(node, "hostname");
+    def->backend.fqdn = virXMLPropString(node, "fqdn");
 
     if (tap)
         def->backend.tap = virFileSanitizePath(tap);
@@ -20880,7 +20884,9 @@ virDomainNetBackendIsEqual(virDomainNetBackend *src,
     if (src->type != dst->type ||
         STRNEQ_NULLABLE(src->tap, dst->tap) ||
         STRNEQ_NULLABLE(src->vhost, dst->vhost) ||
-        STRNEQ_NULLABLE(src->logFile, dst->logFile)) {
+        STRNEQ_NULLABLE(src->logFile, dst->logFile) ||
+        STRNEQ_NULLABLE(src->hostname, dst->hostname) ||
+        STRNEQ_NULLABLE(src->fqdn, dst->fqdn)) {
         return false;
     }
     return true;
@@ -25019,6 +25025,8 @@ virDomainNetBackendFormat(virBuffer *buf,
     virBufferEscapeString(&attrBuf, " tap='%s'", backend->tap);
     virBufferEscapeString(&attrBuf, " vhost='%s'", backend->vhost);
     virBufferEscapeString(&attrBuf, " logFile='%s'", backend->logFile);
+    virBufferEscapeString(&attrBuf, " hostname='%s'", backend->hostname);
+    virBufferEscapeString(&attrBuf, " fqdn='%s'", backend->fqdn);
     virXMLFormatElement(buf, "backend", &attrBuf, NULL);
 }
 
index eca820892ec9533517597962930ffc7a8b2397c5..39807b5fe3436e2ae83c1b9e961f704d853b12a4 100644 (file)
@@ -1077,6 +1077,8 @@ struct _virDomainNetBackend {
     char *vhost;
     /* The following are currently only valid/used when backend type='passt' */
     char *logFile;  /* path to logfile used by passt process */
+    char *hostname; /* hostname of the passt process */
+    char *fqdn; /* fully qualified domain name of the passt process */
 };
 
 struct _virDomainNetPortForwardRange {
index 60a2e46b7ec09f10e74a40e1a94179fe75a1d68a..93a2bc9b0185275659c617c503f19703dd848bfc 100644 (file)
@@ -2284,10 +2284,22 @@ virDomainNetDefValidate(const virDomainNetDef *net)
         }
     }
 
-    if (net->sourceDev && net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("The 'dev' attribute of the <source> element can only be used with <interface> type='user' or type='vhostuser' if the <backend> type='passt'"));
-        return -1;
+    if (net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST) {
+        if (net->sourceDev) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("The 'dev' attribute of the <source> element can only be used with <interface> type='user' or type='vhostuser' if the <backend> type='passt'"));
+            return -1;
+        }
+        if (net->backend.fqdn) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("The 'fqdn' attribute of the <backend> element can only be used with the <backend> type='passt'"));
+            return -1;
+        }
+        if (net->backend.hostname) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("The 'fqdn' attribute of the <backend> element can only be used with the <backend> type='passt'"));
+            return -1;
+        }
     }
 
     if (net->nPortForwards > 0) {
index 298afe0b7c47444a29fb407088a8e9b42cdc91db..b9230a35b478c0a17d832477c47eaaa98c690839 100644 (file)
               <ref name="absFilePath"/>
             </attribute>
           </optional>
+          <optional>
+            <attribute name="hostname">
+              <ref name="dnsName"/>
+            </attribute>
+          </optional>
+          <optional>
+            <attribute name="fqdn">
+              <ref name="dnsName"/>
+            </attribute>
+          </optional>
         </element>
       </optional>
       <optional>
index fcc34de384b7aea3241f0ccdc1488aa7091f26db..81e5c51f6c03fffd4d79e639d09cf0b6ecc8c495 100644 (file)
@@ -229,6 +229,12 @@ qemuPasstStart(virDomainObj *vm,
     if (net->backend.logFile)
         virCommandAddArgList(cmd, "--log-file", net->backend.logFile, NULL);
 
+    if (net->backend.hostname)
+        virCommandAddArgList(cmd, "--hostname", net->backend.hostname, NULL);
+
+    if (net->backend.fqdn)
+        virCommandAddArgList(cmd, "--fqdn", net->backend.fqdn, NULL);
+
     /* Add IP address info */
     for (i = 0; i < net->guestIP.nips; i++) {
         const virNetDevIPAddr *ip = net->guestIP.ips[i];
index cfe07cc62727f1a09fb97f951d6ae353ea695fd1..77da2979367d8328a270494fbc8e562e0c0972f1 100644 (file)
@@ -50,7 +50,7 @@
         <range start='443' to='344'/>
       </portForward>
       <model type='rtl8139'/>
-      <backend type='passt' logFile='/var/log/loglaw.blog'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog' hostname='hostname1' fqdn='hostname1.test.local'/>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
     </interface>
     <input type='mouse' bus='ps2'/>
index d7e0ef5f90d7823bc086b60fd8deeeafa3590476..917a9edaa0c3e054427a906e242970631a15f1d1 100644 (file)
@@ -50,7 +50,7 @@
         <range start='443' to='344'/>
       </portForward>
       <model type='rtl8139'/>
-      <backend type='passt' logFile='/var/log/loglaw.blog'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog' hostname='hostname1' fqdn='hostname1.test.local'/>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
     </interface>
     <input type='mouse' bus='ps2'/>
index 20c9f50542cf8f3ce8f95f460b05d78368415be9..80d15de2edceaa825278b102ff34e0b4e1bad033 100644 (file)
@@ -47,7 +47,7 @@
         <range start='443' to='344'/>
       </portForward>
       <model type='rtl8139'/>
-      <backend type='passt' logFile='/var/log/loglaw.blog'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog' hostname='hostname1' fqdn='hostname1.test.local'/>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
     </interface>
     <input type='mouse' bus='ps2'/>
index 529aff11f82c88bd7ef56d70e252ee2cb4f781b5..5802754c4bc5f266f907828a986a01b87a6d8ec4 100644 (file)
@@ -53,7 +53,7 @@
         <range start='443' to='344'/>
       </portForward>
       <model type='virtio'/>
-      <backend type='passt' logFile='/var/log/loglaw.blog'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog' hostname='hostname1' fqdn='hostname1.test.local'/>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
     </interface>
     <interface type='vhostuser'>
index 71b845329bba2db50348b0cbad06aca382c36a5b..0a37511a0fdb95fb2fbdb319dcf1079aeed2ec1e 100644 (file)
@@ -50,7 +50,7 @@
         <range start='443' to='344'/>
       </portForward>
       <model type='virtio'/>
-      <backend type='passt' logFile='/var/log/loglaw.blog'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog' hostname='hostname1' fqdn='hostname1.test.local'/>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
     </interface>
     <interface type='vhostuser'>