[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