diff --git a/hw/misc/vmport_rpc.c b/hw/misc/vmport_rpc.c
index 0ba3319..a147561 100644
--- a/hw/misc/vmport_rpc.c
+++ b/hw/misc/vmport_rpc.c
@@ -171,6 +171,14 @@ typedef struct VMPortRpcState {
     uint32_t open_cookie;
     channel_t chans[GUESTMSG_MAX_CHANNEL];
     GHashTable *guestinfo;
+    /* Temporary cache for migration purposes */
+    int32_t mig_chan_num;
+    int32_t mig_bucket_num;
+    uint32_t mig_guestinfo_size;
+    uint32_t mig_guestinfo_off;
+    uint8_t *mig_guestinfo_buf;
+    channel_control_t *mig_chans;
+    bucket_control_t *mig_buckets;
 #ifdef VMPORT_RPC_DEBUG
     unsigned int end;
     unsigned int last;
@@ -1168,6 +1176,247 @@ static Property vmport_rpc_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const VMStateDescription vmstate_vmport_rpc_chan = {
+    .name = "vmport_rpc/chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField [])
+    {
+        VMSTATE_UINT64(active_time, channel_control_t),
+        VMSTATE_UINT32(chan_id, channel_control_t),
+        VMSTATE_UINT32(cookie, channel_control_t),
+        VMSTATE_UINT32(proto_num, channel_control_t),
+        VMSTATE_UINT16(send_len, channel_control_t),
+        VMSTATE_UINT16(send_idx, channel_control_t),
+        VMSTATE_UINT16(send_buf_max, channel_control_t),
+        VMSTATE_UINT8(recv_read, channel_control_t),
+        VMSTATE_UINT8(recv_write, channel_control_t),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static const VMStateDescription vmstate_vmport_rpc_bucket = {
+    .name = "vmport_rpc/bucket",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField [])
+    {
+        VMSTATE_UINT16(recv_len, bucket_control_t),
+        VMSTATE_UINT16(recv_idx, bucket_control_t),
+        VMSTATE_UINT16(recv_buf_max, bucket_control_t),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void vmport_rpc_size_mig_guestinfo(gpointer key, gpointer value,
+                                          gpointer opaque)
+{
+    VMPortRpcState *s = opaque;
+    unsigned int key_len = strlen(key) + 1;
+    guestinfo_t *gi = value;
+
+    s->mig_guestinfo_size += 1 + key_len + 4 + gi->val_max;
+}
+
+static void vmport_rpc_fill_mig_guestinfo(gpointer key, gpointer value,
+                                          gpointer opaque)
+{
+    VMPortRpcState *s = opaque;
+    unsigned int key_len = strlen(key) + 1;
+    guestinfo_t *gi = value;
+
+    assert(gi->val_len <= gi->val_max);
+    trace_vmport_rpc_fill_mig_guestinfo(key_len, key_len, key, gi->val_len,
+                                        gi->val_len, gi->val_data);
+    s->mig_guestinfo_buf[s->mig_guestinfo_off++] = key_len;
+    memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off, key, key_len);
+    s->mig_guestinfo_off += key_len;
+    s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_len >> 8;
+    s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_len;
+    s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_max >> 8;
+    s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_max;
+    memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off, gi->val_data,
+           gi->val_max);
+    s->mig_guestinfo_off += gi->val_max;
+}
+
+static int vmport_rpc_pre_load(void *opaque)
+{
+    VMPortRpcState *s = opaque;
+
+    g_free(s->mig_guestinfo_buf);
+    s->mig_guestinfo_buf = NULL;
+    s->mig_guestinfo_size = 0;
+    s->mig_guestinfo_off = 0;
+    g_free(s->mig_chans);
+    s->mig_chans = NULL;
+    s->mig_chan_num = 0;
+    g_free(s->mig_buckets);
+    s->mig_buckets = NULL;
+    s->mig_bucket_num = 0;
+
+    return 0;
+}
+
+static void vmport_rpc_pre_save(void *opaque)
+{
+    VMPortRpcState *s = opaque;
+    unsigned int i;
+    unsigned int mig_chan_idx = 0;
+    unsigned int mig_bucket_idx = 0;
+
+    (void)vmport_rpc_pre_load(opaque);
+    for (i = 0; i < GUESTMSG_MAX_CHANNEL; ++i) {
+        channel_t *c = &s->chans[i];
+
+        if (c->ctl.proto_num) {
+            unsigned int j;
+
+            s->mig_chan_num++;
+            for (j = 0; j < MAX_BKTS; ++j) {
+                bucket_t *b = &c->recv_bkt[j];
+
+                s->mig_bucket_num++;
+                s->mig_guestinfo_size +=
+                    (b->ctl.recv_buf_max + 1) * CHAR_PER_CALL;
+            }
+            s->mig_guestinfo_size += (c->ctl.send_buf_max + 1) * CHAR_PER_CALL;
+        }
+    }
+    g_hash_table_foreach(s->guestinfo, vmport_rpc_size_mig_guestinfo, s);
+    s->mig_guestinfo_size++;
+    s->mig_guestinfo_buf = g_malloc(s->mig_guestinfo_size);
+    s->mig_chans = g_malloc(s->mig_chan_num * sizeof(channel_control_t));
+    s->mig_buckets = g_malloc(s->mig_bucket_num * sizeof(bucket_control_t));
+
+    for (i = 0; i < GUESTMSG_MAX_CHANNEL; ++i) {
+        channel_t *c = &s->chans[i];
+
+        if (c->ctl.proto_num) {
+            unsigned int j;
+            channel_control_t *cm = s->mig_chans + mig_chan_idx++;
+            unsigned int send_chars = (c->ctl.send_buf_max + 1) * CHAR_PER_CALL;
+
+            *cm = c->ctl;
+            for (j = 0; j < MAX_BKTS; ++j) {
+                bucket_t *b = &c->recv_bkt[j];
+                bucket_control_t *bm = s->mig_buckets + mig_bucket_idx++;
+                unsigned int recv_chars =
+                    (b->ctl.recv_buf_max + 1) * CHAR_PER_CALL;
+
+                *bm = b->ctl;
+                memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off,
+                       b->recv.words, recv_chars);
+                s->mig_guestinfo_off += recv_chars;
+            }
+            memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off,
+                   c->send.words, send_chars);
+            s->mig_guestinfo_off += send_chars;
+        }
+    }
+    g_hash_table_foreach(s->guestinfo, vmport_rpc_fill_mig_guestinfo, s);
+    s->mig_guestinfo_buf[s->mig_guestinfo_off++] = 0;
+    assert(s->mig_guestinfo_size == s->mig_guestinfo_off);
+    assert(s->mig_chan_num == mig_chan_idx);
+    assert(s->mig_bucket_num == mig_bucket_idx);
+}
+
+static int vmport_rpc_post_load(void *opaque, int version_id)
+{
+    VMPortRpcState *s = opaque;
+    unsigned int i;
+    unsigned int key_len;
+    unsigned int mig_bucket_idx = 0;
+
+    s->mig_guestinfo_off = 0;
+    for (i = 0; i < s->mig_chan_num; ++i) {
+        channel_control_t *cm = s->mig_chans + i;
+        channel_t *c = &s->chans[cm->chan_id];
+        unsigned int j;
+        unsigned int send_chars;
+
+        c->ctl = *cm;
+        for (j = 0; j < MAX_BKTS; ++j) {
+            bucket_t *b = &c->recv_bkt[j];
+            bucket_control_t *bm = s->mig_buckets + mig_bucket_idx++;
+            unsigned int recv_chars;
+
+            b->ctl = *bm;
+            recv_chars = (b->ctl.recv_buf_max + 1) * CHAR_PER_CALL;
+            b->recv.words =
+                g_memdup(s->mig_guestinfo_buf + s->mig_guestinfo_off,
+                         recv_chars);
+            s->mig_guestinfo_off += recv_chars;
+        }
+        send_chars = (c->ctl.send_buf_max + 1) * CHAR_PER_CALL;
+        c->send.words = g_memdup(s->mig_guestinfo_buf + s->mig_guestinfo_off,
+                                 send_chars);
+        s->mig_guestinfo_off += send_chars;
+    }
+    assert(s->mig_bucket_num == mig_bucket_idx);
+
+    do {
+        key_len = s->mig_guestinfo_buf[s->mig_guestinfo_off++];
+        if (key_len) {
+            gpointer key = g_memdup(s->mig_guestinfo_buf + s->mig_guestinfo_off,
+                                    key_len);
+            guestinfo_t *gi = g_malloc(sizeof(guestinfo_t));
+            unsigned int bhi, blow;
+
+            s->mig_guestinfo_off += key_len;
+            bhi = s->mig_guestinfo_buf[s->mig_guestinfo_off++];
+            blow = s->mig_guestinfo_buf[s->mig_guestinfo_off++];
+            gi->val_len = (bhi << 8) + blow;
+            bhi = s->mig_guestinfo_buf[s->mig_guestinfo_off++];
+            blow = s->mig_guestinfo_buf[s->mig_guestinfo_off++];
+            gi->val_max = (bhi << 8) + blow;
+            assert(gi->val_len <= gi->val_max);
+            gi->val_data = g_memdup(s->mig_guestinfo_buf +
+                                    s->mig_guestinfo_off,
+                                    gi->val_max);
+            s->mig_guestinfo_off += gi->val_max;
+            trace_vmport_rpc_post_load(key_len, key_len, key, gi->val_len,
+                                       gi->val_len, gi->val_data);
+            assert(!g_hash_table_lookup(s->guestinfo, key));
+            g_hash_table_insert(s->guestinfo, key, gi);
+        }
+    } while (key_len);
+    assert(s->mig_guestinfo_size == s->mig_guestinfo_off);
+
+    (void)vmport_rpc_pre_load(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_vmport_rpc = {
+    .name = "vmport_rpc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = vmport_rpc_pre_save,
+    .pre_load = vmport_rpc_pre_load,
+    .post_load = vmport_rpc_post_load,
+    .fields = (VMStateField[])
+    {
+        VMSTATE_UINT64(reset_time, VMPortRpcState),
+        VMSTATE_UINT64(build_number_value, VMPortRpcState),
+        VMSTATE_UINT64(build_number_time, VMPortRpcState),
+        VMSTATE_UINT64(ping_time, VMPortRpcState),
+        VMSTATE_UINT32(open_cookie, VMPortRpcState),
+        VMSTATE_INT32(mig_chan_num, VMPortRpcState),
+        VMSTATE_STRUCT_VARRAY_ALLOC(mig_chans, VMPortRpcState, mig_chan_num,
+                                    0, vmstate_vmport_rpc_chan,
+                                    channel_control_t),
+        VMSTATE_INT32(mig_bucket_num, VMPortRpcState),
+        VMSTATE_STRUCT_VARRAY_ALLOC(mig_buckets, VMPortRpcState,
+                                    mig_bucket_num, 0,
+                                    vmstate_vmport_rpc_bucket,
+                                    bucket_control_t),
+        VMSTATE_UINT32(mig_guestinfo_size, VMPortRpcState),
+        VMSTATE_VBUFFER_ALLOC_UINT32(mig_guestinfo_buf, VMPortRpcState, 1,
+                                     NULL, 0, mig_guestinfo_size),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static void vmport_rpc_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1175,6 +1424,7 @@ static void vmport_rpc_class_init(ObjectClass *klass, void *data)
     dc->realize = vmport_rpc_realize;
     dc->reset = vmport_rpc_reset;
     dc->props = vmport_rpc_properties;
+    dc->vmsd = &vmstate_vmport_rpc;
 }
 
 static const TypeInfo vmport_rpc_info = {
diff --git a/trace-events b/trace-events
index 784397d..1324b9f 100644
--- a/trace-events
+++ b/trace-events
@@ -891,9 +891,9 @@ vmport_detail_rpc_end(int sub_cmd, unsigned int ax, unsigned int bx, unsigned in
 vmport_rpc_send_skip(char *prefix, unsigned int end, unsigned int len, unsigned int k, size_t out_size, char *out) "%s%d[%d,%d,%zu]%s"
 vmport_rpc_send_normal(char *prefix, unsigned int end, unsigned int len, unsigned int k, size_t out_size, char *out) "%s%d[%d,%d,%zu]%s"
 vmport_rpc_recv_normal(char *prefix, unsigned int end, unsigned int len, unsigned int k, size_t out_size, char *out) "%s%d[%d,%d,%zu]%s"
-vmport_rpc_get_guestinfo(int klen, int kmaxlen, char *key) "klen=%d key=%.*s"
-vmport_rpc_get_guestinfo_found(int vlen, int vmaxlen, char *val) "vlen=%d val=%.*s"
-vmport_rpc_set_guestinfo(int klen, int kmaxlen, char *key, int vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s"
+vmport_rpc_get_guestinfo(short klen, int kmaxlen, char *key) "klen=%d key=%.*s"
+vmport_rpc_get_guestinfo_found(short vlen, int vmaxlen, char *val) "vlen=%d val=%.*s"
+vmport_rpc_set_guestinfo(short klen, int kmaxlen, char *key, short vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s"
 vmport_rpc_set_guestinfo_bad(int i, int used_guestinfo) "i=%d not allocated, but used_guestinfo=%d"
 vmport_rpc_send_big(int len, size_t maxlen) "recv_len=%d >= %zd"
 vmport_rpc_sweep(int chan_id, long delta) "flush %d. delta=%ld"
@@ -906,6 +906,8 @@ vmport_detail_rpc_process_send_size(int chan_id, int send_len) "chan %d is %d"
 vmport_detail_rpc_process_recv_size(int chan_id, int send_len) "chan %d is %d"
 vmport_rpc_process_close(int chan_id) "chan %d"
 vmport_rpc_process_open(int chan_id, int proto_num) "chan %d proto 0x%x"
+vmport_rpc_fill_mig_guestinfo(short klen, int kmaxlen, char *key, short vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s"
+vmport_rpc_post_load(short klen, int kmaxlen, char *key, short vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s"
 
 # hw/scsi/vmw_pvscsi.c
 pvscsi_ring_init_data(uint32_t txr_len_log2, uint32_t rxr_len_log2) "TX/RX rings logarithms set to %d/%d"
