1# -*- coding: utf-8 -*- 2 3""" 4Libxl Migration v2 streams 5 6Record structures as per docs/specs/libxl-migration-stream.pandoc, and 7verification routines. 8""" 9 10import sys 11 12from struct import calcsize, unpack, unpack_from 13from xen.migration.verify import StreamError, RecordError, VerifyBase 14from xen.migration.libxc import VerifyLibxc 15 16# Header 17HDR_FORMAT = "!QII" 18 19HDR_IDENT = 0x4c6962786c466d74 # "LibxlFmt" in ASCII 20HDR_VERSION = 2 21 22HDR_OPT_BIT_ENDIAN = 0 23HDR_OPT_BIT_LEGACY = 1 24 25HDR_OPT_LE = (0 << HDR_OPT_BIT_ENDIAN) 26HDR_OPT_BE = (1 << HDR_OPT_BIT_ENDIAN) 27HDR_OPT_LEGACY = (1 << HDR_OPT_BIT_LEGACY) 28 29HDR_OPT_RESZ_MASK = 0xfffc 30 31# Records 32RH_FORMAT = "II" 33 34REC_TYPE_end = 0x00000000 35REC_TYPE_libxc_context = 0x00000001 36REC_TYPE_emulator_xenstore_data = 0x00000002 37REC_TYPE_emulator_context = 0x00000003 38REC_TYPE_checkpoint_end = 0x00000004 39REC_TYPE_checkpoint_state = 0x00000005 40 41rec_type_to_str = { 42 REC_TYPE_end : "End", 43 REC_TYPE_libxc_context : "Libxc context", 44 REC_TYPE_emulator_xenstore_data : "Emulator xenstore data", 45 REC_TYPE_emulator_context : "Emulator context", 46 REC_TYPE_checkpoint_end : "Checkpoint end", 47 REC_TYPE_checkpoint_state : "Checkpoint state", 48} 49 50# emulator_* header 51EMULATOR_HEADER_FORMAT = "II" 52 53EMULATOR_ID_unknown = 0x00000000 54EMULATOR_ID_qemu_trad = 0x00000001 55EMULATOR_ID_qemu_upstream = 0x00000002 56 57emulator_id_to_str = { 58 EMULATOR_ID_unknown : "Unknown", 59 EMULATOR_ID_qemu_trad : "Qemu Traditional", 60 EMULATOR_ID_qemu_upstream : "Qemu Upstream", 61} 62 63 64# 65# libxl format 66# 67 68LIBXL_QEMU_SIGNATURE = "DeviceModelRecord0002" 69LIBXL_QEMU_RECORD_HDR = "=%dsI" % (len(LIBXL_QEMU_SIGNATURE), ) 70 71class VerifyLibxl(VerifyBase): 72 """ Verify a Libxl v2 stream """ 73 74 def __init__(self, info, read): 75 VerifyBase.__init__(self, info, read) 76 77 78 def verify(self): 79 """ Verity a libxl stream """ 80 81 self.verify_hdr() 82 83 while self.verify_record() != REC_TYPE_end: 84 pass 85 86 87 def verify_hdr(self): 88 """ Verify a Header """ 89 ident, version, options = self.unpack_exact(HDR_FORMAT) 90 91 if ident != HDR_IDENT: 92 raise StreamError("Bad image id: Expected 0x%x, got 0x%x" % 93 (HDR_IDENT, ident)) 94 95 if version != HDR_VERSION: 96 raise StreamError("Unknown image version: Expected %d, got %d" % 97 (HDR_VERSION, version)) 98 99 if options & HDR_OPT_RESZ_MASK: 100 raise StreamError("Reserved bits set in image options field: 0x%x" % 101 (options & HDR_OPT_RESZ_MASK)) 102 103 if ( (sys.byteorder == "little") and 104 ((options & HDR_OPT_BIT_ENDIAN) != HDR_OPT_LE) ): 105 raise StreamError( 106 "Stream is not native endianess - unable to validate") 107 108 endian = ["little", "big"][options & HDR_OPT_LE] 109 110 if options & HDR_OPT_LEGACY: 111 self.info("Libxl Header: %s endian, legacy converted" % (endian, )) 112 else: 113 self.info("Libxl Header: %s endian" % (endian, )) 114 115 116 def verify_record(self): 117 """ Verify an individual record """ 118 rtype, length = self.unpack_exact(RH_FORMAT) 119 120 if rtype not in rec_type_to_str: 121 raise StreamError("Unrecognised record type %x" % (rtype, )) 122 123 self.info("Libxl Record: %s, length %d" % 124 (rec_type_to_str[rtype], length)) 125 126 contentsz = (length + 7) & ~7 127 content = self.rdexact(contentsz) 128 129 padding = content[length:] 130 if padding != b"\x00" * len(padding): 131 raise StreamError("Padding containing non0 bytes found") 132 133 if rtype not in record_verifiers: 134 raise RuntimeError( 135 "No verification function for libxl record '%s'" % 136 rec_type_to_str[rtype]) 137 else: 138 record_verifiers[rtype](self, content[:length]) 139 140 return rtype 141 142 143 def verify_record_end(self, content): 144 """ End record """ 145 146 if len(content) != 0: 147 raise RecordError("End record with non-zero length") 148 149 150 def verify_record_libxc_context(self, content): 151 """ Libxc context record """ 152 153 if len(content) != 0: 154 raise RecordError("Libxc context record with non-zero length") 155 156 # Verify the libxc stream, as we can't seek forwards through it 157 VerifyLibxc(self.info, self.read).verify() 158 159 160 def verify_record_emulator_xenstore_data(self, content): 161 """ Emulator Xenstore Data record """ 162 minsz = calcsize(EMULATOR_HEADER_FORMAT) 163 164 if len(content) < minsz: 165 raise RecordError("Length must be at least %d bytes, got %d" % 166 (minsz, len(content))) 167 168 emu_id, emu_idx = unpack(EMULATOR_HEADER_FORMAT, content[:minsz]) 169 170 if emu_id not in emulator_id_to_str: 171 raise RecordError("Unrecognised emulator id 0x%x" % (emu_id, )) 172 173 self.info("Emulator Xenstore Data (%s, idx %d)" % 174 (emulator_id_to_str[emu_id], emu_idx)) 175 176 # Chop off the emulator header 177 content = content[minsz:] 178 179 if len(content): 180 181 if content[-1] != '\x00': 182 raise RecordError("Data not NUL terminated") 183 184 # Split without the final NUL, to get an even number of parts 185 parts = content[:-1].split("\x00") 186 187 if (len(parts) % 2) != 0: 188 raise RecordError("Expected an even number of strings, got %d" % 189 (len(parts), )) 190 191 for key, val in zip(parts[0::2], parts[1::2]): 192 self.info(" '%s' = '%s'" % (key, val)) 193 194 195 def verify_record_emulator_context(self, content): 196 """ Emulator Context record """ 197 minsz = calcsize(EMULATOR_HEADER_FORMAT) 198 199 if len(content) < minsz: 200 raise RecordError("Length must be at least %d bytes, got %d" % 201 (minsz, len(content))) 202 203 emu_id, emu_idx = unpack(EMULATOR_HEADER_FORMAT, content[:minsz]) 204 205 if emu_id not in emulator_id_to_str: 206 raise RecordError("Unrecognised emulator id 0x%x" % (emu_id, )) 207 208 self.info(" Index %d, type %s" % (emu_idx, emulator_id_to_str[emu_id])) 209 210 211 def verify_record_checkpoint_end(self, content): 212 """ Checkpoint end record """ 213 214 if len(content) != 0: 215 raise RecordError("Checkpoint end record with non-zero length") 216 217 def verify_record_checkpoint_state(self, content): 218 """ Checkpoint state """ 219 if len(content) == 0: 220 raise RecordError("Checkpoint state record with zero length") 221 222 223record_verifiers = { 224 REC_TYPE_end: 225 VerifyLibxl.verify_record_end, 226 REC_TYPE_libxc_context: 227 VerifyLibxl.verify_record_libxc_context, 228 REC_TYPE_emulator_xenstore_data: 229 VerifyLibxl.verify_record_emulator_xenstore_data, 230 REC_TYPE_emulator_context: 231 VerifyLibxl.verify_record_emulator_context, 232 REC_TYPE_checkpoint_end: 233 VerifyLibxl.verify_record_checkpoint_end, 234 REC_TYPE_checkpoint_state: 235 VerifyLibxl.verify_record_checkpoint_state, 236} 237