1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4""" 5Libxl Migration v2 streams 6 7Record structures as per docs/specs/libxl-migration-stream.pandoc, and 8verification routines. 9""" 10 11import sys 12 13from struct import calcsize, unpack, unpack_from 14from xen.migration.verify import StreamError, RecordError, VerifyBase 15from xen.migration.libxc import VerifyLibxc 16 17# Header 18HDR_FORMAT = "!QII" 19 20HDR_IDENT = 0x4c6962786c466d74 # "LibxlFmt" in ASCII 21HDR_VERSION = 2 22 23HDR_OPT_BIT_ENDIAN = 0 24HDR_OPT_BIT_LEGACY = 1 25 26HDR_OPT_LE = (0 << HDR_OPT_BIT_ENDIAN) 27HDR_OPT_BE = (1 << HDR_OPT_BIT_ENDIAN) 28HDR_OPT_LEGACY = (1 << HDR_OPT_BIT_LEGACY) 29 30HDR_OPT_RESZ_MASK = 0xfffc 31 32# Records 33RH_FORMAT = "II" 34 35REC_TYPE_end = 0x00000000 36REC_TYPE_libxc_context = 0x00000001 37REC_TYPE_emulator_xenstore_data = 0x00000002 38REC_TYPE_emulator_context = 0x00000003 39REC_TYPE_checkpoint_end = 0x00000004 40REC_TYPE_checkpoint_state = 0x00000005 41 42rec_type_to_str = { 43 REC_TYPE_end : "End", 44 REC_TYPE_libxc_context : "Libxc context", 45 REC_TYPE_emulator_xenstore_data : "Emulator xenstore data", 46 REC_TYPE_emulator_context : "Emulator context", 47 REC_TYPE_checkpoint_end : "Checkpoint end", 48 REC_TYPE_checkpoint_state : "Checkpoint state" 49} 50 51# emulator_* header 52EMULATOR_HEADER_FORMAT = "II" 53 54EMULATOR_ID_unknown = 0x00000000 55EMULATOR_ID_qemu_trad = 0x00000001 56EMULATOR_ID_qemu_upstream = 0x00000002 57 58emulator_id_to_str = { 59 EMULATOR_ID_unknown : "Unknown", 60 EMULATOR_ID_qemu_trad : "Qemu Traditional", 61 EMULATOR_ID_qemu_upstream : "Qemu Upstream", 62} 63 64 65# 66# libxl format 67# 68 69LIBXL_QEMU_SIGNATURE = "DeviceModelRecord0002" 70LIBXL_QEMU_RECORD_HDR = "=%dsI" % (len(LIBXL_QEMU_SIGNATURE), ) 71 72class VerifyLibxl(VerifyBase): 73 """ Verify a Libxl v2 stream """ 74 75 def __init__(self, info, read): 76 VerifyBase.__init__(self, info, read) 77 78 79 def verify(self): 80 """ Verity a libxl stream """ 81 82 self.verify_hdr() 83 84 while self.verify_record() != REC_TYPE_end: 85 pass 86 87 88 def verify_hdr(self): 89 """ Verify a Header """ 90 ident, version, options = self.unpack_exact(HDR_FORMAT) 91 92 if ident != HDR_IDENT: 93 raise StreamError("Bad image id: Expected 0x%x, got 0x%x" 94 % (HDR_IDENT, ident)) 95 96 if version != HDR_VERSION: 97 raise StreamError("Unknown image version: Expected %d, got %d" 98 % (HDR_VERSION, version)) 99 100 if options & HDR_OPT_RESZ_MASK: 101 raise StreamError("Reserved bits set in image options field: 0x%x" 102 % (options & HDR_OPT_RESZ_MASK)) 103 104 if ( (sys.byteorder == "little") and 105 ((options & HDR_OPT_BIT_ENDIAN) != HDR_OPT_LE) ): 106 raise StreamError( 107 "Stream is not native endianess - unable to validate") 108 109 endian = ["little", "big"][options & HDR_OPT_LE] 110 111 if options & HDR_OPT_LEGACY: 112 self.info("Libxl Header: %s endian, legacy converted" % (endian, )) 113 else: 114 self.info("Libxl Header: %s endian" % (endian, )) 115 116 117 def verify_record(self): 118 """ Verify an individual record """ 119 rtype, length = self.unpack_exact(RH_FORMAT) 120 121 if rtype not in rec_type_to_str: 122 raise StreamError("Unrecognised record type %x" % (rtype, )) 123 124 self.info("Libxl Record: %s, length %d" 125 % (rec_type_to_str[rtype], length)) 126 127 contentsz = (length + 7) & ~7 128 content = self.rdexact(contentsz) 129 130 padding = content[length:] 131 if padding != "\x00" * len(padding): 132 raise StreamError("Padding containing non0 bytes found") 133 134 if rtype not in record_verifiers: 135 raise RuntimeError("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