* Michal Privoznik <mpriv...@redhat.com> [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 <mpriv...@redhat.com> > --- > 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 <mdr...@linux.vnet.ibm.com> > + * Michal Privoznik <mpriv...@redhat.com> > * > * 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 ry...@us.ibm.com