]> xenbits.xensource.com Git - xen.git/commitdiff
libxl: allow a generation ID to be specified at domain creation
authorDavid Vrabel <david.vrabel@citrix.com>
Fri, 27 Jun 2014 13:57:51 +0000 (14:57 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Fri, 27 Jun 2014 14:55:57 +0000 (15:55 +0100)
Toolstacks may specify a VM generation ID using the u.hvm.ms_vm_genid
field in the libxl_domain_build_info structure, when creating a
domain.

The toolstack is responsible for providing the correct generation ID
according to the Microsoft specification (e.g., generating new random
ones with libxl_ms_vm_genid_generate() as appropriate when restoring).

Although the specification requires that a ACPI Notify event is raised
if the generation ID is changed, the generation ID is never changed
when the domain is in a state to receive such an event (it's either
newly created or suspended).

Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Cc: David Scott <dave.scott@citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
tools/libxl/Makefile
tools/libxl/gentest.py
tools/libxl/libxl.h
tools/libxl/libxl_dom.c
tools/libxl/libxl_genid.c [new file with mode: 0644]
tools/libxl/libxl_internal.h
tools/libxl/libxl_json.c
tools/libxl/libxl_json.h
tools/libxl/libxl_types.idl
tools/ocaml/libs/xl/genwrap.py
tools/ocaml/libs/xl/xenlight_stubs.c

index 8dd8c957b0f503567309fd6ea417df97b7acd87f..78c199633271c60175245cf1b666a2c5d6ee616e 100644 (file)
@@ -81,6 +81,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
                        libxl_json.o libxl_aoutils.o libxl_numa.o \
                        libxl_save_callout.o _libxl_save_msgs_callout.o \
                        libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
+LIBXL_OBJS += libxl_genid.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
 LIBXL_TESTS += timedereg
index eb9a21b4ba11e5c031070bebeab2699f2407a6a8..0195bf4046895095e807eab7bb020a283cec2235 100644 (file)
@@ -60,7 +60,7 @@ def gen_rand_init(ty, v, indent = "    ", parent = None):
         s += "%s(%s);\n" % (ty.rand_init,
                             ty.pass_arg(v, isref=parent is None,
                                         passby=idl.PASS_BY_REFERENCE))
-    elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap"]:
+    elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap", "libxl_ms_vm_genid"]:
         s += "rand_bytes((uint8_t *)%s, sizeof(*%s));\n" % (v,v)
     elif ty.typename in ["libxl_domid", "libxl_devid"] or isinstance(ty, idl.Number):
         s += "%s = rand() %% (sizeof(%s)*8);\n" % \
index d63cd11dd913f05bbc034b8a5317fd376193cbca..459557d12119735a0c705931bc7f3948d2c3917e 100644 (file)
  */
 #define LIBXL_HAVE_BUILDINFO_EVENT_CHANNELS 1
 
+/*
+ * libxl_domain_build_info has the u.hvm.ms_vm_genid field.
+ */
+#define LIBXL_HAVE_BUILDINFO_HVM_MS_VM_GENID 1
+
 /*
  * LIBXL_HAVE_VCPUINFO_SOFT_AFFINITY indicates that a 'cpumap_soft'
  * field (of libxl_bitmap type) is present in libxl_vcpuinfo,
@@ -639,6 +644,11 @@ const char *libxl_defbool_to_string(libxl_defbool b);
 #define LIBXL_TIMER_MODE_DEFAULT -1
 #define LIBXL_MEMKB_DEFAULT ~0ULL
 
+#define LIBXL_MS_VM_GENID_LEN 16
+typedef struct {
+    uint8_t bytes[LIBXL_MS_VM_GENID_LEN];
+} libxl_ms_vm_genid;
+
 #include "_libxl_types.h"
 
 const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
@@ -1262,6 +1272,9 @@ int libxl_flask_getenforce(libxl_ctx *ctx);
 int libxl_flask_setenforce(libxl_ctx *ctx, int mode);
 int libxl_flask_loadpolicy(libxl_ctx *ctx, void *policy, uint32_t size);
 
+int libxl_ms_vm_genid_generate(libxl_ctx *ctx, libxl_ms_vm_genid *id);
+bool libxl_ms_vm_genid_is_zero(const libxl_ms_vm_genid *id);
+
 /* misc */
 
 /* Each of these sets or clears the flag according to whether the
index acb07947a42d6cda4ee2ea5701757dd79f896476..0448d1723f7b7fd9f8c871b85f37680b1f6bfecd 100644 (file)
@@ -339,6 +339,16 @@ int libxl__build_post(libxl__gc *gc, uint32_t domid,
     if (info->cpuid != NULL)
         libxl_cpuid_set(ctx, domid, info->cpuid);
 
+    if (info->type == LIBXL_DOMAIN_TYPE_HVM
+        && !libxl_ms_vm_genid_is_zero(&info->u.hvm.ms_vm_genid)) {
+        rc = libxl__ms_vm_genid_set(gc, domid,
+                                    &info->u.hvm.ms_vm_genid);
+        if (rc) {
+            LOG(ERROR, "Failed to set VM Generation ID");
+            return rc;
+        }
+    }
+
     ents = libxl__calloc(gc, 12 + (info->max_vcpus * 2) + 2, sizeof(char *));
     ents[0] = "memory/static-max";
     ents[1] = GCSPRINTF("%"PRId64, info->max_memkb);
diff --git a/tools/libxl/libxl_genid.c b/tools/libxl/libxl_genid.c
new file mode 100644 (file)
index 0000000..9853fa6
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 Citrix Systems R&D Ltd.
+ *
+ * This program 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; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program 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.
+ */
+
+#include "libxl_osdeps.h" /* must come before any other headers */
+
+#include "libxl_internal.h"
+
+#include <xenctrl.h>
+#include <xen/hvm/params.h>
+
+/*
+ * Generate a random VM generation ID.
+ *
+ * Returns ERROR_FAIL if a suitable source of random numbers is not
+ * available.
+ *
+ * See Microsoft's "Virtual Machine Generation ID" specification for
+ * further details, including when a new generation ID is required.
+ *
+ *   http://www.microsoft.com/en-us/download/details.aspx?id=30707
+ */
+int libxl_ms_vm_genid_generate(libxl_ctx *ctx, libxl_ms_vm_genid *id)
+{
+    GC_INIT(ctx);
+    int ret;
+
+    ret = libxl__random_bytes(gc, id->bytes, LIBXL_MS_VM_GENID_LEN);
+
+    GC_FREE;
+    return ret;
+}
+
+/*
+ * Is this VM generation ID all zeros?
+ */
+bool libxl_ms_vm_genid_is_zero(const libxl_ms_vm_genid *id)
+{
+    static const libxl_ms_vm_genid zero;
+
+    return memcmp(id->bytes, zero.bytes, LIBXL_MS_VM_GENID_LEN) == 0;
+}
+
+int libxl__ms_vm_genid_set(libxl__gc *gc, uint32_t domid,
+                           const libxl_ms_vm_genid *id)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    const char *dom_path;
+    uint64_t genid[2];
+    uint64_t paddr = 0;
+    int rc;
+
+    memcpy(genid, id->bytes, LIBXL_MS_VM_GENID_LEN);
+
+    /*
+     * Set the "platform/generation-id" XenStore key to pass the ID to
+     * hvmloader.
+     */
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = libxl__xs_write(gc, XBT_NULL,
+                         GCSPRINTF("%s/platform/generation-id", dom_path),
+                         "%"PRIu64 ":%" PRIu64, genid[0], genid[1]);
+    if (rc < 0)
+        goto out;
+
+    /*
+     * Update the ID in guest memory (if available).
+     */
+    xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_VM_GENERATION_ID_ADDR, &paddr);
+    if (paddr) {
+        void *vaddr;
+
+        vaddr = xc_map_foreign_range(ctx->xch, domid, XC_PAGE_SIZE,
+                                     PROT_READ | PROT_WRITE,
+                                     paddr >> XC_PAGE_SHIFT);
+        if (vaddr == NULL) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+        memcpy(vaddr + (paddr & ~XC_PAGE_MASK), genid, 2 * sizeof(*genid));
+        munmap(vaddr, XC_PAGE_SIZE);
+
+        /*
+         * The spec requires an ACPI Notify event is injected into the
+         * guest when the generation ID is changed.
+         *
+         * This is only called for domains that are suspended or newly
+         * created and they won't be in a state to receive such an
+         * event.
+         */
+    }
+
+    rc = 0;
+
+  out:
+    return rc;
+}
index d4f32a9a5149d4e35546c79864c1d3a77500d2bd..2eea5575fff25dab3152f7694adb0cc3046fd7cb 100644 (file)
@@ -3086,6 +3086,10 @@ void libxl__numa_candidate_put_nodemap(libxl__gc *gc,
     libxl_bitmap_copy(CTX, &cndt->nodemap, nodemap);
 }
 
+_hidden int libxl__ms_vm_genid_set(libxl__gc *gc, uint32_t domid,
+                                   const libxl_ms_vm_genid *id);
+
+
 /* Som handy macros for defbool type. */
 #define LIBXL__DEFBOOL_DEFAULT     (0)
 #define LIBXL__DEFBOOL_FALSE       (-1)
@@ -3163,6 +3167,8 @@ int libxl_key_value_list_parse_json(libxl__gc *gc,
                                     libxl_key_value_list *p);
 int libxl_hwcap_parse_json(libxl__gc *gc, const libxl__json_object *o,
                            libxl_hwcap *p);
+int libxl_ms_vm_genid_parse_json(libxl__gc *gc, const libxl__json_object *o,
+                                 libxl_ms_vm_genid *p);
 int libxl__int_parse_json(libxl__gc *gc, const libxl__json_object *o,
                           void *p);
 int libxl__uint8_parse_json(libxl__gc *gc, const libxl__json_object *o,
index fb9baf8fd3fda01ef635bed26605b3a5f702775b..63125dc8dc74e53bbda96f35d511de70bd118196 100644 (file)
@@ -377,6 +377,45 @@ int libxl_hwcap_parse_json(libxl__gc *gc, const libxl__json_object *o,
     return 0;
 }
 
+yajl_gen_status libxl_ms_vm_genid_gen_json(yajl_gen hand, libxl_ms_vm_genid *p)
+{
+    yajl_gen_status s;
+    int i;
+
+    s = yajl_gen_array_open(hand);
+    if (s != yajl_gen_status_ok)
+        return s;
+
+    for (i = 0; i < LIBXL_MS_VM_GENID_LEN; i++) {
+        s = yajl_gen_integer(hand, p->bytes[i]);
+        if (s != yajl_gen_status_ok)
+            return s;
+    }
+
+    return yajl_gen_array_close(hand);
+}
+
+int libxl_ms_vm_genid_parse_json(libxl__gc *gc, const libxl__json_object *o,
+                                 libxl_ms_vm_genid *p)
+{
+    unsigned int i;
+
+    if (!libxl__json_object_is_array(o))
+        return ERROR_FAIL;
+
+    for (i = 0; i < LIBXL_MS_VM_GENID_LEN; i++) {
+        const libxl__json_object *t;
+
+        t = libxl__json_array_get(o, i);
+        if (!t || !libxl__json_object_is_integer(t))
+            return ERROR_FAIL;
+
+        p->bytes[i] = libxl__json_object_get_integer(t);
+    }
+
+    return 0;
+}
+
 yajl_gen_status libxl__string_gen_json(yajl_gen hand,
                                        const char *p)
 {
index e4c0f6ce62080c49ecfcaf2888531e326cfd7b82..af26e7885de894483fd533979ef6f3f6bffe74ed 100644 (file)
@@ -33,6 +33,7 @@ yajl_gen_status libxl_string_list_gen_json(yajl_gen hand, libxl_string_list *p);
 yajl_gen_status libxl_key_value_list_gen_json(yajl_gen hand,
                                               libxl_key_value_list *p);
 yajl_gen_status libxl_hwcap_gen_json(yajl_gen hand, libxl_hwcap *p);
+yajl_gen_status libxl_ms_vm_genid_gen_json(yajl_gen hand, libxl_ms_vm_genid *p);
 
 #include <_libxl_types_json.h>
 
index 5607ea7142395c8313c14db986c2a105ff208424..de25f427ca3db0380fd9d6c06bc00579e6c723d3 100644 (file)
@@ -17,6 +17,7 @@ libxl_cpuid_policy_list = Builtin("cpuid_policy_list", dispose_fn="libxl_cpuid_d
 libxl_string_list = Builtin("string_list", dispose_fn="libxl_string_list_dispose", passby=PASS_BY_REFERENCE)
 libxl_key_value_list = Builtin("key_value_list", dispose_fn="libxl_key_value_list_dispose", passby=PASS_BY_REFERENCE)
 libxl_hwcap = Builtin("hwcap", passby=PASS_BY_REFERENCE)
+libxl_ms_vm_genid = Builtin("ms_vm_genid", passby=PASS_BY_REFERENCE)
 
 #
 # Specific integer types
@@ -378,6 +379,8 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                        ("xen_platform_pci", libxl_defbool),
                                        ("usbdevice_list",   libxl_string_list),
                                        ("vendor_device",    libxl_vendor_device),
+                                       # See libxl_ms_vm_genid_generate()
+                                       ("ms_vm_genid",      libxl_ms_vm_genid),
                                        ])),
                  ("pv", Struct(None, [("kernel", string),
                                       ("slack_memkb", MemKB),
index 5e4383144d7516b88fab2b76c12262d58762f03e..402e489f4f9025120f02e7a200af59fdc71aab8b 100644 (file)
@@ -18,6 +18,7 @@ builtins = {
     "libxl_string_list":    ("string list",            "libxl_string_list_val(&%(c)s, %(o)s)", "Val_string_list(&%(c)s)"),
     "libxl_mac":            ("int array",              "Mac_val(&%(c)s, %(o)s)",    "Val_mac(&%(c)s)"),
     "libxl_hwcap":          ("int32 array",            None,                                "Val_hwcap(&%(c)s)"),
+    "libxl_ms_vm_genid":    ("int array",              "Ms_vm_genid_val(&%(c)s, %(o)s)",    "Val_ms_vm_genid(&%(c)s)"),
     # The following needs to be sorted out later
     "libxl_cpuid_policy_list": ("unit",                "%(c)s = 0",                         "Val_unit"),
     }
index 8e825aec9ef9396e99a9fd2f1f63d38f1e05a23d..413352744050bf1979ec67dbf1e9c2e50c6648c8 100644 (file)
@@ -370,6 +370,31 @@ static value Val_hwcap(libxl_hwcap *c_val)
        CAMLreturn(hwcap);
 }
 
+static value Val_ms_vm_genid (libxl_ms_vm_genid *c_val)
+{
+       CAMLparam0();
+       CAMLlocal1(v);
+       int i;
+
+       v = caml_alloc_tuple(LIBXL_MS_VM_GENID_LEN);
+
+       for(i=0; i<LIBXL_MS_VM_GENID_LEN; i++)
+               Store_field(v, i, Val_int(c_val->bytes[i]));
+
+       CAMLreturn(v);
+}
+
+static int Ms_vm_genid_val(libxl_ms_vm_genid *c_val, value v)
+{
+       CAMLparam1(v);
+       int i;
+
+       for(i=0; i<LIBXL_MS_VM_GENID_LEN; i++)
+               c_val->bytes[i] = Int_val(Field(v, i));
+
+       CAMLreturn(0);
+}
+
 static value Val_string_option(const char *c_val)
 {
        CAMLparam0();