All of lore.kernel.org
 help / color / mirror / Atom feed
From: Olga Krishtal <okrishtal@parallels.com>
To: Chen Fan <chen.fan.fnst@cn.fujitsu.com>, libvir-list@redhat.com
Cc: izumi.taku@jp.fujitsu.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [RFC 1/3] qemu-agent: add guest-network-set-interface command
Date: Thu, 21 May 2015 16:52:38 +0300	[thread overview]
Message-ID: <555DE326.9010903@parallels.com> (raw)
In-Reply-To: <97201fc4eb0dacc2480382ff75e3170fdc24ce7a.1429257498.git.chen.fan.fnst@cn.fujitsu.com>

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 <chen.fan.fnst@cn.fujitsu.com>
> ---
>   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 <netcf.h>
> +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 <sys/socket.h>
>   #include <net/if.h>
>   
> +#ifdef CONFIG_NETCF
> +#include <netcf.h>
> +#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, "<interface type='%s' name='%s'>\n",
> +            interface_type_string[interface->type], interface->name);
> +    adjust_indent(&target_xml, 2);
> +    sprintf(target_xml + strlen(target_xml), "<start mode='%s'/>\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), "<protocol family='%s'>\n",
> +                ip_address_type_string[address_item->ip_address_type]);
> +        adjust_indent(&target_xml, 4);
> +        sprintf(target_xml + strlen(target_xml), "<ip address='%s' prefix='%" PRId64 "'/>\n",
> +                address_item->ip_address, address_item->prefix);
> +        if (address_item->has_gateway) {
> +            adjust_indent(&target_xml, 4);
> +            sprintf(target_xml + strlen(target_xml), "<route gateway='%s'/>\n",
> +                    address_item->gateway);
> +        }
> +        adjust_indent(&target_xml, 2);
> +        sprintf(target_xml + strlen(target_xml), "%s\n", "</protocol>");
> +    }
> +
> +    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), "<bond mode='%s'>\n",
> +                    value);
> +            g_free(value);
> +        } else {
> +            sprintf(target_xml + strlen(target_xml), "%s\n", "<bond>");
> +        }
> +
> +        value = parse_options(interface->options, "miimon=");
> +        if (value) {
> +            adjust_indent(&target_xml, 4);
> +            sprintf(target_xml + strlen(target_xml), "<miimon freq='%s'",
> +                   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), "<arpmon interval='%s'",
> +                    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", "<bond>");
> +    }
> +
> +    if (interface->has_subInterfaces) {
> +        GuestNetworkInterfaceList *head = interface->subInterfaces;
> +
> +        for (; head; head = head->next) {
> +            adjust_indent(&target_xml, 4);
> +            sprintf(target_xml + strlen(target_xml),
> +                    "<interface type='ethernet' name='%s'/>\n",
> +                    head->value->name);
> +        }
> +    }
> +
> +    adjust_indent(&target_xml, 2);
> +    sprintf(target_xml + strlen(target_xml), "%s\n", "</bond>");
> +    sprintf(target_xml + strlen(target_xml), "%s\n", "</interface>");
> +
> +    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.

  reply	other threads:[~2015-05-21 13:53 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-17  8:53 [Qemu-devel] [RFC 0/7] Live Migration with Pass-through Devices proposal Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 1/7] qemu-agent: add agent init callback when detecting guest setup Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 2/7] qemu: add guest init event callback to do the initialize work for guest Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 3/7] hostdev: add a 'bond' type element in <hostdev> element Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 4/7] qemu-agent: add qemuAgentCreateBond interface Chen Fan
2015-05-19  9:13   ` Michael S. Tsirkin
2015-05-29  7:37   ` Michal Privoznik
2015-04-17  8:53 ` [Qemu-devel] [RFC 5/7] hostdev: add parse ip and route for bond configure Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 6/7] migrate: hot remove hostdev at perform phase for bond device Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 7/7] migrate: add hostdev migrate status to support hostdev migration Chen Fan
2015-04-17  8:53 ` [Qemu-devel] [RFC 0/3] add support migration with passthrough device Chen Fan
2015-04-17  8:53   ` [Qemu-devel] [RFC 1/3] qemu-agent: add guest-network-set-interface command Chen Fan
2015-05-21 13:52     ` Olga Krishtal [this message]
2015-05-21 14:43       ` [Qemu-devel] [libvirt] " Eric Blake
2015-04-17  8:53   ` [Qemu-devel] [RFC 2/3] qemu-agent: add guest-network-delete-interface command Chen Fan
2015-04-17  8:53   ` [Qemu-devel] [RFC 3/3] qemu-agent: add notify for qemu-ga boot Chen Fan
2015-04-21 23:38     ` Eric Blake
2015-04-19 22:29 ` [Qemu-devel] [libvirt] [RFC 0/7] Live Migration with Pass-through Devices proposal Laine Stump
2015-04-22  4:22   ` Chen Fan
2015-04-23 14:14     ` Laine Stump
2015-04-23  8:34   ` Chen Fan
2015-04-23 15:01     ` Laine Stump
2015-05-19  9:10       ` Michael S. Tsirkin
2015-04-22  9:23 ` [Qemu-devel] " Daniel P. Berrange
2015-04-22 13:05   ` Daniel P. Berrange
2015-04-22 17:01   ` Dr. David Alan Gilbert
2015-04-22 17:06     ` Daniel P. Berrange
2015-04-22 17:12       ` Dr. David Alan Gilbert
2015-04-22 17:15         ` Daniel P. Berrange
2015-04-22 17:20           ` Dr. David Alan Gilbert
2015-04-23 16:35             ` [Qemu-devel] [libvirt] " Laine Stump
2015-05-19  9:04               ` Michael S. Tsirkin
2015-05-19  9:07   ` [Qemu-devel] " Michael S. Tsirkin
2015-05-19 14:15     ` [Qemu-devel] [libvirt] " Laine Stump
2015-05-19 14:21       ` Daniel P. Berrange
2015-05-19 15:03         ` Dr. David Alan Gilbert
2015-05-19 15:18           ` Michael S. Tsirkin
2015-05-19 15:35           ` Daniel P. Berrange
2015-05-19 15:39             ` Michael S. Tsirkin
2015-05-19 15:45               ` Daniel P. Berrange
2015-05-19 16:08                 ` Michael S. Tsirkin
2015-05-19 16:13                   ` Daniel P. Berrange
2015-05-19 16:27                   ` Dr. David Alan Gilbert
2015-05-19 15:21         ` Michael S. Tsirkin
2015-05-19 15:14       ` Michael S. Tsirkin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=555DE326.9010903@parallels.com \
    --to=okrishtal@parallels.com \
    --cc=chen.fan.fnst@cn.fujitsu.com \
    --cc=izumi.taku@jp.fujitsu.com \
    --cc=libvir-list@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.