You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1042 lines
35 KiB
1042 lines
35 KiB
From 3e6f148988ad7d0e61cdc821bd972dec7b9a5300 Mon Sep 17 00:00:00 2001 |
|
From: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> |
|
Date: Thu, 29 Aug 2013 17:18:52 +0200 |
|
Subject: [PATCH 10/60] libxkutil: Provide easy access to the libvirt |
|
capabilities |
|
|
|
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@linux.vnet.ibm.com> |
|
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> |
|
Signed-off-by: John Ferlan <jferlan@redhat.com> |
|
--- |
|
libxkutil/Makefile.am | 2 + |
|
libxkutil/capability_parsing.c | 551 +++++++++++++++++++++++++++++++++++++++++ |
|
libxkutil/capability_parsing.h | 97 ++++++++ |
|
libxkutil/device_parsing.c | 29 --- |
|
libxkutil/device_parsing.h | 2 - |
|
libxkutil/xml_parse_test.c | 201 ++++++++++++++- |
|
6 files changed, 848 insertions(+), 34 deletions(-) |
|
create mode 100644 libxkutil/capability_parsing.c |
|
create mode 100644 libxkutil/capability_parsing.h |
|
|
|
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..2acd45b |
|
--- /dev/null |
|
+++ b/libxkutil/capability_parsing.c |
|
@@ -0,0 +1,551 @@ |
|
+/* |
|
+ * Copyright IBM Corp. 2013 |
|
+ * |
|
+ * Authors: |
|
+ * Boris Fiuczynski <fiuczy@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, see |
|
+ * <http://www.gnu.org/licenses/>. |
|
+ */ |
|
+#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; |
|
+ |
|
+ for (i = 0; i < caps->num_guests; i++) { |
|
+ 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 && os_type != NULL) { |
|
+ /* 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 */ |
|
+ ret = _findDefArch(caps, os_type, NULL); |
|
+ } |
|
+ 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 ? |
|
+ 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; |
|
+ return false; |
|
+} |
|
+ |
|
+bool host_supports_kvm(struct capabilities *caps) |
|
+{ |
|
+ bool kvm = false; |
|
+ if (caps != NULL) { |
|
+ 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..41a4933 |
|
--- /dev/null |
|
+++ b/libxkutil/capability_parsing.h |
|
@@ -0,0 +1,97 @@ |
|
+/* |
|
+ * Copyright IBM Corp. 2013 |
|
+ * |
|
+ * Authors: |
|
+ * Boris Fiuczynski <fiuczy@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, see |
|
+ * <http://www.gnu.org/licenses/>. |
|
+ */ |
|
+#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 7af3953..fa9f998 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 df5080c..14e49b8 100644 |
|
--- a/libxkutil/device_parsing.h |
|
+++ b/libxkutil/device_parsing.h |
|
@@ -226,8 +226,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..af5e508 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) |
|
+ return; |
|
+ |
|
+ if (capgdiinfo->emulator != NULL) |
|
+ print_value(d, " Emulator", capgdiinfo->emulator); |
|
+ if (capgdiinfo->loader != NULL) |
|
+ 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; |
|
} |
|
|
|
-- |
|
2.1.0
|
|
|