Sorry again for taking so long to respond to this - it's turned into a
ridiculous mental block for me for really unexplainable reasons...
On 5/30/25 8:21 AM, Enrique Llorente via Devel wrote:
This commit introduces a feature enhancement for configuring hostnames in
virtual machines (VMs) using DHCP. It adds new options to the "passt" tool
to set the hostname and fully qualified domain name (FQDN) for VMs. These
map to DHCP option 12 for the hostname and options 81 (IPv4) and 39 (IPv6)
for the FQDN.
The update enables passt to dynamically assign hostnames to DHCP-aware
VMs. To achieve this, the commit adds two fields to the passt domain XML
backend. These fields allow passt to configure the hostname and FQDN for
the virtual machine, ensuring smooth integration with the DHCP protocol.
This improvement is particularly valuable in environments where VMs need
dynamic hostname configuration, enhancing flexibility and automation in
virtualized network setups.
libvirt: Integrate passt --hostname --fqdn options
Not sure what the above "tag-looking" line is for. Is there some
automation that consumes it?
Resolves: https://issues.redhat.com/browse/RHEL-79806
Signed-off-by: Enrique Llorente <ellor...@redhat.com>
---
Compared to v1 this fix the mapping between backend fqdn and hostname
docs/formatdomain.rst | 8 +++++---
src/conf/domain_conf.c | 10 +++++++++-
src/conf/domain_conf.h | 2 ++
src/conf/schemas/domaincommon.rng | 6 ++++++
src/qemu/qemu_passt.c | 6 ++++++
tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml | 2 +-
tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml | 2 +-
tests/qemuxmlconfdata/net-user-passt.xml | 2 +-
.../net-vhostuser-passt.x86_64-latest.xml | 2 +-
tests/qemuxmlconfdata/net-vhostuser-passt.xml | 2 +-
10 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 8753ee9c23..9c80aa9270 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -5372,10 +5372,12 @@ 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
+message log, 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
+guest for forwarding traffic upstream and the ``hostname`` and ``fqdn``
You're missing an Oxford(ish) Comma just after "upstream" :-)
+will conigure the DHCP option 12 hostname and DHCP option 81 and DHCPv6
+option 39 fqdn attribute.
(pardon this interlude...)
For the curious, here are links to the relevant RFCs:
https://datatracker.ietf.org/doc/html/rfc2132#section-3.14 - DHCPv4
option 12
https://datatracker.ietf.org/doc/html/rfc4702 - DHCPv4 option 81
https://datatracker.ietf.org/doc/html/rfc4704 - DHCPv6 option 39
In a previous attempt at reviewing this patch, I spent (wasted) a lot of
time querying an AI chatbot about the details of these options and their
usage, naively writing a bunch of text based on the provided details,
and only then looking up the source material (the RFCs, you know - like
in the "Beforefore Time"?) to verify the details, just to learn that the
chatbot had misled me and so everything I'd written was incorrect (well,
most of it anyway).
In the end what I've learned (other than that everything an AI chatbot
tells you really is just as suspect as Gary Marcus and others say it is) is:
1) while DHCPv4 option 12 can bet sent from server to client without the
client previously sending an option 12, for DHCPv4 option 81 / v6 option
39, the server can only send those options in a response if the client
previously included the same option in its request (*However*, the
payload of the option sent by the client could just be empty, which I'm
guessing is often the case).
2) Even though option 12 is named "host name", it is totally permissible
for an option 12 to contain a FQDN (in either direction) rather than
just a plain unqualified host name. (And dnsmasq, as one example,
handles this quite well).
3) Even though options 81/39 are named "FQDN", it is also totally
permissible for the client to send an unqualified host name in an option
81/39, after which the server can/should respond with an option 81/39
that either adds the domain onto that hostname, or potentially provides
a completely different fqdn.
3) If DHCPv4 negotiation has both an option 12 and option 81, the option
12 is ignored in favor of option 81.
4) Really, *none* of this has any bearing on this patch at all (I just
thought it was interesting and didn't want the time I spent parsing
through the RFCs to be completely wasted :-)
(Note that, based on the original descriptions from the aforementioned
(but unnamed) chatbot, I had created an entire universe (with
accompanying long diatribe) where DHCP option 81 was being misused. Good
thing I took the time to look up the primary source and read/understand
it myself.)
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
Along with adding descriptions of the new attributes, they should be
added to at least one existing example XML in the documentation, or a
new example added if it's more complicated. (Actually it can also be
very useful to include an example of the XML (and the change it causes
to the passt commandline) in the commit log message - makes it easy to
search through "git log" for that commit).
(What? Is it time for another interlude already? Yes. Yes it is.)
As usual, I spent way too much time thinking about what is the ideal
place for these options in the XML grammar, my main concern being that
adding more and more attributes to the <backend> element could become
unwieldy, but also that the same options might be useful in other
situations and/or be used as templates for future similar additional
options.
One idea I had was that we could add a <dhcp> subelement to <backend>
where dhcp options could be added, e.g.:
<interface type='vhostuser'>
<backend type='passt>
<dhcp hostname='blah' fqdn='blah.blorp.com'/>
</backend>
I suppose that would have been nicer if we could *consistently* put all
the things that are used to configure the host-side DHCP server in this
mythical <dhcp> element, but that possibility was eliminated when the
original passt support re-used the pre-existing toplevel <ip> subelement
to configure passt's DHCP server IP addresses (<ip> was originally added
to configure the IP addresses of interfaces when an LXC domain is
created - they aren't just "available for the domain to request" from a
DHCP server, but are directly configured using the netlink equivalent of
"ip addr add"). We can't move that into backend/dhcp, meaning <dhcp>
would only contain *some* of the dhcp options, and there's probably no
point in only doing it for some DHCP options, so that idea is a non-starter.
Another possibility I thought of was to put these attributes either
directly at the top level (which would be completely nonsensical), or in
another existing subelement, e.g. <ip> (doesn't work because the "fqdn"
option applies to both IPv4 and IPv6 of the same <interface>, and also
it would mean that every *other* use of <ip> would now have this new
attribute that we would need to check for just to be sure it wasn't
added in a place where it didn't make sense), possibly in <source> ("How
is that better than putting it in <backend>?") or maybe a *new* toplevel
subelement ("And call it *what*?" is the proper rhetorical question
here). So - no, no, no, and (checks list) no.
I do think it is worthwhile to consider how some other backend might
make use of these options, for example let's say we decided to enhance
<interface type='network'> by supporting use of the <ip> in the domain
xml to add a static host entry to the network; it would be totally
reasonable to expect that we could also use a host name from the
<interface> in that static host entry. With the XML implemented by this
patch, that would look like:
<interface type='network'>
<source network='blah'/>
<mac address='52:54:00:A1:BE:EF'/>
<ip address='192.168.128.22'/>
<backend hostname='xyzzy'/>
...
</interface>
(which would temporarily add a static host entry like this to the
libvirt virtual network "blah"):
<host mac='52:54:00:A1:BE:EF' name='xyzzy' ip='192.168.128.22'/>
I mean... it seems kind of arbitrary that "hostname" is in the <backend>
subelement while the ip address isn't, but then really in the end isn't
*everything* arbitrary?? (This is starting to sound like something The
Dude would say).
So, after all my internal wrestling with the placement and naming of
these two options, I think I'll just declare all my pondering as
pointless, and agree that what you've proposed is just fine (unless
someone else has a better idea in the next couple days :-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b3b0bd7329..15143f8fa2 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2909,6 +2909,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);
@@ -9757,6 +9759,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);
@@ -20757,7 +20761,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;
@@ -24838,6 +24844,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);
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 58b97a2b54..79fd2f1f63 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1067,6 +1067,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 */
A better description would be good, something like "DHCPv4 hostname
(option 12)"
+ char *fqdn; /* fully qualified domain name of the passt process */
Maybe "DHCP fully qualified domain name (option 81/v4 39/v6)"?
};
struct _virDomainNetPortForwardRange {
diff --git a/src/conf/schemas/domaincommon.rng
b/src/conf/schemas/domaincommon.rng
index 5597d5a66b..f64199ca18 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -3913,6 +3913,12 @@
<ref name="absFilePath"/>
</attribute>
</optional>
+ <optional>
+ <attribute name="hostname"/>
+ </optional>
+ <optional>
+ <attribute name="fqdn"/>
+ </optional>
<optional>
<attribute name="hostname">
<ref name="dnsName"/>
</attribute>
</optional>
<optional>
<attribute name="fqdn">
<ref name="dnsName"/>
</attribute>
</optional>
And while I'm on the subject - I also notice that there was nothing
added to src/conf/domain_validate.c to reject someone adding hostname or
fqdn when the backend isn't type='passt' - it will happily accept them
and then they will of course be ignored. (Noticing this made me realize
that there is also no validation check for the existing logFile
attribute, which I will send in a separate patch after we get this patch
pushed).
I've attached a patch to this reply that fixes these two problems (but
not the documentation issues I mentioned above, ie. adding the new
attributes to an example in formatdomain.rst and adding an example of an
<interface> with the new <backend> options in the commit log).
Otherwise this all looks fine. I'm going to wait a couple days to see if
anyone has any useful response to my despair about XML
naming/organization, and then if nobody has a better idea and you're
okay with the changes in the attached patchfile, I'll add the example
XML in the two places and push it.
Thanks for the contribution. I promise I'll respond in a more timely
manner next time.
</element>
</optional>
<optional>
diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c
index fcc34de384..81e5c51f6c 100644
--- a/src/qemu/qemu_passt.c
+++ b/src/qemu/qemu_passt.c
@@ -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];
diff --git a/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
b/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
index cfe07cc627..77da297936 100644
--- a/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
+++ b/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
@@ -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'/>
diff --git a/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
b/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
index d7e0ef5f90..917a9edaa0 100644
--- a/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
+++ b/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
@@ -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'/>
diff --git a/tests/qemuxmlconfdata/net-user-passt.xml
b/tests/qemuxmlconfdata/net-user-passt.xml
index 20c9f50542..80d15de2ed 100644
--- a/tests/qemuxmlconfdata/net-user-passt.xml
+++ b/tests/qemuxmlconfdata/net-user-passt.xml
@@ -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'/>
diff --git a/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml
b/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml
index 529aff11f8..5802754c4b 100644
--- a/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml
+++ b/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml
@@ -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'>
diff --git a/tests/qemuxmlconfdata/net-vhostuser-passt.xml
b/tests/qemuxmlconfdata/net-vhostuser-passt.xml
index 71b845329b..0a37511a0f 100644
--- a/tests/qemuxmlconfdata/net-vhostuser-passt.xml
+++ b/tests/qemuxmlconfdata/net-vhostuser-passt.xml
@@ -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'>
From 44b228da4a5091143ba63b542d7f2a12383dfb39 Mon Sep 17 00:00:00 2001
From: Laine Stump <la...@redhat.com>
Date: Thu, 7 Aug 2025 15:27:32 -0400
Subject: [PATCH] fixup schema for previous commit add validation to only allow
backend hostname/fqdn if type='passt'
Signed-off-by: Laine Stump <la...@redhat.com>
---
src/conf/domain_validate.c | 20 ++++++++++++++++----
src/conf/schemas/domaincommon.rng | 8 ++++++--
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 40edecef83..043169b234 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -2273,10 +2273,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) {
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index d580235a00..ea1a07e383 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -3979,10 +3979,14 @@
</attribute>
</optional>
<optional>
- <attribute name="hostname"/>
+ <attribute name="hostname">
+ <ref name="dnsName"/>
+ </attribute>
</optional>
<optional>
- <attribute name="fqdn"/>
+ <attribute name="fqdn">
+ <ref name="dnsName"/>
+ </attribute>
</optional>
</element>
</optional>
--
2.49.0