]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Reflect MAC address change in live domain XML
authorMichal Privoznik <mprivozn@redhat.com>
Tue, 27 Jun 2023 15:13:33 +0000 (17:13 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 25 Mar 2025 10:49:30 +0000 (11:49 +0100)
If a guest changes MAC address on its vNIC, then QEMU emits
NIC_RX_FILTER_CHANGED event (the event is emitted in other cases
too, but that's not important right now). Now, domain XML allows
users to chose whether to trust these events or not:

  <interface trustGuestRxFilters='yes|no'/>

For the 'no' case no action is performed and the event is
ignored. But for the 'yes' case, some host side features of
corresponding vNIC (well tap/macvtap device) are tweaked to
reflect changed MAC address. But what is missing is reflecting
this new MAC address in domain XML.

Basically, what happens is: the host sees traffic with new MAC
address, all tools inside the guest see the new MAC address
(including 'virsh domifaddr --source agent') which makes it
harder to match device in the guest with the one in the domain
XML.

Therefore, report this new MAC address as another attribute of
the <mac/> element:

  <mac address="52:54:00:a4:6f:91" currentAddress="00:11:22:33:44:55"/>

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
docs/formatdomain.rst
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/schemas/domaincommon.rng
src/qemu/qemu_domain.c
src/qemu/qemu_driver.c

index aae58fab600c7f96132d99d910fee4a4e728157c..3be7ee0ff4c19259388bb98e915074d88ae5715e 100644 (file)
@@ -5052,6 +5052,11 @@ when it's in the reserved VMware range by adding a ``type="static"`` attribute
 to the ``<mac/>`` element. Note that this attribute is useless if the provided
 MAC address is outside of the reserved VMWare ranges.
 
+:since:`Since 11.2.0`, the ``<mac/>`` element can optionally contain
+``currentAddress`` attribute (output only), which contains new MAC address if the
+guest changed it. This is currently implemented only for QEMU/KVM and requires
+setting ``trustGuestRxFilters`` to ``yes``.
+
 :since:`Since 7.3.0`, one can set the ACPI index against network interfaces.
 With some operating systems (eg Linux with systemd), the ACPI index is used
 to provide network interface device naming, that is stable across changes
index 7ea74b9b64a69d6334168170410c9244ba42ebc7..99ecb030677783391354595d4c53c5a8bad2a46e 100644 (file)
@@ -2853,6 +2853,7 @@ virDomainNetDefFree(virDomainNetDef *def)
     if (!def)
         return;
 
+    g_free(def->currentAddress);
     g_free(def->modelstr);
 
     switch (def->type) {
@@ -24948,6 +24949,11 @@ virDomainNetDefFormat(virBuffer *buf,
         virBufferAsprintf(&macAttrBuf, " type='%s'", virDomainNetMacTypeTypeToString(def->mac_type));
     if (def->mac_check != VIR_TRISTATE_BOOL_ABSENT)
         virBufferAsprintf(&macAttrBuf, " check='%s'", virTristateBoolTypeToString(def->mac_check));
+    if (def->currentAddress &&
+        !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
+        virBufferAsprintf(&macAttrBuf, " currentAddress='%s'",
+                          virMacAddrFormat(def->currentAddress, macstr));
+    }
     virXMLFormatElement(buf, "mac", &macAttrBuf, NULL);
 
     if (publicActual) {
index ed39b60f6d65a4c73814321bede6e4997ab28ce1..0d1dd954aee4bada0d7a965f3a00d4ab13f1de12 100644 (file)
@@ -1091,6 +1091,9 @@ struct _virDomainNetDef {
     bool mac_generated; /* true if mac was *just now* auto-generated by libvirt */
     virDomainNetMacType mac_type;
     virTristateBool mac_check;
+    virMacAddr *currentAddress; /* MAC address from query-rx-filter (as reported
+                                   by guest). Not parsed from domain XML. Output
+                                   only. */
     int model; /* virDomainNetModelType */
     char *modelstr;
     union {
index 8bf909e6fb249a9543c834eb6e9afa18e54625cc..5597d5a66baf036c096daba312a1de16b18d068d 100644 (file)
               <ref name="virYesNo"/>
             </attribute>
           </optional>
+          <optional>
+            <attribute name="currentAddress">
+              <ref name="uniMacAddr"/>
+            </attribute>
+          </optional>
           <empty/>
         </element>
       </optional>
index fcdf28f3fceb6c081708a776252da908f23b4003..7f89b193f9dcf98c6c349e783bd47c25cb8f4b92 100644 (file)
@@ -11072,6 +11072,19 @@ syncNicRxFilterMulticast(char *ifname,
 }
 
 
+/**
+ * qemuDomainSyncRxFilter:
+ * @vm: domain object
+ * @def: domain interface definition
+ * @asyncJob: async job type
+ *
+ * Fetch new state of RX Filter and set host side of the interface
+ * accordingly (e.g. reflect MAC address change on macvtap).
+ *
+ * Reflect changed MAC address in the domain definition.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
 int
 qemuDomainSyncRxFilter(virDomainObj *vm,
                        virDomainNetDef *def,
@@ -11080,6 +11093,7 @@ qemuDomainSyncRxFilter(virDomainObj *vm,
     qemuDomainObjPrivate *priv = vm->privateData;
     g_autoptr(virNetDevRxFilter) guestFilter = NULL;
     g_autoptr(virNetDevRxFilter) hostFilter = NULL;
+    virMacAddr *oldMac = NULL;
     int rc;
 
     if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
@@ -11125,6 +11139,24 @@ qemuDomainSyncRxFilter(virDomainObj *vm,
             return -1;
     }
 
+    if (def->currentAddress)
+        oldMac = def->currentAddress;
+    else
+        oldMac = &def->mac;
+
+    if (virMacAddrCmp(oldMac, &guestFilter->mac)) {
+        /* Reflect changed MAC address in the domain XML. */
+        if (virMacAddrCmp(&def->mac, &guestFilter->mac)) {
+            if (!def->currentAddress) {
+                def->currentAddress = g_new0(virMacAddr, 1);
+            }
+
+            virMacAddrSet(def->currentAddress, &guestFilter->mac);
+        } else {
+            VIR_FREE(def->currentAddress);
+        }
+    }
+
     return 0;
 }
 
index 3cf21380ed8e7b032cd28b665aa1ac6111bf9fa2..20b94ccdf0e3b0a4a3288a7730bd899e352c829f 100644 (file)
@@ -3689,7 +3689,7 @@ processNicRxFilterChangedEvent(virDomainObj *vm,
               "from domain %p %s",
               devAlias, vm, vm->def->name);
 
-    if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0)
+    if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0)
         return;
 
     if (!virDomainObjIsActive(vm)) {