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

2012-02-28 Thread Ryan Harper
* Michal Privoznik  [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 
> ---
> 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  
> + *  Michal Privoznik  
>   *
>   * 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 
>  #include 
> +#include 
> +#include 
> +#include 
> +#include 
>  #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;
> + 

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

2012-02-28 Thread Michal Privoznik
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 
---
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  
+ *  Michal Privoznik  
  *
  * 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 
 #include 
+#include 
+#include 
+#include 
+#include 
 #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_ms