[Libvirt-cim] [PATCHv2 4/5] libxkutil: Provide easy access to the libvirt capabilities

John Ferlan jferlan at redhat.com
Thu Aug 29 20:28:33 UTC 2013


On 08/29/2013 11:18 AM, Viktor Mihajlovski wrote:
> From: Boris Fiuczynski <fiuczy at linux.vnet.ibm.com>
> 
> Introspecting the libvirt capabilities and creating an internal capabilities
> data structure. Methods are provided for retrieving default values regarding
> architecture, machine and emulator for easy of use in the provider code.
> 
> Changed the KVM detection to use the capabilities instead of unique
> XML parsing.
> 
> Further, xml_parse_test was extendend to display hypervisor capabilities
> and defaults.
> 
> Signed-off-by: Boris Fiuczynski <fiuczy at linux.vnet.ibm.com>
> Signed-off-by: Viktor Mihajlovski <mihajlov at linux.vnet.ibm.com>
> 
> ---
>  libxkutil/Makefile.am          |    2 +
>  libxkutil/capability_parsing.c |  556 ++++++++++++++++++++++++++++++++++++++++
>  libxkutil/capability_parsing.h |   97 +++++++
>  libxkutil/device_parsing.c     |   29 ---
>  libxkutil/device_parsing.h     |    2 -
>  libxkutil/xml_parse_test.c     |  201 ++++++++++++++-
>  6 files changed, 853 insertions(+), 34 deletions(-)
>  create mode 100644 libxkutil/capability_parsing.c
>  create mode 100644 libxkutil/capability_parsing.h
> 
> V2 Changes
>  + Removed memory leaks
>  + Removed occurrence of crashes when multiple guests are defined
>  + Corrected search pattern for default architecture and machine
>  + Added host CPU architecture parsing
>  + Extended xml_parse_test with better testing capabilities coverage
>  + Wrong free on cap guest struct
>  + Fixed use_kvm method
> 
> diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am
> index 8d436ad..dd7be55 100644
> --- a/libxkutil/Makefile.am
> +++ b/libxkutil/Makefile.am
> @@ -7,6 +7,7 @@ noinst_HEADERS = \
>  	cs_util.h \
>  	misc_util.h \
>  	device_parsing.h \
> +	capability_parsing.h \
>  	xmlgen.h \
>  	infostore.h \
>  	pool_parsing.h \
> @@ -20,6 +21,7 @@ libxkutil_la_SOURCES = \
>  	cs_util_instance.c \
>  	misc_util.c \
>  	device_parsing.c \
> +	capability_parsing.c \
>  	xmlgen.c \
>  	infostore.c \
>  	pool_parsing.c \
> diff --git a/libxkutil/capability_parsing.c b/libxkutil/capability_parsing.c
> new file mode 100644
> index 0000000..e3c0f2b
> --- /dev/null
> +++ b/libxkutil/capability_parsing.c
> @@ -0,0 +1,556 @@
> +/*
> + * Copyright IBM Corp. 2013
> + *
> + * Authors:
> + *  Boris Fiuczynski <fiuczy at linux.vnet.ibm.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

Forgot to mention this last time - I went through an exercise where I
removed the address here since the above is apparently their old
address....  See commit id '391634e2c'.  The difference is essentially:

- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.

Also see: http://www.gnu.org/licenses/gpl-howto.html


> + */
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <sys/stat.h>
> +#include <stdint.h>
> +
> +#include <libcmpiutil/libcmpiutil.h>
> +#include <libvirt/libvirt.h>
> +#include <libxml/xpath.h>
> +#include <libxml/parser.h>
> +#include <libxml/tree.h>
> +
> +#include "misc_util.h"
> +#include "capability_parsing.h"
> +#include "xmlgen.h"
> +#include "../src/svpc_types.h"
> +
> +static void cleanup_cap_machine(struct cap_machine *machine)
> +{
> +        if (machine == NULL)
> +                return;
> +        free(machine->name);
> +        free(machine->canonical_name);
> +}
> +
> +static void cleanup_cap_domain_info(struct cap_domain_info *cgdi)
> +{
> +        int i;
> +        if (cgdi == NULL)
> +                return;
> +        free(cgdi->emulator);
> +        free(cgdi->loader);
> +        for (i = 0; i < cgdi->num_machines; i++)
> +                cleanup_cap_machine(&cgdi->machines[i]);
> +        free(cgdi->machines);
> +}
> +
> +static void cleanup_cap_domain(struct cap_domain *cgd)
> +{
> +        if (cgd == NULL)
> +                return;
> +        free(cgd->typestr);
> +        cleanup_cap_domain_info(&cgd->guest_domain_info);
> +}
> +
> +static void cleanup_cap_arch(struct cap_arch *cga)
> +{
> +        int i;
> +        if (cga == NULL)
> +                return;
> +        free(cga->name);
> +        cleanup_cap_domain_info(&cga->default_domain_info);
> +        for (i = 0; i < cga->num_domains; i++)
> +                cleanup_cap_domain(&cga->domains[i]);
> +        free(cga->domains);
> +}
> +
> +static void cleanup_cap_guest(struct cap_guest *cg)
> +{
> +        if (cg == NULL)
> +                return;
> +        free(cg->ostype);
> +        cleanup_cap_arch(&cg->arch);
> +}
> +
> +static void cleanup_cap_host(struct cap_host *ch)
> +{
> +        if (ch == NULL)
> +                return;
> +        free(ch->cpu_arch);
> +}
> +
> +void cleanup_capabilities(struct capabilities **caps)
> +{
> +        int i;
> +        struct capabilities *cap;
> +
> +        if ((caps == NULL) || (*caps == NULL))
> +                return;
> +
> +        cap = *caps;
> +        cleanup_cap_host(&cap->host);
> +        for (i = 0; i < cap->num_guests; i++)
> +                cleanup_cap_guest(&cap->guests[i]);
> +
> +        free(cap->guests);
> +        free(cap);
> +        *caps = NULL;
> +}
> +
> +static void extend_cap_machines(struct cap_domain_info *cg_domaininfo,
> +                                char *name, char *canonical_name)
> +{
> +        struct cap_machine *tmp_list = NULL;
> +        tmp_list = realloc(cg_domaininfo->machines,
> +                           (cg_domaininfo->num_machines + 1) *
> +                           sizeof(struct cap_machine));
> +
> +        if (tmp_list == NULL) {
> +                /* Nothing you can do. Just go on. */
> +                CU_DEBUG("Could not alloc space for "
> +                         "guest domain info list");
> +                return;
> +        }
> +        cg_domaininfo->machines = tmp_list;
> +
> +        struct cap_machine *cap_gm =
> +                &cg_domaininfo->machines[cg_domaininfo->num_machines];
> +        cap_gm->name = name;
> +        cap_gm->canonical_name = canonical_name;
> +        cg_domaininfo->num_machines++;
> +}
> +
> +static void parse_cap_domain_info(struct cap_domain_info *cg_domaininfo,
> +                                  xmlNode *domain_child_node)
> +{
> +        CU_DEBUG("Capabilities guest domain info element node: %s",
> +                 domain_child_node->name);
> +
> +        if (XSTREQ(domain_child_node->name, "emulator")) {
> +                cg_domaininfo->emulator =
> +                        get_node_content(domain_child_node);
> +        } else if (XSTREQ(domain_child_node->name, "loader")) {
> +                cg_domaininfo->loader =
> +                        get_node_content(domain_child_node);
> +        } else if (XSTREQ(domain_child_node->name, "machine")) {
> +                extend_cap_machines(cg_domaininfo,
> +                                    get_node_content(domain_child_node),
> +                                    get_attr_value(domain_child_node,
> +                                                   "canonical"));
> +        }
> +}
> +
> +static void parse_cap_domain(struct cap_domain *cg_domain,
> +                             xmlNode *guest_dom)
> +{
> +        CU_DEBUG("Capabilities guest domain node: %s", guest_dom->name);
> +
> +        xmlNode *child;
> +
> +        cg_domain->typestr = get_attr_value(guest_dom, "type");
> +
> +        for (child = guest_dom->children; child != NULL; child = child->next)
> +                parse_cap_domain_info(&cg_domain->guest_domain_info, child);
> +}
> +
> +static void parse_cap_arch(struct cap_arch *cg_archinfo,
> +                           xmlNode *arch)
> +{
> +        CU_DEBUG("Capabilities arch node: %s", arch->name);
> +
> +        xmlNode *child;
> +
> +        cg_archinfo->name = get_attr_value(arch, "name");
> +
> +        for (child = arch->children; child != NULL; child = child->next) {
> +                if (XSTREQ(child->name, "wordsize")) {
> +                        char *wordsize_str;
> +                        unsigned int wordsize;
> +                        wordsize_str = get_node_content(child);
> +                        /* Default to 0 wordsize if garbage */
> +                        if (wordsize_str == NULL ||
> +                            sscanf(wordsize_str, "%i", &wordsize) != 1)
> +                                wordsize = 0;
> +                        free(wordsize_str);
> +                        cg_archinfo->wordsize = wordsize;
> +                } else if (XSTREQ(child->name, "domain")) {
> +                        struct cap_domain *tmp_list = NULL;
> +                        tmp_list = realloc(cg_archinfo->domains,
> +                                           (cg_archinfo->num_domains + 1) *
> +                                           sizeof(struct cap_domain));
> +                        if (tmp_list == NULL) {
> +                                /* Nothing you can do. Just go on. */
> +                                CU_DEBUG("Could not alloc space for "
> +                                         "guest domain");
> +                                continue;
> +                        }
> +                        memset(&tmp_list[cg_archinfo->num_domains],
> +                               0, sizeof(struct cap_domain));
> +                        cg_archinfo->domains = tmp_list;
> +                        parse_cap_domain(&cg_archinfo->
> +                                         domains[cg_archinfo->num_domains],
> +                                         child);
> +                        cg_archinfo->num_domains++;
> +                } else {
> +                        /* Check for the default domain child nodes */
> +                        parse_cap_domain_info(&cg_archinfo->default_domain_info,
> +                                              child);
> +                }
> +        }
> +}
> +
> +static void parse_cap_guests(xmlNodeSet *nsv, struct cap_guest *cap_guests)
> +{
> +        xmlNode **nodes = nsv->nodeTab;
> +        xmlNode *child;
> +        int numGuestNodes = nsv->nodeNr;
> +        int i;
> +
> +        for (i = 0; i < numGuestNodes; i++) {
> +                for (child = nodes[i]->children; child != NULL;
> +                     child = child->next) {
> +                        if (XSTREQ(child->name, "os_type")) {
> +                                STRPROP((&cap_guests[i]), ostype, child);
> +                        } else if (XSTREQ(child->name, "arch")) {
> +                                parse_cap_arch(&cap_guests[i].arch, child);
> +                        }
> +                }
> +        }
> +}
> +
> +static int parse_cap_host_cpu(struct cap_host *cap_host, xmlNode *cpu)
> +{
> +        xmlNode *child;
> +
> +        for (child = cpu->children; child != NULL; child = child->next) {
> +                if (XSTREQ(child->name, "arch")) {
> +                        cap_host->cpu_arch = get_node_content(child);
> +                        if (cap_host->cpu_arch != NULL)
> +                                return 1; /* success - host arch node found */
> +                        else {
> +                                CU_DEBUG("Host architecture is not defined");
> +                                break;
> +                        }
> +                }
> +        }
> +        return 0; /* error - no arch node or empty arch node */
> +}
> +
> +static int parse_cap_host(xmlNodeSet *nsv, struct cap_host *cap_host)
> +{
> +        xmlNode **nodes = nsv->nodeTab;
> +        xmlNode *child;
> +        if (nsv->nodeNr < 1)
> +                return 0; /* error no node below host */
> +
> +        for (child = nodes[0]->children; child != NULL; child = child->next) {
> +                if (XSTREQ(child->name, "cpu"))
> +                        return parse_cap_host_cpu(cap_host, child);
> +        }
> +        return 0;  /* error - no cpu node */
> +}
> +
> +static void compare_copy_domain_info_machines(
> +        struct cap_domain_info *def_gdomi,
> +        struct cap_domain_info *cap_gadomi)
> +{
> +        int i,j;
> +        int org_l = cap_gadomi->num_machines;
> +        char *cp_name = NULL;
> +        char *cp_canonical_name = NULL;
> +        bool found;
> +
> +        for (i = 0; i < def_gdomi->num_machines; i++) {
> +                found = false;
> +                for (j = 0; j < org_l; j++) {
> +                        if (STREQC(def_gdomi->machines[i].name,
> +                                   cap_gadomi->machines[j].name)) {
> +                                found = true;
> +                                continue;
> +                                /* found match => check next default */
> +                        }
> +                }
> +                if (!found) { /* no match => insert default */
> +                        cp_name = NULL;
> +                        cp_canonical_name = NULL;
> +                        if (def_gdomi->machines[i].name != NULL)
> +                                cp_name = strdup(def_gdomi->machines[i].name);
> +                        if (def_gdomi->machines[i].canonical_name != NULL)
> +                                cp_canonical_name =
> +                                        strdup(def_gdomi->
> +                                               machines[i].canonical_name);
> +
> +                        extend_cap_machines(cap_gadomi,
> +                                            cp_name,
> +                                            cp_canonical_name);
> +                }
> +        }
> +}
> +
> +static void extend_defaults_cap_guests(struct capabilities *caps)
> +{
> +        struct cap_arch *cap_garch;
> +        struct cap_domain_info *cap_gadomi;
> +        struct cap_domain_info *def_gdomi;
> +        int i,j;
> +
> +        if (caps == NULL)
> +                return;
> +
> +        for (i = 0; i < caps->num_guests; i++) {
> +                cap_garch = &caps->guests[i].arch;
> +                def_gdomi = &cap_garch->default_domain_info;
> +
> +                for (j = 0; j < cap_garch->num_domains; j++) {
> +                        /* compare guest_domain_info */
> +                        cap_gadomi = &cap_garch->domains[j].guest_domain_info;
> +                        if (cap_gadomi->emulator == NULL &&
> +                            def_gdomi->emulator != NULL)
> +                                cap_gadomi->emulator =
> +                                        strdup(def_gdomi->emulator);
> +                        if (cap_gadomi->loader == NULL &&
> +                            def_gdomi->loader != NULL)
> +                                cap_gadomi->loader = strdup(def_gdomi->loader);
> +
> +                        compare_copy_domain_info_machines(def_gdomi,
> +                                                          cap_gadomi);
> +                }
> +        }
> +}
> +
> +static int _get_capabilities(const char *xml, struct capabilities *caps)
> +{
> +        int len;
> +        int ret = 0;
> +
> +        xmlDoc *xmldoc = NULL;
> +        xmlXPathContext *xpathctx = NULL;
> +        xmlXPathObject *xpathobj = NULL;
> +        const xmlChar *xpathhoststr = (xmlChar *)"//capabilities//host";
> +        const xmlChar *xpathgueststr = (xmlChar *)"//capabilities//guest";
> +        xmlNodeSet *nsv;
> +
> +        len = strlen(xml) + 1;
> +
> +        if ((xmldoc = xmlParseMemory(xml, len)) == NULL)
> +                goto err;
> +
> +        if ((xpathctx = xmlXPathNewContext(xmldoc)) == NULL)
> +                goto err;
> +
> +        /* host node */
> +        if ((xpathobj = xmlXPathEvalExpression(xpathhoststr, xpathctx)) == NULL)
> +                goto err;
> +        if (xmlXPathNodeSetIsEmpty(xpathobj->nodesetval)) {
> +                CU_DEBUG("No capabilities host node found!");
> +                goto err;
> +        }
> +
> +        nsv = xpathobj->nodesetval;
> +        if (!parse_cap_host(nsv, &caps->host))
> +                goto err;
> +        xmlXPathFreeObject(xpathobj);
> +
> +        /* all guest nodes */
> +        if ((xpathobj = xmlXPathEvalExpression(xpathgueststr, xpathctx)) == NULL)
> +                goto err;
> +        if (xmlXPathNodeSetIsEmpty(xpathobj->nodesetval)) {
> +                CU_DEBUG("No capabilities guest nodes found!");
> +                goto err;
> +        }
> +
> +        nsv = xpathobj->nodesetval;
> +        caps->guests = calloc(nsv->nodeNr, sizeof(struct cap_guest));
> +        if (caps->guests == NULL)
> +                goto err;
> +        caps->num_guests = nsv->nodeNr;
> +
> +        parse_cap_guests(nsv, caps->guests);
> +        extend_defaults_cap_guests(caps);
> +        ret = 1;
> +
> + err:
> +        xmlXPathFreeObject(xpathobj);
> +        xmlXPathFreeContext(xpathctx);
> +        xmlFreeDoc(xmldoc);
> +        return ret;
> +}
> +
> +int get_caps_from_xml(const char *xml, struct capabilities **caps)
> +{
> +        CU_DEBUG("In get_caps_from_xml");
> +
> +        free(*caps);
> +        *caps = calloc(1, sizeof(struct capabilities));
> +        if (*caps == NULL)
> +                goto err;
> +
> +        if (_get_capabilities(xml, *caps) == 0)
> +                goto err;
> +
> +        return 1;
> +
> + err:
> +        free(*caps);
> +        *caps = NULL;
> +        return 0;
> +}
> +
> +int get_capabilities(virConnectPtr conn, struct capabilities **caps)
> +{
> +        char *caps_xml = NULL;
> +        int ret = 0;
> +
> +        if (conn == NULL) {
> +                CU_DEBUG("Unable to connect to libvirt.");
> +                return 0;
> +        }
> +
> +        caps_xml = virConnectGetCapabilities(conn);
> +
> +        if (caps_xml == NULL) {
> +                CU_DEBUG("Unable to get capabilities xml.");
> +                return 0;
> +        }
> +
> +        ret = get_caps_from_xml(caps_xml, caps);
> +
> +        free(caps_xml);
> +
> +        return ret;
> +}
> +
> +struct cap_domain_info *findDomainInfo(struct capabilities *caps,
> +                                       const char *os_type,
> +                                       const char *arch,
> +                                       const char *domain_type)
> +{
> +        int i,j;
> +        struct cap_arch *ar;
> +
> +        for (i = 0; i < caps->num_guests; i++) {
> +                if (os_type == NULL ||
> +                    STREQC(caps->guests[i].ostype, os_type)) {
> +                        ar = &caps->guests[i].arch;
> +                        if (arch == NULL || STREQC(ar->name,arch))
> +                                for (j = 0; j < ar->num_domains; j++)
> +                                        if (domain_type == NULL ||
> +                                            STREQC(ar->domains[j].typestr,
> +                                                   domain_type))
> +                                                return &ar->domains[j].
> +                                                        guest_domain_info;
> +                }
> +        }
> +        return NULL;
> +}
> +
> +static char *_findDefArch(struct capabilities *caps,
> +                          const char *os_type,
> +                          const char *host_arch)
> +{
> +        char *ret = NULL;
> +        int i;
> +
> +        if (os_type == NULL)
> +                return NULL;

Technically unnecessary...  See comment below

> +
> +        for (i = 0; i < caps->num_guests; i++)


I know there's just one statement inside, but consider using {} for
consistency and on the off chance someone misses this in the future.

> +                if (STREQC(caps->guests[i].ostype, os_type) &&
> +                    (host_arch == NULL || (host_arch != NULL &&
> +                    STREQC(caps->guests[i].arch.name, host_arch)))) {
> +                        ret = caps->guests[i].arch.name;
> +                        break;
> +                }
> +        return ret;
> +}
> +
> +char *get_default_arch(struct capabilities *caps,
> +                       const char *os_type)
> +{
> +        char *ret = NULL;
> +
> +        if (caps != NULL) {
> +                if (os_type != NULL) {

Checks could be combined - reducing indention a bit.

> +                        /* search first guest matching os_type and host arch */
> +                        ret = _findDefArch(caps, os_type, caps->host.cpu_arch);
> +                        if (ret== NULL) /* search first matching guest */

Need space                       ^

> +                                ret = _findDefArch(caps, os_type, NULL);

Since this is the only caller to _findDefArch and we know "caps != NULL
&& os_type != NULL", then the check in _findDefArch() becomes unnecessary

> +                }
> +        }
> +        return ret;
> +}
> +
> +char *get_default_machine(
> +        struct capabilities *caps,
> +        const char *os_type,
> +        const char *arch,
> +        const char *domain_type)
> +{
> +        char *ret = NULL;
> +        struct cap_domain_info *di;
> +
> +        if (caps != NULL) {
> +                di = findDomainInfo(caps, os_type, arch, domain_type);
> +                if (di != NULL && di->num_machines > 0) {
> +                        ret = di->machines[0].canonical_name;
> +                        if (ret == NULL) {
> +                                ret = di->machines[0].name;
> +                        }

Alternatively  ret = di->machines[0].canonical_name ?
                        di->machines[0].canonical_name :
                        di->machines[0].name;

> +                }
> +        }
> +        return ret;
> +}
> +
> +char *get_default_emulator(struct capabilities *caps,
> +                           const char *os_type,
> +                           const char *arch,
> +                           const char *domain_type)
> +{
> +        char *ret = NULL;
> +        struct cap_domain_info *di;
> +
> +        if (caps != NULL) {
> +                di = findDomainInfo(caps, os_type, arch, domain_type);
> +                if (di != NULL)
> +                        ret = di->emulator;
> +        }
> +        return ret;
> +}
> +
> +bool use_kvm(struct capabilities *caps) {
> +        if (host_supports_kvm(caps) && !get_disable_kvm())
> +                return true;
> +        else

else is unnecessary

> +                return false;
> +}
> +
> +bool host_supports_kvm(struct capabilities *caps)
> +{
> +        bool kvm = false;
> +        if (caps != NULL)

Again consider {} here so for consistency and prevention...

> +                if (findDomainInfo(caps, NULL, NULL, "kvm") != NULL)
> +                        kvm = true;
> +        return kvm;
> +}
> +/*
> + * Local Variables:
> + * mode: C
> + * c-set-style: "K&R"
> + * tab-width: 8
> + * c-basic-offset: 8
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/libxkutil/capability_parsing.h b/libxkutil/capability_parsing.h
> new file mode 100644
> index 0000000..d258f62
> --- /dev/null
> +++ b/libxkutil/capability_parsing.h
> @@ -0,0 +1,97 @@
> +/*
> + * Copyright IBM Corp. 2013
> + *
> + * Authors:
> + *  Boris Fiuczynski <fiuczy at linux.vnet.ibm.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

Adjust the info here too.

> + */
> +#ifndef __CAPABILITY_PARSING_H
> +#define __CAPABILITY_PARSING_H
> +
> +#include <stdint.h>
> +#include <stdbool.h>
> +
> +struct cap_host {
> +        char *cpu_arch;
> +};
> +
> +struct cap_machine {
> +        char *name;
> +        char *canonical_name;
> +};
> +
> +struct cap_domain_info {
> +        char *emulator;
> +        char *loader;
> +        int num_machines;
> +        struct cap_machine *machines;
> +};
> +
> +struct cap_domain {
> +        char *typestr;
> +        struct cap_domain_info guest_domain_info;
> +};
> +
> +struct cap_arch {
> +        char *name;
> +        unsigned int wordsize;
> +        struct cap_domain_info default_domain_info;
> +        int num_domains;
> +        struct cap_domain *domains;
> +};
> +
> +struct cap_guest {
> +        char *ostype;
> +        struct cap_arch arch;
> +};
> +
> +struct capabilities {
> +        struct cap_host host;
> +        int num_guests;
> +        struct cap_guest *guests;
> +};
> +
> +int get_caps_from_xml(const char *xml, struct capabilities **caps);
> +int get_capabilities(virConnectPtr conn, struct capabilities **caps);
> +char *get_default_arch(struct capabilities *caps,
> +                       const char *os_type);
> +char *get_default_machine(struct capabilities *caps,
> +                          const char *os_type,
> +                          const char *arch,
> +                          const char *domain_type);
> +char *get_default_emulator(struct capabilities *caps,
> +                           const char *os_type,
> +                           const char *arch,
> +                           const char *domain_type);
> +struct cap_domain_info *findDomainInfo(struct capabilities *caps,
> +                                       const char *os_type,
> +                                       const char *arch,
> +                                       const char *domain_type);
> +bool use_kvm(struct capabilities *caps);
> +bool host_supports_kvm(struct capabilities *caps);
> +void cleanup_capabilities(struct capabilities **caps);
> +
> +#endif
> +
> +/*
> + * Local Variables:
> + * mode: C
> + * c-set-style: "K&R"
> + * tab-width: 8
> + * c-basic-offset: 8
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c
> index df7a87a..449f51c 100644
> --- a/libxkutil/device_parsing.c
> +++ b/libxkutil/device_parsing.c
> @@ -397,35 +397,6 @@ err:
>          return 0;
>  }
>  
> -bool has_kvm_domain_type(xmlNodePtr node)
> -{
> -        xmlNodePtr child = NULL;
> -        char *type = NULL;
> -        bool ret = false;
> -
> -        child = node->children;
> -        while (child != NULL) {
> -                if (XSTREQ(child->name, "domain")) {
> -                        type = get_attr_value(child, "type");
> -                        if (XSTREQ(type, "kvm")) {
> -                                ret = true;
> -                                goto out;
> -                        }
> -                }
> -
> -                if (has_kvm_domain_type(child) == 1) {
> -                        ret = true;
> -                        goto out;
> -                }
> -
> -                child = child->next;
> -        }
> -
> -  out:
> -            free(type);
> -            return ret;
> -}
> -
>  static int parse_net_device(xmlNode *inode, struct virt_device **vdevs)
>  {
>          struct virt_device *vdev = NULL;
> diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h
> index 379d48c..a39e881 100644
> --- a/libxkutil/device_parsing.h
> +++ b/libxkutil/device_parsing.h
> @@ -223,8 +223,6 @@ int attach_device(virDomainPtr dom, struct virt_device *dev);
>  int detach_device(virDomainPtr dom, struct virt_device *dev);
>  int change_device(virDomainPtr dom, struct virt_device *dev);
>  
> -bool has_kvm_domain_type(xmlNodePtr node);
> -
>  #define XSTREQ(x, y) (STREQ((char *)x, y))
>  #define STRPROP(d, p, n) (d->p = get_node_content(n))
>  
> diff --git a/libxkutil/xml_parse_test.c b/libxkutil/xml_parse_test.c
> index 384593d..de2c88a 100644
> --- a/libxkutil/xml_parse_test.c
> +++ b/libxkutil/xml_parse_test.c
> @@ -6,6 +6,7 @@
>  #include <libvirt/libvirt.h>
>  
>  #include "device_parsing.h"
> +#include "capability_parsing.h"
>  #include "xmlgen.h"
>  
>  static void print_value(FILE *d, const char *name, const char *val)
> @@ -25,6 +26,36 @@ static void print_u32(FILE *d, const char *name, uint32_t val)
>  }
>  #endif
>  
> +static char *get_ostype(struct domain *dom)
> +{
> +        if (dom->type == DOMAIN_XENPV) {
> +                return dom->os_info.pv.type;
> +        } else if ((dom->type == DOMAIN_XENFV) ||
> +                   (dom->type == DOMAIN_KVM) ||
> +                   (dom->type == DOMAIN_QEMU)) {
> +                return dom->os_info.fv.type;
> +        } else if (dom->type == DOMAIN_LXC) {
> +                return dom->os_info.lxc.type;
> +        } else {
> +                return NULL;
> +        }
> +}
> +
> +static char *get_domaintype(struct domain *dom)
> +{
> +        if (dom->type == DOMAIN_XENPV || dom->type == DOMAIN_XENFV) {
> +                return "xen";
> +        } else if (dom->type == DOMAIN_KVM) {
> +                return "kvm";
> +        } else if (dom->type == DOMAIN_QEMU) {
> +                return "qemu";
> +        } else if (dom->type == DOMAIN_LXC) {
> +                return "lxc";
> +        } else {
> +                return NULL;
> +        }
> +}
> +
>  static void print_os(struct domain *dom,
>                       FILE *d)
>  {
> @@ -183,6 +214,98 @@ static char *read_from_file(FILE *file)
>          return xml;
>  }
>  
> +static void print_cap_domain_info(struct cap_domain_info *capgdiinfo,
> +                                  FILE *d)
> +{
> +        struct cap_machine capgminfo;
> +        int i;
> +
> +        if (capgdiinfo==NULL)

NIT: No spacing (e.g. " == ")

> +                return;
> +
> +        if (capgdiinfo->emulator!=NULL)

Ditto

> +                print_value(d, "  Emulator", capgdiinfo->emulator);
> +        if (capgdiinfo->loader!=NULL)

Ditto

The remainder seemed fine.

John

> +                print_value(d, "  Loader", capgdiinfo->loader);
> +        for (i = 0; i < capgdiinfo->num_machines; i++) {
> +                capgminfo = capgdiinfo->machines[i];
> +                fprintf(d, "  Machine name : %-15s  canonical name : %s\n",
> +                        capgminfo.name, capgminfo.canonical_name);
> +        }
> +        fprintf(d, "\n");
> +}
> +
> +static void print_cap_domains(struct cap_arch caparchinfo,
> +                              FILE *d)
> +{
> +        struct cap_domain capgdinfo;
> +        int i;
> +        for (i = 0; i < caparchinfo.num_domains; i++) {
> +                capgdinfo = caparchinfo.domains[i];
> +                print_value(d, "  Type", capgdinfo.typestr);
> +                print_cap_domain_info(&capgdinfo.guest_domain_info, d);
> +        }
> +}
> +
> +static void print_cap_arch(struct cap_arch caparchinfo,
> +                           FILE *d)
> +{
> +        print_value(d, " Arch name", caparchinfo.name);
> +        fprintf(d, " Arch wordsize : %i\n", caparchinfo.wordsize);
> +        fprintf(d, "\n  -- Default guest domain settings --\n");
> +        print_cap_domain_info(&caparchinfo.default_domain_info, d);
> +        fprintf(d, "  -- Guest domains (%i) --\n", caparchinfo.num_domains);
> +        print_cap_domains(caparchinfo, d);
> +}
> +
> +static void print_cap_guest(struct cap_guest *capginfo,
> +                            FILE *d)
> +{
> +        print_value(d, "Guest OS type", capginfo->ostype);
> +        print_cap_arch(capginfo->arch, d);
> +}
> +
> +static void print_cap_host(struct cap_host *caphinfo,
> +                           FILE *d)
> +{
> +        print_value(d, "Host CPU architecture", caphinfo->cpu_arch);
> +}
> +
> +static void print_capabilities(struct capabilities *capsinfo,
> +                               FILE *d)
> +{
> +        int i;
> +        fprintf(d, "\n### Capabilities ###\n");
> +        fprintf(d, "-- Host --\n");
> +        print_cap_host(&capsinfo->host, d);
> +        fprintf(d, "\n-- Guest (%i) --\n", capsinfo->num_guests);
> +        for (i = 0; i < capsinfo->num_guests; i++)
> +                print_cap_guest(&capsinfo->guests[i], d);
> +}
> +
> +static int capinfo_for_dom(const char *uri,
> +                           struct domain *dominfo,
> +                           struct capabilities **capsinfo)
> +{
> +        virConnectPtr conn = NULL;
> +        char *caps_xml = NULL;
> +        int ret = 0;
> +
> +        conn = virConnectOpen(uri);
> +        if (conn == NULL) {
> +                printf("Unable to connect to libvirt\n");
> +                goto out;
> +        }
> +
> +        ret = get_capabilities(conn, capsinfo);
> +
> + out:
> +        free(caps_xml);
> +        virConnectClose(conn);
> +
> +        return ret;
> +}
> +
>  static int dominfo_from_dom(const char *uri,
>                              const char *domain,
>                              struct domain **d)
> @@ -246,12 +369,13 @@ static int dominfo_from_file(const char *fname, struct domain **d)
>  static void usage(void)
>  {
>          printf("xml_parse_test -f [FILE | -] [--xml]\n"
> -               "xml_parse_test -d domain [--uri URI] [--xml]\n"
> +               "xml_parse_test -d domain [--uri URI] [--xml] [--cap]\n"
>                 "\n"
>                 "-f,--file FILE    Parse domain XML from file (or stdin if -)\n"
>                 "-d,--domain DOM   Display dominfo for a domain from libvirt\n"
>                 "-u,--uri URI      Connect to libvirt with URI\n"
>                 "-x,--xml          Dump generated XML instead of summary\n"
> +               "-c,--cap          Display the libvirt default capability values for the specified domain\n"
>                 "-h,--help         Display this help message\n");
>  }
>  
> @@ -262,7 +386,10 @@ int main(int argc, char **argv)
>          char *uri = "xen";
>          char *file = NULL;
>          bool xml = false;
> +        bool cap = false;
>          struct domain *dominfo = NULL;
> +        struct capabilities *capsinfo = NULL;
> +        struct cap_domain_info *capgdinfo = NULL;
>          int ret;
>  
>          static struct option lopts[] = {
> @@ -270,13 +397,14 @@ int main(int argc, char **argv)
>                  {"uri",    1, 0, 'u'},
>                  {"xml",    0, 0, 'x'},
>                  {"file",   1, 0, 'f'},
> +                {"cap",    0, 0, 'c'},
>                  {"help",   0, 0, 'h'},
>                  {0,        0, 0, 0}};
>  
>          while (1) {
>                  int optidx = 0;
>  
> -                c = getopt_long(argc, argv, "d:u:f:xh", lopts, &optidx);
> +                c = getopt_long(argc, argv, "d:u:f:xch", lopts, &optidx);
>                  if (c == -1)
>                          break;
>  
> @@ -297,11 +425,14 @@ int main(int argc, char **argv)
>                          xml = true;
>                          break;
>  
> +                case 'c':
> +                        cap = true;
> +                        break;
> +
>                  case '?':
>                  case 'h':
>                          usage();
>                          return c == '?';
> -
>                  };
>          }
>  
> @@ -326,6 +457,70 @@ int main(int argc, char **argv)
>                  print_devices(dominfo, stdout);
>          }
>  
> +        if (cap && file == NULL) {
> +                ret = capinfo_for_dom(uri, dominfo, &capsinfo);
> +                if (ret == 0) {
> +                        printf("Unable to get capsinfo\n");
> +                        return 3;
> +                } else {
> +                        print_capabilities(capsinfo, stdout);
> +                        const char *os_type = get_ostype(dominfo);
> +                        const char *dom_type = get_domaintype(dominfo);
> +                        const char *def_arch = get_default_arch(capsinfo, os_type);
> +
> +                        fprintf(stdout, "-- KVM is used: %s\n\n", (use_kvm(capsinfo)?"true":"false"));
> +                        fprintf(stdout, "-- For all following default OS type=%s\n", os_type);
> +                        fprintf(stdout, "-- Default Arch : %s\n", def_arch);
> +
> +                        fprintf(stdout,
> +                                "-- Default Machine for arch=NULL : %s\n",
> +                                get_default_machine(capsinfo, os_type, NULL, NULL));
> +                        fprintf(stdout,
> +                                "-- Default Machine for arch=%s and domain type=NULL : %s\n",
> +                                def_arch,
> +                                get_default_machine(capsinfo, os_type, def_arch, NULL));
> +                        fprintf(stdout,
> +                                "-- Default Machine for arch=%s and domain type=%s : %s\n",
> +                                def_arch, dom_type,
> +                                get_default_machine(capsinfo, os_type, def_arch, dom_type));
> +                        fprintf(stdout,
> +                                "-- Default Machine for arch=NULL and domain type=%s : %s\n",
> +                                dom_type,
> +                                get_default_machine(capsinfo, os_type, NULL, dom_type));
> +
> +                        fprintf(stdout,
> +                                "-- Default Emulator for arch=NULL : %s\n",
> +                                get_default_emulator(capsinfo, os_type, NULL, NULL));
> +                        fprintf(stdout,
> +                                "-- Default Emulator for arch=%s and domain type=NULL : %s\n",
> +                                def_arch,
> +                                get_default_emulator(capsinfo, os_type, def_arch, NULL));
> +                        fprintf(stdout,
> +                                "-- Default Emulator for arch=%s and domain type=%s : %s\n",
> +                                def_arch, dom_type,
> +                                get_default_emulator(capsinfo, os_type, def_arch, dom_type));
> +                        fprintf(stdout,
> +                                "-- Default Emulator for arch=NULL and domain type=%s : %s\n",
> +                                dom_type,
> +                                get_default_emulator(capsinfo, os_type, NULL, dom_type));
> +
> +                        fprintf(stdout, "\n-- Default Domain Search for: \n"
> +                                "guest type=hvm - guest arch=* - guest domain type=kvm\n");
> +                        capgdinfo = findDomainInfo(capsinfo, "hvm", NULL, "kvm");
> +                        print_cap_domain_info(capgdinfo, stdout);
> +
> +                        fprintf(stdout, "-- Default Domain Search for: \n"
> +                                "guest type=* - guest arch=* - guest domain type=*\n");
> +                        capgdinfo = findDomainInfo(capsinfo, NULL, NULL, NULL);
> +                        print_cap_domain_info(capgdinfo, stdout);
> +
> +                        cleanup_capabilities(&capsinfo);
> +                }
> +        } else if (cap) {
> +                printf("Need a data source (--domain) to get default capabilities\n");
> +                return 4;
> +        }
> +
>          return 0;
>  }
>  
> 




More information about the Libvirt-cim mailing list