[PATCH] qemu_driver:report guest interface informations

scuzhanglei posted 1 patch 2 years, 7 months ago
Test syntax-check failed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20210827034233.407481-1-greatzhanglei@gmail.com
There is a newer version of this series
NEWS.rst                         |  5 ++
include/libvirt/libvirt-domain.h |  1 +
src/libvirt-domain.c             | 12 +++++
src/qemu/qemu_agent.c            |  9 ++--
src/qemu/qemu_agent.h            |  3 +-
src/qemu/qemu_driver.c           | 88 +++++++++++++++++++++++++++++++-
tests/qemuagenttest.c            |  2 +-
tools/virsh-domain.c             |  2 +
8 files changed, 115 insertions(+), 7 deletions(-)
[PATCH] qemu_driver:report guest interface informations
Posted by scuzhanglei 2 years, 7 months ago
Signed-off-by: scuzhanglei <greatzhanglei@gmail.com>
---
 NEWS.rst                         |  5 ++
 include/libvirt/libvirt-domain.h |  1 +
 src/libvirt-domain.c             | 12 +++++
 src/qemu/qemu_agent.c            |  9 ++--
 src/qemu/qemu_agent.h            |  3 +-
 src/qemu/qemu_driver.c           | 88 +++++++++++++++++++++++++++++++-
 tests/qemuagenttest.c            |  2 +-
 tools/virsh-domain.c             |  2 +
 8 files changed, 115 insertions(+), 7 deletions(-)

diff --git a/NEWS.rst b/NEWS.rst
index 21df0e1602..fde781b320 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -19,6 +19,11 @@ v7.7.0 (unreleased)
 
 * **Improvements**
 
+  * qemu: Report guest interfaces information in ``virDomainGetGuestInfo``
+
+    Libvirt is now able to report interfaces from the guest's
+    perspective (using guest agent).
+
 * **Bug fixes**
 
 
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 7ef8ac51e5..b088847725 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5074,6 +5074,7 @@ typedef enum {
     VIR_DOMAIN_GUEST_INFO_HOSTNAME = (1 << 3), /* return hostname information */
     VIR_DOMAIN_GUEST_INFO_FILESYSTEM = (1 << 4), /* return filesystem information */
     VIR_DOMAIN_GUEST_INFO_DISKS = (1 << 5), /* return disks information */
+    VIR_DOMAIN_GUEST_INFO_INTERFACES = (1 << 6), /* return interfaces information */
 } virDomainGuestInfoTypes;
 
 int virDomainGetGuestInfo(virDomainPtr domain,
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index a8a386e839..dfd84b4744 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12586,6 +12586,18 @@ virDomainSetVcpu(virDomainPtr domain,
  * virTypedParamsFree to free memory returned in @params.
  *
  * Returns 0 on success, -1 on error.
+ * VIR_DOMAIN_GUEST_INFO_INTERFACES:
+ *  Returns information about the interfaces within the domain. the typed
+ *  parameter keys are in this format:
+ *
+ *      "if.count" - the number of interfaces defined on this domain
+ *                    as an unsigned int
+ *      "if.<num>.name" - interface name in the guest
+ *      "if.<num>.hwaddr" -  hardware address of interface
+ *      "if.<num>.addr.count - the number of ip addresses of interface
+ *      "if.<num>.addr.<num>.type" - the type of ip address(e.g. ipv4)
+ *      "if.<num>.addr.<num>.addr" - the ip address
+ *      "if.<num>.addr.<num>.prefix" - the number of bits of ip address prefix
  */
 int virDomainGetGuestInfo(virDomainPtr domain,
                           unsigned int types,
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index 5f421be6f6..a7f943e0dc 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -2245,17 +2245,20 @@ qemuAgentGetAllInterfaceAddresses(virDomainInterfacePtr **ifaces_ret,
  */
 int
 qemuAgentGetInterfaces(qemuAgent *agent,
-                       virDomainInterfacePtr **ifaces)
+                       virDomainInterfacePtr **ifaces,
+                       bool report_unsupported)
 {
     g_autoptr(virJSONValue) cmd = NULL;
     g_autoptr(virJSONValue) reply = NULL;
     virJSONValue *ret_array = NULL;
+    int rc;
 
     if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL)))
         return -1;
 
-    if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
-        return -1;
+    if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
+                                   report_unsupported)) < 0)
+        return rc;
 
     if (!(ret_array = virJSONValueObjectGetArray(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h
index 81b45b8e5d..94eab9de9f 100644
--- a/src/qemu/qemu_agent.h
+++ b/src/qemu/qemu_agent.h
@@ -151,7 +151,8 @@ int qemuAgentSetTime(qemuAgent *mon,
                      bool sync);
 
 int qemuAgentGetInterfaces(qemuAgent *mon,
-                           virDomainInterfacePtr **ifaces);
+                           virDomainInterfacePtr **ifaces,
+                           bool report_unsupported);
 
 int qemuAgentSetUserPassword(qemuAgent *mon,
                              const char *user,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f1f961c51c..0b803c392b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -18957,7 +18957,7 @@ qemuDomainInterfaceAddresses(virDomainPtr dom,
             goto endjob;
 
         agent = qemuDomainObjEnterAgent(vm);
-        ret = qemuAgentGetInterfaces(agent, ifaces);
+        ret = qemuAgentGetInterfaces(agent, ifaces, true);
         qemuDomainObjExitAgent(vm, agent);
 
     endjob:
@@ -19903,7 +19903,8 @@ static const unsigned int qemuDomainGetGuestInfoSupportedTypes =
     VIR_DOMAIN_GUEST_INFO_TIMEZONE |
     VIR_DOMAIN_GUEST_INFO_HOSTNAME |
     VIR_DOMAIN_GUEST_INFO_FILESYSTEM |
-    VIR_DOMAIN_GUEST_INFO_DISKS;
+    VIR_DOMAIN_GUEST_INFO_DISKS |
+    VIR_DOMAIN_GUEST_INFO_INTERFACES;
 
 static int
 qemuDomainGetGuestInfoCheckSupport(unsigned int types,
@@ -20102,6 +20103,69 @@ qemuAgentFSInfoFormatParams(qemuAgentFSInfo **fsinfo,
     }
 }
 
+static void
+virDomainInterfaceFormatParams(virDomainInterfacePtr *ifaces,
+int nifaces,
+virTypedParameterPtr *params,
+int *nparams, int * maxparams)
+{
+    size_t i, j;
+    const char *type = NULL;
+
+    if (virTypedParamsAddUInt(params, nparams, maxparams,
+                             "if.count", nifaces) < 0)
+      return;
+
+    for (i = 0; i < nifaces; i++) {
+        char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
+        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.name", i);
+        if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, ifaces[i]->name) < 0)
+            return;
+
+        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.hwaddr", i);
+        if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, ifaces[i]->hwaddr) < 0)
+            return;
+
+        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.count", i);
+        if (virTypedParamsAddUInt(params, nparams, maxparams,
+                                    param_name, ifaces[i]->naddrs) < 0)
+            return;
+
+        for (j = 0; j < ifaces[i]->naddrs; j++) {
+            switch (ifaces[i]->addrs[j].type) {
+                case VIR_IP_ADDR_TYPE_IPV4:
+                    type = "ipv4";
+                    break;
+                case VIR_IP_ADDR_TYPE_IPV6:
+                    type = "ipv6";
+                    break;
+           }
+
+           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.%zu.type", i, j);
+           if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, type) < 0)
+            return;
+
+           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.%zu.addr", i, j);
+           if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, ifaces[i]->addrs[j].addr) < 0)
+            return;
+
+           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.%zu.prefix", i, j);
+           if (virTypedParamsAddUInt(params, nparams, maxparams,
+                                    param_name, ifaces[i]->addrs[j].prefix) < 0)
+            return;
+        }
+    }
+}
 
 static int
 qemuDomainGetGuestInfo(virDomainPtr dom,
@@ -20123,6 +20187,8 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
     qemuAgentFSInfo **agentfsinfo = NULL;
     size_t ndisks = 0;
     qemuAgentDiskInfo **agentdiskinfo = NULL;
+    virDomainInterfacePtr *ifaces = NULL;
+    size_t nifaces = 0;
     size_t i;
 
     virCheckFlags(0, -1);
@@ -20188,6 +20254,15 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
         }
     }
 
+    if (supportedTypes & VIR_DOMAIN_GUEST_INFO_INTERFACES) {
+        rc = qemuAgentGetInterfaces(agent, &ifaces, report_unsupported);
+        if (rc == -1) {
+            goto exitagent;
+        } else if (rc >= 0) {
+            nifaces = rc;
+        }
+    }
+
     qemuDomainObjExitAgent(vm, agent);
     qemuDomainObjEndAgentJob(vm);
 
@@ -20210,6 +20285,10 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
         qemuDomainObjEndJob(driver, vm);
     }
 
+    if (nifaces > 0) {
+        virDomainInterfaceFormatParams(ifaces, nifaces, params, nparams, &maxparams);
+    }
+
     ret = 0;
 
  cleanup:
@@ -20219,6 +20298,11 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
     for (i = 0; i < ndisks; i++)
         qemuAgentDiskInfoFree(agentdiskinfo[i]);
     g_free(agentdiskinfo);
+    if (ifaces && nifaces > 0) {
+        for (i = 0; i < nifaces; i++)
+            virDomainInterfaceFree(ifaces[i]);
+    }
+    g_free(ifaces);
 
     virDomainObjEndAPI(&vm);
     return ret;
diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c
index a447c93494..e0b22c042a 100644
--- a/tests/qemuagenttest.c
+++ b/tests/qemuagenttest.c
@@ -920,7 +920,7 @@ testQemuAgentGetInterfaces(const void *data)
         goto cleanup;
 
     if ((ifaces_count = qemuAgentGetInterfaces(qemuMonitorTestGetAgent(test),
-                                               &ifaces)) < 0)
+                                               &ifaces, true)) < 0)
         goto cleanup;
 
     if (ifaces_count != 4) {
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index e5bd1fdd75..ea3ba58616 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -13854,6 +13854,8 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
         types |= VIR_DOMAIN_GUEST_INFO_FILESYSTEM;
     if (vshCommandOptBool(cmd, "disk"))
         types |= VIR_DOMAIN_GUEST_INFO_DISKS;
+    if (vshCommandOptBool(cmd, "interface"))
+        types |= VIR_DOMAIN_GUEST_INFO_INTERFACES;
 
     if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
         return false;
-- 
2.31.1

[PATCH] qemu_driver:report guest interface informations
Posted by scuzhanglei 2 years, 7 months ago
Signed-off-by: scuzhanglei <greatzhanglei@gmail.com>
---
 NEWS.rst                         |  5 ++
 docs/manpages/virsh.rst          | 12 ++++-
 include/libvirt/libvirt-domain.h |  1 +
 src/libvirt-domain.c             | 12 +++++
 src/qemu/qemu_agent.c            |  9 ++--
 src/qemu/qemu_agent.h            |  3 +-
 src/qemu/qemu_driver.c           | 88 +++++++++++++++++++++++++++++++-
 tests/qemuagenttest.c            |  2 +-
 tools/virsh-domain.c             |  6 +++
 9 files changed, 129 insertions(+), 9 deletions(-)

diff --git a/NEWS.rst b/NEWS.rst
index 1af934e068..8666b318d8 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -45,6 +45,11 @@ v7.7.0 (unreleased)
     The genid attribute is now reported for VMX guests. Libvirt can now
     properly process super wide SCSI bus (64 units).
 
+  * qemu: Report guest interfaces information in ``virDomainGetGuestInfo``
+
+    Libvirt is now able to report interfaces from the guest's
+    perspective (using guest agent).
+
 * **Bug fixes**
 
   * qemu: Open chardev logfile on behalf of QEMU
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 2204bed3bb..9f878d400c 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -2700,7 +2700,7 @@ guestinfo
 ::
 
    guestinfo domain [--user] [--os] [--timezone] [--hostname] [--filesystem]
-      [--disk]
+      [--disk] [--interface]
 
 Print information about the guest from the point of view of the guest agent.
 Note that this command requires a guest agent to be configured and running in
@@ -2711,7 +2711,7 @@ are supported by the guest agent. You can limit the types of information that
 are returned by specifying one or more flags.  If a requested information
 type is not supported, the processes will provide an exit code of 1.
 Available information types flags are *--user*, *--os*,
-*--timezone*, *--hostname*, *--filesystem* and *--disk*.
+*--timezone*, *--hostname*, *--filesystem*, *--disk* and *--interface*.
 
 Note that depending on the hypervisor type and the version of the guest agent
 running within the domain, not all of the following information may be
@@ -2779,6 +2779,14 @@ returned:
 * ``disk.<num>.alias`` - the device alias of the disk (e.g. sda)
 * ``disk.<num>.guest_alias`` - optional alias assigned to the disk
 
+*--interface* returns:
+* ``if.count`` - the number of interfaces defined on this domain
+* ``if.<num>.name`` - name in the guest (e.g. ``eth0``) for interface <num>
+* ``if.<num>.hwaddr`` - hardware address in the guest for interface <num>
+* ``if.<num>.addr.count`` - the number of IP addresses of interface <num>
+* ``if.<num>.addr.<num>.type`` - the type of IP address <num> (e.g. ipv4)
+* ``if.<num>.addr.<num>.addr`` - the address of IP address <num>
+* ``if.<num>.addr.<num>.prefix`` - the prefix of IP address <num>
 
 guestvcpus
 ----------
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 7ef8ac51e5..b088847725 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5074,6 +5074,7 @@ typedef enum {
     VIR_DOMAIN_GUEST_INFO_HOSTNAME = (1 << 3), /* return hostname information */
     VIR_DOMAIN_GUEST_INFO_FILESYSTEM = (1 << 4), /* return filesystem information */
     VIR_DOMAIN_GUEST_INFO_DISKS = (1 << 5), /* return disks information */
+    VIR_DOMAIN_GUEST_INFO_INTERFACES = (1 << 6), /* return interfaces information */
 } virDomainGuestInfoTypes;
 
 int virDomainGetGuestInfo(virDomainPtr domain,
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index a8a386e839..dfd84b4744 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12586,6 +12586,18 @@ virDomainSetVcpu(virDomainPtr domain,
  * virTypedParamsFree to free memory returned in @params.
  *
  * Returns 0 on success, -1 on error.
+ * VIR_DOMAIN_GUEST_INFO_INTERFACES:
+ *  Returns information about the interfaces within the domain. the typed
+ *  parameter keys are in this format:
+ *
+ *      "if.count" - the number of interfaces defined on this domain
+ *                    as an unsigned int
+ *      "if.<num>.name" - interface name in the guest
+ *      "if.<num>.hwaddr" -  hardware address of interface
+ *      "if.<num>.addr.count - the number of ip addresses of interface
+ *      "if.<num>.addr.<num>.type" - the type of ip address(e.g. ipv4)
+ *      "if.<num>.addr.<num>.addr" - the ip address
+ *      "if.<num>.addr.<num>.prefix" - the number of bits of ip address prefix
  */
 int virDomainGetGuestInfo(virDomainPtr domain,
                           unsigned int types,
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index 5f421be6f6..a7f943e0dc 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -2245,17 +2245,20 @@ qemuAgentGetAllInterfaceAddresses(virDomainInterfacePtr **ifaces_ret,
  */
 int
 qemuAgentGetInterfaces(qemuAgent *agent,
-                       virDomainInterfacePtr **ifaces)
+                       virDomainInterfacePtr **ifaces,
+                       bool report_unsupported)
 {
     g_autoptr(virJSONValue) cmd = NULL;
     g_autoptr(virJSONValue) reply = NULL;
     virJSONValue *ret_array = NULL;
+    int rc;
 
     if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL)))
         return -1;
 
-    if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
-        return -1;
+    if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
+                                   report_unsupported)) < 0)
+        return rc;
 
     if (!(ret_array = virJSONValueObjectGetArray(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h
index 81b45b8e5d..94eab9de9f 100644
--- a/src/qemu/qemu_agent.h
+++ b/src/qemu/qemu_agent.h
@@ -151,7 +151,8 @@ int qemuAgentSetTime(qemuAgent *mon,
                      bool sync);
 
 int qemuAgentGetInterfaces(qemuAgent *mon,
-                           virDomainInterfacePtr **ifaces);
+                           virDomainInterfacePtr **ifaces,
+                           bool report_unsupported);
 
 int qemuAgentSetUserPassword(qemuAgent *mon,
                              const char *user,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f1f961c51c..0b803c392b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -18957,7 +18957,7 @@ qemuDomainInterfaceAddresses(virDomainPtr dom,
             goto endjob;
 
         agent = qemuDomainObjEnterAgent(vm);
-        ret = qemuAgentGetInterfaces(agent, ifaces);
+        ret = qemuAgentGetInterfaces(agent, ifaces, true);
         qemuDomainObjExitAgent(vm, agent);
 
     endjob:
@@ -19903,7 +19903,8 @@ static const unsigned int qemuDomainGetGuestInfoSupportedTypes =
     VIR_DOMAIN_GUEST_INFO_TIMEZONE |
     VIR_DOMAIN_GUEST_INFO_HOSTNAME |
     VIR_DOMAIN_GUEST_INFO_FILESYSTEM |
-    VIR_DOMAIN_GUEST_INFO_DISKS;
+    VIR_DOMAIN_GUEST_INFO_DISKS |
+    VIR_DOMAIN_GUEST_INFO_INTERFACES;
 
 static int
 qemuDomainGetGuestInfoCheckSupport(unsigned int types,
@@ -20102,6 +20103,69 @@ qemuAgentFSInfoFormatParams(qemuAgentFSInfo **fsinfo,
     }
 }
 
+static void
+virDomainInterfaceFormatParams(virDomainInterfacePtr *ifaces,
+int nifaces,
+virTypedParameterPtr *params,
+int *nparams, int * maxparams)
+{
+    size_t i, j;
+    const char *type = NULL;
+
+    if (virTypedParamsAddUInt(params, nparams, maxparams,
+                             "if.count", nifaces) < 0)
+      return;
+
+    for (i = 0; i < nifaces; i++) {
+        char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
+        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.name", i);
+        if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, ifaces[i]->name) < 0)
+            return;
+
+        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.hwaddr", i);
+        if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, ifaces[i]->hwaddr) < 0)
+            return;
+
+        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.count", i);
+        if (virTypedParamsAddUInt(params, nparams, maxparams,
+                                    param_name, ifaces[i]->naddrs) < 0)
+            return;
+
+        for (j = 0; j < ifaces[i]->naddrs; j++) {
+            switch (ifaces[i]->addrs[j].type) {
+                case VIR_IP_ADDR_TYPE_IPV4:
+                    type = "ipv4";
+                    break;
+                case VIR_IP_ADDR_TYPE_IPV6:
+                    type = "ipv6";
+                    break;
+           }
+
+           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.%zu.type", i, j);
+           if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, type) < 0)
+            return;
+
+           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.%zu.addr", i, j);
+           if (virTypedParamsAddString(params, nparams, maxparams,
+                                    param_name, ifaces[i]->addrs[j].addr) < 0)
+            return;
+
+           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
+                   "if.%zu.addr.%zu.prefix", i, j);
+           if (virTypedParamsAddUInt(params, nparams, maxparams,
+                                    param_name, ifaces[i]->addrs[j].prefix) < 0)
+            return;
+        }
+    }
+}
 
 static int
 qemuDomainGetGuestInfo(virDomainPtr dom,
@@ -20123,6 +20187,8 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
     qemuAgentFSInfo **agentfsinfo = NULL;
     size_t ndisks = 0;
     qemuAgentDiskInfo **agentdiskinfo = NULL;
+    virDomainInterfacePtr *ifaces = NULL;
+    size_t nifaces = 0;
     size_t i;
 
     virCheckFlags(0, -1);
@@ -20188,6 +20254,15 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
         }
     }
 
+    if (supportedTypes & VIR_DOMAIN_GUEST_INFO_INTERFACES) {
+        rc = qemuAgentGetInterfaces(agent, &ifaces, report_unsupported);
+        if (rc == -1) {
+            goto exitagent;
+        } else if (rc >= 0) {
+            nifaces = rc;
+        }
+    }
+
     qemuDomainObjExitAgent(vm, agent);
     qemuDomainObjEndAgentJob(vm);
 
@@ -20210,6 +20285,10 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
         qemuDomainObjEndJob(driver, vm);
     }
 
+    if (nifaces > 0) {
+        virDomainInterfaceFormatParams(ifaces, nifaces, params, nparams, &maxparams);
+    }
+
     ret = 0;
 
  cleanup:
@@ -20219,6 +20298,11 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
     for (i = 0; i < ndisks; i++)
         qemuAgentDiskInfoFree(agentdiskinfo[i]);
     g_free(agentdiskinfo);
+    if (ifaces && nifaces > 0) {
+        for (i = 0; i < nifaces; i++)
+            virDomainInterfaceFree(ifaces[i]);
+    }
+    g_free(ifaces);
 
     virDomainObjEndAPI(&vm);
     return ret;
diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c
index a447c93494..e0b22c042a 100644
--- a/tests/qemuagenttest.c
+++ b/tests/qemuagenttest.c
@@ -920,7 +920,7 @@ testQemuAgentGetInterfaces(const void *data)
         goto cleanup;
 
     if ((ifaces_count = qemuAgentGetInterfaces(qemuMonitorTestGetAgent(test),
-                                               &ifaces)) < 0)
+                                               &ifaces, true)) < 0)
         goto cleanup;
 
     if (ifaces_count != 4) {
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index e5bd1fdd75..5ba5bd6b8c 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -13829,6 +13829,10 @@ static const vshCmdOptDef opts_guestinfo[] = {
      .type = VSH_OT_BOOL,
      .help = N_("report disk information"),
     },
+    {.name = "interface",
+     .type = VSH_OT_BOOL,
+     .help = N_("report interface information"),
+    },
     {.name = NULL}
 };
 
@@ -13854,6 +13858,8 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
         types |= VIR_DOMAIN_GUEST_INFO_FILESYSTEM;
     if (vshCommandOptBool(cmd, "disk"))
         types |= VIR_DOMAIN_GUEST_INFO_DISKS;
+    if (vshCommandOptBool(cmd, "interface"))
+        types |= VIR_DOMAIN_GUEST_INFO_INTERFACES;
 
     if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
         return false;
-- 
2.31.1

Re: [PATCH] qemu_driver:report guest interface informations
Posted by Michal Prívozník 2 years, 6 months ago
On 8/30/21 7:35 AM, scuzhanglei wrote:
> Signed-off-by: scuzhanglei <greatzhanglei@gmail.com>
> ---
>  NEWS.rst                         |  5 ++
>  docs/manpages/virsh.rst          | 12 ++++-
>  include/libvirt/libvirt-domain.h |  1 +
>  src/libvirt-domain.c             | 12 +++++
>  src/qemu/qemu_agent.c            |  9 ++--
>  src/qemu/qemu_agent.h            |  3 +-
>  src/qemu/qemu_driver.c           | 88 +++++++++++++++++++++++++++++++-
>  tests/qemuagenttest.c            |  2 +-
>  tools/virsh-domain.c             |  6 +++
>  9 files changed, 129 insertions(+), 9 deletions(-)

The patch is more-or-less correct, however, we like to split things a
bit. In the first patch you can define the public flag and in this
specific case I'd say also do virsh change (virsh-domain.c + virsh.rst).
Or you can split that into two. Then, in the next patch you'd do the
hypervisor driver change (src/qemu/* + tests/qemuagenttest.c). And as
the very last patch you document the feature in NEWS.rst. This should
always be separate.

The reason for this split is to make it easier to backport patches
(should somebody do that).

Do you think you can do that in v2?

BTW: I'm no native speaker but I don't think "information" has a plural
form, thus s/informations/information/.

> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index f1f961c51c..0b803c392b 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -18957,7 +18957,7 @@ qemuDomainInterfaceAddresses(virDomainPtr dom,
>              goto endjob;
>  
>          agent = qemuDomainObjEnterAgent(vm);
> -        ret = qemuAgentGetInterfaces(agent, ifaces);
> +        ret = qemuAgentGetInterfaces(agent, ifaces, true);
>          qemuDomainObjExitAgent(vm, agent);
>  
>      endjob:
> @@ -19903,7 +19903,8 @@ static const unsigned int qemuDomainGetGuestInfoSupportedTypes =
>      VIR_DOMAIN_GUEST_INFO_TIMEZONE |
>      VIR_DOMAIN_GUEST_INFO_HOSTNAME |
>      VIR_DOMAIN_GUEST_INFO_FILESYSTEM |
> -    VIR_DOMAIN_GUEST_INFO_DISKS;
> +    VIR_DOMAIN_GUEST_INFO_DISKS |
> +    VIR_DOMAIN_GUEST_INFO_INTERFACES;
>  
>  static int
>  qemuDomainGetGuestInfoCheckSupport(unsigned int types,
> @@ -20102,6 +20103,69 @@ qemuAgentFSInfoFormatParams(qemuAgentFSInfo **fsinfo,
>      }
>  }
>  
> +static void
> +virDomainInterfaceFormatParams(virDomainInterfacePtr *ifaces,
> +int nifaces,
> +virTypedParameterPtr *params,
> +int *nparams, int * maxparams)

Indentation looks off.

> +{
> +    size_t i, j;
> +    const char *type = NULL;
> +
> +    if (virTypedParamsAddUInt(params, nparams, maxparams,
> +                             "if.count", nifaces) < 0)
> +      return;
> +
> +    for (i = 0; i < nifaces; i++) {
> +        char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
> +        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
> +                   "if.%zu.name", i);

We like to separate variable declaration block and code block with an
empty line.

> +        if (virTypedParamsAddString(params, nparams, maxparams,
> +                                    param_name, ifaces[i]->name) < 0)
> +            return;
> +
> +        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
> +                   "if.%zu.hwaddr", i);
> +        if (virTypedParamsAddString(params, nparams, maxparams,
> +                                    param_name, ifaces[i]->hwaddr) < 0)
> +            return;
> +
> +        g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
> +                   "if.%zu.addr.count", i);
> +        if (virTypedParamsAddUInt(params, nparams, maxparams,
> +                                    param_name, ifaces[i]->naddrs) < 0)
> +            return;
> +
> +        for (j = 0; j < ifaces[i]->naddrs; j++) {
> +            switch (ifaces[i]->addrs[j].type) {
> +                case VIR_IP_ADDR_TYPE_IPV4:
> +                    type = "ipv4";
> +                    break;
> +                case VIR_IP_ADDR_TYPE_IPV6:
> +                    type = "ipv6";
> +                    break;
> +           }
> +
> +           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
> +                   "if.%zu.addr.%zu.type", i, j);
> +           if (virTypedParamsAddString(params, nparams, maxparams,
> +                                    param_name, type) < 0)
> +            return;
> +
> +           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
> +                   "if.%zu.addr.%zu.addr", i, j);
> +           if (virTypedParamsAddString(params, nparams, maxparams,
> +                                    param_name, ifaces[i]->addrs[j].addr) < 0)
> +            return;
> +
> +           g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
> +                   "if.%zu.addr.%zu.prefix", i, j);
> +           if (virTypedParamsAddUInt(params, nparams, maxparams,
> +                                    param_name, ifaces[i]->addrs[j].prefix) < 0)
> +            return;
> +        }
> +    }
> +}
>  

Michal