[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v5] qemu-ga: Add guest-network-info command
From: |
Ryan Harper |
Subject: |
Re: [Qemu-devel] [PATCH v5] qemu-ga: Add guest-network-info command |
Date: |
Tue, 28 Feb 2012 11:44:13 -0600 |
User-agent: |
Mutt/1.5.6+20040907i |
* Michal Privoznik <address@hidden> [2012-02-28 09:38]:
> 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.
What about vlans and bonding info?
>
> 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
>
--
Ryan Harper
Software Engineer; Linux Technology Center
IBM Corp., Austin, Tx
address@hidden