qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v5] qemu-ga: Add guest-network-info command


From: Michal Privoznik
Subject: [Qemu-devel] [PATCH v5] qemu-ga: Add guest-network-info command
Date: Tue, 28 Feb 2012 16:36:54 +0100

This command returns an array of:

 [ifname, hwaddr, [ipaddr, ipaddr_family, prefix] ]

for each interface in the system.
Currently, only IPv4 and IPv6 are supported.

Signed-off-by: Michal Privoznik <address@hidden>
---
diff to v4:
-change return type

diff to v3:
-use ctpop32() instead of separate count_one_bits()

diff to v2:
-Properly set IP addr family for IPv6

diff to v1:
-move from guest-getip to guest-network-info
-replace black boxed algorithm for population count
-several coding styles improvements

 qapi-schema-guest.json |   62 +++++++++++++++
 qga/commands-posix.c   |  197 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 259 insertions(+), 0 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 706925d..41ea2bf 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -295,3 +295,65 @@
 ##
 { 'command': 'guest-fsfreeze-thaw',
   'returns': 'int' }
+
+##
+# @GuestIpAddressType:
+#
+# An enumeration of supported IP address types
+#
+# @ipv4: IP version 4
+#
+# @ipv6: IP version 6
+#
+# Since: 1.1
+##
+{ 'enum': 'GuestIpAddressType',
+  'data': [ 'ipv4', 'ipv6' ] }
+
+##
+# @GuestIpAddress:
+#
+# @ip-address: IP address
+#
+# @ip-address-type: Type of @ip-address (e.g. ipv4, ipv6)
+#
+# @prefix: Network prefix length of @ip-address
+#
+# Since: 1.1
+##
+{ 'type': 'GuestIpAddress',
+  'data': {'ip-address': 'str',
+           'ip-address-type': 'GuestIpAddressType',
+           'prefix': 'int'} }
+
+##
+# @GuestNetworkInterface:
+#
+# @name: The name of interface for which info are being delivered
+#
+# @hardware-address: Hardware address of @name
+#
+# @ip-addresses: List of addresses assigned to @name
+#
+# Since: 1.1
+##
+{ 'type': 'GuestNetworkInterface',
+  'data': {'name': 'str',
+           '*hardware-address': 'str',
+           '*ip-addresses': ['GuestIpAddress'] } }
+
+##
+# @guest-network-info:
+#
+# Get list of guest IP addresses, MAC addresses
+# and netmasks.
+#
+# Returns: List of GuestNetworkInfo on success.
+#
+# Since: 1.1
+##
+{ 'type': 'GuestNetworkInfo',
+  'data': { 'interfaces': ['GuestNetworkInterface'] } }
+
+{ 'command': 'guest-network-info',
+  'returns': 'GuestNetworkInfo' }
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 126127a..095507b 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -5,6 +5,7 @@
  *
  * Authors:
  *  Michael Roth      <address@hidden>
+ *  Michal Privoznik  <address@hidden>
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
@@ -23,10 +24,15 @@
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <ifaddrs.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <net/if.h>
 #include "qga/guest-agent-core.h"
 #include "qga-qmp-commands.h"
 #include "qerror.h"
 #include "qemu-queue.h"
+#include "host-utils.h"
 
 static GAState *ga_state;
 
@@ -526,3 +532,194 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
 #endif
     ga_command_state_add(cs, guest_file_init, NULL);
 }
+
+static GuestNetworkInterfaceList *
+guest_find_interface(GuestNetworkInterfaceList *head,
+                     const char *name)
+{
+    for (; head; head = head->next) {
+        if (strcmp(head->value->name, name) == 0) {
+            break;
+        }
+    }
+
+    return head;
+}
+
+/*
+ * Build information about guest interfaces
+ */
+static GuestNetworkInterfaceList *guest_build_interfaces_info(Error **errp)
+{
+    GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
+    struct ifaddrs *ifap, *ifa;
+    char err_msg[512];
+
+    if (getifaddrs(&ifap) < 0) {
+        snprintf(err_msg, sizeof(err_msg),
+                 "getifaddrs failed: %s", strerror(errno));
+        error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+        goto error;
+    }
+
+    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+        GuestNetworkInterfaceList *info;
+        GuestIpAddressList **address_list = NULL, *address_item = NULL;
+        char addr4[INET_ADDRSTRLEN];
+        char addr6[INET6_ADDRSTRLEN];
+        int sock;
+        struct ifreq ifr;
+        unsigned char *mac_addr;
+        void *p;
+
+        g_debug("Processing %s interface", ifa->ifa_name);
+
+        info = guest_find_interface(head, ifa->ifa_name);
+
+        if (!info) {
+            info = g_malloc0(sizeof(*info));
+            info->value = g_malloc0(sizeof(*info->value));
+            info->value->name = g_strdup(ifa->ifa_name);
+
+            if (!cur_item) {
+                head = cur_item = info;
+            } else {
+                cur_item->next = info;
+                cur_item = info;
+            }
+        }
+
+        if (!info->value->has_hardware_address &&
+            ifa->ifa_flags & SIOCGIFHWADDR) {
+            /* we haven't obtained HW address yet */
+            sock = socket(PF_INET, SOCK_STREAM, 0);
+            if (sock == -1) {
+                snprintf(err_msg, sizeof(err_msg),
+                         "failed to create socket: %s", strerror(errno));
+                error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+                goto error;
+            }
+
+            memset(&ifr, 0, sizeof(ifr));
+            strncpy(ifr.ifr_name,  info->value->name, IF_NAMESIZE);
+            if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
+                snprintf(err_msg, sizeof(err_msg),
+                         "failed to get MAC addres of %s: %s",
+                         ifa->ifa_name,
+                         strerror(errno));
+                error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+                goto error;
+            }
+
+            mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+
+            if (asprintf(&info->value->hardware_address,
+                         "%02x:%02x:%02x:%02x:%02x:%02x",
+                         (int) mac_addr[0], (int) mac_addr[1],
+                         (int) mac_addr[2], (int) mac_addr[3],
+                         (int) mac_addr[4], (int) mac_addr[5]) == -1) {
+                snprintf(err_msg, sizeof(err_msg),
+                         "failed to format MAC: %s", strerror(errno));
+                error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+                goto error;
+            }
+
+            info->value->has_hardware_address = true;
+            close(sock);
+        }
+
+        if (ifa->ifa_addr &&
+            ifa->ifa_addr->sa_family == AF_INET) {
+            /* interface with IPv4 address */
+            address_item = g_malloc0(sizeof(*address_item));
+            address_item->value = g_malloc0(sizeof(*address_item->value));
+            p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+            if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
+                snprintf(err_msg, sizeof(err_msg),
+                         "inet_ntop failed : %s", strerror(errno));
+                error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+                goto error;
+            }
+
+            address_item->value->ip_address = g_strdup(addr4);
+            address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
+
+            if (ifa->ifa_netmask) {
+                /* Count the number of set bits in netmask.
+                 * This is safe as '1' and '0' cannot be shuffled in netmask. 
*/
+                p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
+                address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
+            }
+        } else if (ifa->ifa_addr &&
+                   ifa->ifa_addr->sa_family == AF_INET6) {
+            /* interface with IPv6 address */
+            address_item = g_malloc0(sizeof(*address_item));
+            address_item->value = g_malloc0(sizeof(*address_item->value));
+            p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+            if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
+                snprintf(err_msg, sizeof(err_msg),
+                         "inet_ntop failed : %s", strerror(errno));
+                error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+                goto error;
+            }
+
+            address_item->value->ip_address = g_strdup(addr6);
+            address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
+
+            if (ifa->ifa_netmask) {
+                /* Count the number of set bits in netmask.
+                 * This is safe as '1' and '0' cannot be shuffled in netmask. 
*/
+                p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
+                address_item->value->prefix =
+                    ctpop32(((uint32_t *) p)[0]) +
+                    ctpop32(((uint32_t *) p)[1]) +
+                    ctpop32(((uint32_t *) p)[2]) +
+                    ctpop32(((uint32_t *) p)[3]);
+            }
+        }
+
+        if (!address_item) {
+            continue;
+        }
+
+        address_list = &info->value->ip_addresses;
+
+        while (*address_list && (*address_list)->next) {
+            address_list = &(*address_list)->next;
+        }
+
+        if (!*address_list) {
+            *address_list = address_item;
+        } else {
+            (*address_list)->next = address_item;
+        }
+
+        info->value->has_ip_addresses = true;
+
+
+    }
+
+    freeifaddrs(ifap);
+    return head;
+
+error:
+    freeifaddrs(ifap);
+    qapi_free_GuestNetworkInterfaceList(head);
+    return NULL;
+}
+
+/*
+ * Get guest network information
+ */
+GuestNetworkInfo *qmp_guest_network_info(Error **errp)
+{
+    GuestNetworkInfo *network_info = NULL;
+    GuestNetworkInterfaceList *interfaces = guest_build_interfaces_info(errp);
+
+    if (interfaces) {
+        network_info = g_malloc0(sizeof(*network_info));
+        network_info->interfaces = interfaces;
+    }
+
+    return network_info;
+}
-- 
1.7.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]