From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47879) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvQuB-0002Gh-Ef for qemu-devel@nongnu.org; Thu, 21 May 2015 09:53:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YvQu8-00055k-35 for qemu-devel@nongnu.org; Thu, 21 May 2015 09:52:59 -0400 Received: from relay.parallels.com ([195.214.232.42]:58367) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvQu7-00055e-ML for qemu-devel@nongnu.org; Thu, 21 May 2015 09:52:56 -0400 Message-ID: <555DE326.9010903@parallels.com> Date: Thu, 21 May 2015 16:52:38 +0300 From: Olga Krishtal MIME-Version: 1.0 References: <97201fc4eb0dacc2480382ff75e3170fdc24ce7a.1429257498.git.chen.fan.fnst@cn.fujitsu.com> In-Reply-To: <97201fc4eb0dacc2480382ff75e3170fdc24ce7a.1429257498.git.chen.fan.fnst@cn.fujitsu.com> Content-Type: text/plain; charset="windows-1252"; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [RFC 1/3] qemu-agent: add guest-network-set-interface command List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Chen Fan , libvir-list@redhat.com Cc: izumi.taku@jp.fujitsu.com, qemu-devel@nongnu.org On 17/04/15 11:53, Chen Fan wrote: > Nowadays, qemu has supported physical NIC hotplug for high network > throughput. but it's in conflict with live migration feature, to keep > network connectivity, we could to create bond device interface which > provides a mechanism for enslaving multiple network interfaces into a > single "bond" interface. the active-backup mode can be used for an > automatic switch. so this patch is adding a guest-network-set-interface > command for creating bond device. so the management can easy to create > a bond device dynamically when guest running. > > Signed-off-by: Chen Fan > --- > configure | 16 ++++ > qga/commands-posix.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++ > qga/commands-win32.c | 7 ++ > qga/qapi-schema.json | 54 +++++++++++ > 4 files changed, 338 insertions(+) > > diff --git a/configure b/configure > index f185dd0..ebfcc6a 100755 > --- a/configure > +++ b/configure > @@ -3618,6 +3618,18 @@ if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ > fi > > ########################################## > +# Do we need netcf > +netcf=no > +cat > $TMPC << EOF > +#include > +int main(void) { return 0; } > +EOF > +if compile_prog "" "-lnetcf" ; then > + netcf=yes > + libs_qga="$libs_qga -lnetcf" > +fi > + > +########################################## > # spice probe > if test "$spice" != "no" ; then > cat > $TMPC << EOF > @@ -4697,6 +4709,10 @@ if test "$spice" = "yes" ; then > echo "CONFIG_SPICE=y" >> $config_host_mak > fi > > +if test "$netcf" = "yes" ; then > + echo "CONFIG_NETCF=y" >> $config_host_mak > +fi > + > if test "$smartcard_nss" = "yes" ; then > echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak > echo "NSS_LIBS=$nss_libs" >> $config_host_mak > diff --git a/qga/commands-posix.c b/qga/commands-posix.c > index f6f3e3c..5ee7949 100644 > --- a/qga/commands-posix.c > +++ b/qga/commands-posix.c > @@ -46,6 +46,10 @@ extern char **environ; > #include > #include > > +#ifdef CONFIG_NETCF > +#include > +#endif > + > #ifdef FIFREEZE > #define CONFIG_FSFREEZE > #endif > @@ -1719,6 +1723,263 @@ error: > return NULL; > } > > +#ifdef CONFIG_NETCF > +static const char *interface_type_string[] = { > + "bond", > +}; > + > +static const char *ip_address_type_string[] = { > + "ipv4", > + "ipv6", > +}; > + > +static char *parse_options(const char *str, const char *needle) > +{ > + char *start, *end, *buffer = NULL; > + char *ret = NULL; > + > + buffer = g_strdup(str); > + start = buffer; > + if ((start = strstr(start, needle))) { > + start += strlen(needle); > + end = strchr(start, ' '); > + if (end) { > + *end = '\0'; > + } > + if (strlen(start) == 0) { > + goto cleanup; > + } > + ret = g_strdup(start); > + } > + > +cleanup: > + g_free(buffer); > + return ret; > +} > + > +/** > + * @buffer: xml string data to be formatted > + * @indent: indent number relative to first line > + * > + */ > +static void adjust_indent(char **buffer, int indent) > +{ > + char spaces[1024]; > + int i; > + > + if (!*buffer) { > + return; > + } > + > + if (indent < 0 || indent >= 1024) { > + return; > + } > + memset(spaces, 0, sizeof(spaces)); > + for (i = 0; i < indent; i++) { > + spaces[i] = ' '; > + } > + > + sprintf(*buffer + strlen(*buffer), "%s", spaces); > +} > + > +static char *create_bond_interface(GuestNetworkInterface2 *interface) > +{ > + char *target_xml; > + > + target_xml = g_malloc0(1024); > + if (!target_xml) { > + return NULL; > + } > + > + sprintf(target_xml, "\n", > + interface_type_string[interface->type], interface->name); > + adjust_indent(&target_xml, 2); > + sprintf(target_xml + strlen(target_xml), "\n", > + interface->has_onboot ? interface->onboot : "none"); > + if (interface->has_ip_address) { > + GuestIpAddress *address_item = interface->ip_address; > + > + adjust_indent(&target_xml, 2); > + sprintf(target_xml + strlen(target_xml), "\n", > + ip_address_type_string[address_item->ip_address_type]); > + adjust_indent(&target_xml, 4); > + sprintf(target_xml + strlen(target_xml), "\n", > + address_item->ip_address, address_item->prefix); > + if (address_item->has_gateway) { > + adjust_indent(&target_xml, 4); > + sprintf(target_xml + strlen(target_xml), "\n", > + address_item->gateway); > + } > + adjust_indent(&target_xml, 2); > + sprintf(target_xml + strlen(target_xml), "%s\n", ""); > + } > + > + adjust_indent(&target_xml, 2); > + if (interface->has_options) { > + char *value; > + > + value = parse_options(interface->options, "mode="); > + if (value) { > + sprintf(target_xml + strlen(target_xml), "\n", > + value); > + g_free(value); > + } else { > + sprintf(target_xml + strlen(target_xml), "%s\n", ""); > + } > + > + value = parse_options(interface->options, "miimon="); > + if (value) { > + adjust_indent(&target_xml, 4); > + sprintf(target_xml + strlen(target_xml), " + value); > + g_free(value); > + > + value = parse_options(interface->options, "updelay="); > + if (value) { > + sprintf(target_xml + strlen(target_xml), " updelay='%s'", > + value); > + g_free(value); > + } > + value = parse_options(interface->options, "downdelay="); > + if (value) { > + sprintf(target_xml + strlen(target_xml), " downdelay='%s'", > + value); > + g_free(value); > + } > + value = parse_options(interface->options, "use_carrier="); > + if (value) { > + sprintf(target_xml + strlen(target_xml), " carrier='%s'", > + value); > + g_free(value); > + } > + > + sprintf(target_xml + strlen(target_xml), "%s\n", "/>"); > + } > + > + value = parse_options(interface->options, "arp_interval="); > + if (value) { > + adjust_indent(&target_xml, 4); > + sprintf(target_xml + strlen(target_xml), " + value); > + g_free(value); > + > + value = parse_options(interface->options, "arp_ip_target="); > + if (value) { > + sprintf(target_xml + strlen(target_xml), " target='%s'", > + value); > + g_free(value); > + } > + > + value = parse_options(interface->options, "arp_validate="); > + if (value) { > + sprintf(target_xml + strlen(target_xml), " validate='%s'", > + value); > + g_free(value); > + } > + > + sprintf(target_xml + strlen(target_xml), "%s\n", "/>"); > + } > + } else { > + sprintf(target_xml + strlen(target_xml), "%s\n", ""); > + } > + > + if (interface->has_subInterfaces) { > + GuestNetworkInterfaceList *head = interface->subInterfaces; > + > + for (; head; head = head->next) { > + adjust_indent(&target_xml, 4); > + sprintf(target_xml + strlen(target_xml), > + "\n", > + head->value->name); > + } > + } > + > + adjust_indent(&target_xml, 2); > + sprintf(target_xml + strlen(target_xml), "%s\n", ""); > + sprintf(target_xml + strlen(target_xml), "%s\n", ""); > + > + return target_xml; > +} > + > +static struct netcf *netcf; > + > +static void create_interface(GuestNetworkInterface2 *interface, Error **errp) > +{ > + int ret = -1; > + struct netcf_if *iface; > + unsigned int flags = 0; > + char *target_xml; > + > + /* open netcf */ > + if (netcf == NULL) { > + if (ncf_init(&netcf, NULL) != 0) { > + error_setg(errp, "netcf init failed"); > + return; > + } > + } > + > + if (interface->type != GUEST_INTERFACE_TYPE_BOND) { > + error_setg(errp, "interface type is not supported, only support 'bond' type"); > + return; > + } > + > + target_xml = create_bond_interface(interface); > + if (!target_xml) { > + error_setg(errp, "no enough memory spaces"); > + return; > + } > + > + iface = ncf_define(netcf, target_xml); > + if (!iface) { > + error_setg(errp, "netcf interface define failed"); > + g_free(target_xml); > + goto cleanup; > + } > + > + g_free(target_xml); > + > + if (ncf_if_status(iface, &flags) < 0) { > + error_setg(errp, "netcf interface get status failed"); > + goto cleanup; > + } > + > + if (flags & NETCF_IFACE_ACTIVE) { > + error_setg(errp, "interface is already running"); > + goto cleanup; > + } > + > + ret = ncf_if_up(iface); > + if (ret < 0) { > + error_setg(errp, "netcf interface up failed"); > + goto cleanup; > + } > + > + cleanup: > + ncf_if_free(iface); > +} > + > +int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, > + Error **errp) > +{ > + Error *local_err = NULL; > + > + create_interface(interface, &local_err); > + if (local_err != NULL) { > + error_propagate(errp, local_err); > + return -1; > + } > + > + return 0; > +} > +#else > +int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, > + Error **errp) > +{ > + error_set(errp, QERR_UNSUPPORTED); > + return -1; > +} > +#endif > + > #define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp)) > > static long sysconf_exact(int name, const char *name_str, Error **errp) > diff --git a/qga/commands-win32.c b/qga/commands-win32.c > index 3bcbeae..4c14514 100644 > --- a/qga/commands-win32.c > +++ b/qga/commands-win32.c > @@ -446,6 +446,13 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) > return -1; > } > > +int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, > + Error **errp) > +{ > + error_set(errp, QERR_UNSUPPORTED); > + return -1; > +} > + > /* add unsupported commands to the blacklist */ > GList *ga_command_blacklist_init(GList *blacklist) > { > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json > index 376e79f..77f499b 100644 > --- a/qga/qapi-schema.json > +++ b/qga/qapi-schema.json > @@ -556,6 +556,7 @@ > { 'type': 'GuestIpAddress', > 'data': {'ip-address': 'str', > 'ip-address-type': 'GuestIpAddressType', > + '*gateway': 'str', > 'prefix': 'int'} } > > ## > @@ -575,6 +576,43 @@ > '*ip-addresses': ['GuestIpAddress'] } } > > ## > +# @GuestInterfaceType: > +# > +# An enumeration of supported interface types > +# > +# @bond: bond device > +# > +# Since: 2.3 > +## > +{ 'enum': 'GuestInterfaceType', > + 'data': [ 'bond' ] } > + > +## > +# @GuestNetworkInterface2: > +# > +# @type: the interface type which supported in enum GuestInterfaceType. > +# > +# @name: the interface name. > +# > +# @onboot: the interface start model. > +# > +# @ip-address: IP address. > +# > +# @options: the options argument. > +# > +# @subInterfaces: the slave interfaces. > +# > +# Since: 2.3 > +## > +{ 'type': 'GuestNetworkInterface2', > + 'data': {'type': 'GuestInterfaceType', > + 'name': 'str', > + '*onboot': 'str', > + '*ip-address': 'GuestIpAddress', > + '*options': 'str', > + '*subInterfaces': ['GuestNetworkInterface'] } } > + > +## > # @guest-network-get-interfaces: > # > # Get list of guest IP addresses, MAC addresses > @@ -588,6 +626,22 @@ > 'returns': ['GuestNetworkInterface'] } > > ## > +# @guest-network-set-interface: > +# > +# Set guest network interface > +# > +# return: 0: call successful. > +# > +# -1: call failed. > +# > +# > +# Since: 2.3 > +## > +{ 'command': 'guest-network-set-interface', > + 'data' : {'interface': 'GuestNetworkInterface2' }, > + 'returns': 'int' } I thought that usage of built-in types as the returning value is deprecated. Lets return dictionary in guest-network-set (get)-interface > + > +## > # @GuestLogicalProcessor: > # > # @logical-id: Arbitrary guest-specific unique identifier of the VCPU.