Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2195258/?format=api
{ "id": 2195258, "url": "http://patchwork.ozlabs.org/api/patches/2195258/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260210-colo_unit_test_multifd-v8-14-7f9e5f7d082b@web.de/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260210-colo_unit_test_multifd-v8-14-7f9e5f7d082b@web.de>", "list_archive_url": null, "date": "2026-02-10T16:23:12", "name": "[v8,14/17] Convert colo main documentation to restructuredText", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "bd76c3da3b78c81bdfdcd2ad374e6514e5add803", "submitter": { "id": 76468, "url": "http://patchwork.ozlabs.org/api/people/76468/?format=api", "name": "Lukas Straub", "email": "lukasstraub2@web.de" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260210-colo_unit_test_multifd-v8-14-7f9e5f7d082b@web.de/mbox/", "series": [ { "id": 491704, "url": "http://patchwork.ozlabs.org/api/series/491704/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=491704", "date": "2026-02-10T16:23:04", "name": "migration: Add COLO multifd support and COLO migration unit test", "version": 8, "mbox": "http://patchwork.ozlabs.org/series/491704/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2195258/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2195258/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=web.de header.i=lukasstraub2@web.de header.a=rsa-sha256\n header.s=s29768273 header.b=JTsuWwS8;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)" ], "Received": [ "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4f9Rjh3kZGz1xwG\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 11 Feb 2026 03:24:56 +1100 (AEDT)", "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1vpqWe-00015F-Mn; Tue, 10 Feb 2026 11:23:44 -0500", "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <lukasstraub2@web.de>)\n id 1vpqWZ-0000yb-7l\n for qemu-devel@nongnu.org; Tue, 10 Feb 2026 11:23:40 -0500", "from mout.web.de ([212.227.15.14])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <lukasstraub2@web.de>)\n id 1vpqWU-0006zj-Uy\n for qemu-devel@nongnu.org; Tue, 10 Feb 2026 11:23:38 -0500", "from [127.0.1.1] ([141.58.43.188]) by smtp.web.de (mrweb006\n [213.165.67.108]) with ESMTPSA (Nemesis) id 1MVacq-1wHJWL0WOK-00RboJ; Tue, 10\n Feb 2026 17:23:25 +0100" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=web.de;\n s=s29768273; t=1770740605; x=1771345405; i=lukasstraub2@web.de;\n bh=hGC+m0tA3M0So0oR7D2e5cbVpsMtE6mQ3ydGsBOWEV8=;\n h=X-UI-Sender-Class:From:Date:Subject:MIME-Version:Content-Type:\n Content-Transfer-Encoding:Message-Id:References:In-Reply-To:To:Cc:\n cc:content-transfer-encoding:content-type:date:from:message-id:\n mime-version:reply-to:subject:to;\n b=JTsuWwS8ZQi9Q6l85bRF5ayJMQuf+qJqQnjx0ESqicByCUzU0Jyq3S0tXqO+KbmY\n IVjvrWbtHvAta1rZNmpVjW7Z/WJbC17cc87yLBpvojLpdwdVlUSf5dV8ejkvfzj/S\n Ldd77fiDWD/n5cLSOtB0mPGoxk5LRs5byoKWoz3MXTI5eO4ioBQ+7px5tWeu7F8pb\n FUeH4s/Ooz66R1MIEo5bVnvPdHVVy0SSNnIkM183SZ1Ya9yE81SnjijcZ6eKIrybx\n UUBo9/hjTnhIhlntO2g8kHtrZPiPVHFQMsMIgHMTod66FoGzDUCGxK3QAS2B+nR2Q\n Bl4Oa33SlpwmE8laiQ==", "X-UI-Sender-Class": "814a7b36-bfc1-4dae-8640-3722d8ec6cd6", "From": "Lukas Straub <lukasstraub2@web.de>", "Date": "Tue, 10 Feb 2026 17:23:12 +0100", "Subject": "[PATCH v8 14/17] Convert colo main documentation to restructuredText", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "quoted-printable", "Message-Id": "<20260210-colo_unit_test_multifd-v8-14-7f9e5f7d082b@web.de>", "References": "<20260210-colo_unit_test_multifd-v8-0-7f9e5f7d082b@web.de>", "In-Reply-To": "<20260210-colo_unit_test_multifd-v8-0-7f9e5f7d082b@web.de>", "To": "qemu-devel@nongnu.org", "Cc": "Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>,\n Laurent Vivier <lvivier@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>,\n Zhang Chen <zhangckid@gmail.com>,\n Hailiang Zhang <zhanghailiang@xfusion.com>,\n Markus Armbruster <armbru@redhat.com>, Li Zhijian <lizhijian@fujitsu.com>,\n \"Dr. David Alan Gilbert\" <dave@treblig.org>,\n Lukas Straub <lukasstraub2@web.de>", "X-Mailer": "b4 0.14.2", "X-Developer-Signature": "v=1; a=openpgp-sha256; l=41531; i=lukasstraub2@web.de;\n h=from:subject:message-id;\n bh=+Fe4mH4KK78+TLQ/FOH4wNoY+Th9EiHhTnmw9JF8BDE=;\n b=owEBbQKS/ZANAwAKATWrCyicXbJYAcsmYgBpi1t3abaXCzb5lBr6BK4xd4E7QL4nb54yq+aOH\n /bKGFCKRDqJAjMEAAEKAB0WIQSD+rFYoNm4+3Jij6Q1qwsonF2yWAUCaYtbdwAKCRA1qwsonF2y\n WCGWEACKbgBopcDgluE2mgrZYOIuz5fop183CP7rr7t4lvBSvhZh+FcBRT/TFIkxN4OqvN06Alu\n UigcNwXdbTWDNBE3ghOHZCqOwyL4F0rv/RYfBTZ5fPApEqQ3/bRazZ0BjkGWqTZawkdULhUPAYd\n HJD2DVnYDzi1qjBmnsQO1ZYR0npYbv2Y+WRry1foiGFPEKQ8JR4Hjt0tRSKfZaV8jcY4t5TxVOY\n 5VoArbifObWnX1OQarhzT9k9V8HyzKzqcMD5HDWYvqNjsIm6sdwQQ9rB0vLQ97Q656Vx4StinPx\n hwVtoBTG71LqiMdlR5OCYFSJ0D/u0tZCvcBXcH6hvN4IFsSYzynNhf3sFYnnHulQQZvDPmKmQMI\n HhfZ8xmtLpLjXgliqpOXLJZmR5KEZ538FYZuiVCfwNEiAeF+wPwi03kMObJ1iAu1Z8Y40wUhfcZ\n E59X3N5HUYagHFFdog4TPc/44AInZ2Df/VyRCmUIpNlPU3FVrNvT6d4dNUIL6oS+wosAE4B5+g9\n HqRWtthOOt59Igsr04NqUabtpX8Kdldia5nX6kwVwQM06EPH30BvtIQLxheSNVO1xdU5ipkq1eg\n TV4q/wjHaJK0YWBi2tYqId6SGitVtNmhBtiMJmrSrBnj9VfiX11uaWnB6dNSiSavyULjBY5eL8T\n RWqIG76bQ7walDA==", "X-Developer-Key": "i=lukasstraub2@web.de; a=openpgp;\n fpr=83FAB158A0D9B8FB72628FA435AB0B289C5DB258", "X-Provags-ID": "V03:K1:DkJ2nl3pzfGJpFltMpZvcXb5KImaJsaXSAy/tRtt7R+bzyEQO0X\n 4TYo0q7YuF3Ipe6kgVEFaO2PTs2SMqTJpbpSMMG/cX3/F5ZJzeTWyTQbkkC1Szmqzd8v2IS\n idGL5a6vuTJUah57HtqilwObhvzwgOjZX5N4xNaPSrLWnqIdXXZrn6smIQFnlUx2FmCFY8C\n 88IJrFOI/hEL6R7I6RnOA==", "UI-OutboundReport": "notjunk:1;M01:P0:7GJT3qvMuxI=;knmRf7S73UAUAv3rQ4yNdqdGdOM\n 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", "Received-SPF": "pass client-ip=212.227.15.14; envelope-from=lukasstraub2@web.de;\n helo=mout.web.de", "X-Spam_score_int": "-24", "X-Spam_score": "-2.5", "X-Spam_bar": "--", "X-Spam_report": "(-2.5 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7,\n RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001,\n RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001,\n SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no", "X-Spam_action": "no action", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "qemu development <qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org" }, "content": "Reviewed-by: Fabiano Rosas <farosas@suse.de>\nReviewed-by: Zhang Chen <zhangckid@gmail.com>\nSigned-off-by: Lukas Straub <lukasstraub2@web.de>\n---\n MAINTAINERS | 2 +-\n docs/COLO-FT.txt | 334 ------------------------------------------\n docs/system/index.rst | 1 +\n docs/system/qemu-colo.rst | 360 ++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 362 insertions(+), 335 deletions(-)", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex fe6010929fc4cb83bc8a7686fbe537f1120f1eba..50beba7cb105efb867c7d8cb140357f329241654 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -3863,7 +3863,7 @@ F: migration/multifd-colo.*\n F: include/migration/colo.h\n F: include/migration/failover.h\n F: tests/qtest/migration/colo-tests.c\n-F: docs/COLO-FT.txt\n+F: docs/system/qemu-colo.rst\n \n COLO Proxy\n M: Zhang Chen <zhangckid@gmail.com>\ndiff --git a/docs/COLO-FT.txt b/docs/COLO-FT.txt\ndeleted file mode 100644\nindex 2283a09c080b8996f9767eeb415e8d4fbdc940af..0000000000000000000000000000000000000000\n--- a/docs/COLO-FT.txt\n+++ /dev/null\n@@ -1,334 +0,0 @@\n-COarse-grained LOck-stepping Virtual Machines for Non-stop Service\n-----------------------------------------\n-Copyright (c) 2016 Intel Corporation\n-Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.\n-Copyright (c) 2016 Fujitsu, Corp.\n-\n-This work is licensed under the terms of the GNU GPL, version 2 or later.\n-See the COPYING file in the top-level directory.\n-\n-This document gives an overview of COLO's design and how to use it.\n-\n-== Background ==\n-Virtual machine (VM) replication is a well known technique for providing\n-application-agnostic software-implemented hardware fault tolerance,\n-also known as \"non-stop service\".\n-\n-COLO (COarse-grained LOck-stepping) is a high availability solution.\n-Both primary VM (PVM) and secondary VM (SVM) run in parallel. They receive the\n-same request from client, and generate response in parallel too.\n-If the response packets from PVM and SVM are identical, they are released\n-immediately. Otherwise, a VM checkpoint (on demand) is conducted.\n-\n-== Architecture ==\n-\n-The architecture of COLO is shown in the diagram below.\n-It consists of a pair of networked physical nodes:\n-The primary node running the PVM, and the secondary node running the SVM\n-to maintain a valid replica of the PVM.\n-PVM and SVM execute in parallel and generate output of response packets for\n-client requests according to the application semantics.\n-\n-The incoming packets from the client or external network are received by the\n-primary node, and then forwarded to the secondary node, so that both the PVM\n-and the SVM are stimulated with the same requests.\n-\n-COLO receives the outbound packets from both the PVM and SVM and compares them\n-before allowing the output to be sent to clients.\n-\n-The SVM is qualified as a valid replica of the PVM, as long as it generates\n-identical responses to all client requests. Once the differences in the outputs\n-are detected between the PVM and SVM, COLO withholds transmission of the\n-outbound packets until it has successfully synchronized the PVM state to the SVM.\n-\n- Primary Node Secondary Node\n-+------------+ +-----------------------+ +------------------------+ +------------+\n-| | | HeartBeat +<----->+ HeartBeat | | |\n-| Primary VM | +-----------+-----------+ +-----------+------------+ |Secondary VM|\n-| | | | | |\n-| | +-----------|-----------+ +-----------|------------+ | |\n-| | |QEMU +---v----+ | |QEMU +----v---+ | | |\n-| | | |Failover| | | |Failover| | | |\n-| | | +--------+ | | +--------+ | | |\n-| | | +---------------+ | | +---------------+ | | |\n-| | | | VM Checkpoint +-------------->+ VM Checkpoint | | | |\n-| | | +---------------+ | | +---------------+ | | |\n-|Requests<--------------------------\\ /-----------------\\ /--------------------->Requests|\n-| | | ^ ^ | | | | | | |\n-|Responses+---------------------\\ /-|-|------------\\ /-------------------------+Responses|\n-| | | | | | | | | | | | | | | |\n-| | | +-----------+ | | | | | | | | | | +----------+ | | |\n-| | | | COLO disk | | | | | | | | | | | | COLO disk| | | |\n-| | | | Manager +---------------------------->| Manager | | | |\n-| | | ++----------+ v v | | | | | v v | +---------++ | | |\n-| | | |+-----------+-+-+-++| | ++-+--+-+---------+ | | | |\n-| | | || COLO Proxy || | | COLO Proxy | | | | |\n-| | | || (compare packet || | |(adjust sequence | | | | |\n-| | | ||and mirror packet)|| | | and ACK) | | | | |\n-| | | |+------------+---+-+| | +-----------------+ | | | |\n-+------------+ +-----------------------+ +------------------------+ +------------+\n-+------------+ | | | | +------------+\n-| VM Monitor | | | | | | VM Monitor |\n-+------------+ | | | | +------------+\n-+---------------------------------------+ +----------------------------------------+\n-| Kernel | | | | | Kernel | |\n-+---------------------------------------+ +----------------------------------------+\n- | | | |\n- +--------------v+ +---------v---+--+ +------------------+ +v-------------+\n- | Storage | |External Network| | External Network | | Storage |\n- +---------------+ +----------------+ +------------------+ +--------------+\n-\n-\n-== Components introduction ==\n-\n-You can see there are several components in COLO's diagram of architecture.\n-Their functions are described below.\n-\n-HeartBeat:\n-Runs on both the primary and secondary nodes, to periodically check platform\n-availability. When the primary node suffers a hardware fail-stop failure,\n-the heartbeat stops responding, the secondary node will trigger a failover\n-as soon as it determines the absence.\n-\n-COLO disk Manager:\n-When primary VM writes data into image, the colo disk manager captures this data\n-and sends it to secondary VM's which makes sure the context of secondary VM's\n-image is consistent with the context of primary VM 's image.\n-For more details, please refer to docs/block-replication.txt.\n-\n-Checkpoint/Failover Controller:\n-Modifications of save/restore flow to realize continuous migration,\n-to make sure the state of VM in Secondary side is always consistent with VM in\n-Primary side.\n-\n-COLO Proxy:\n-Delivers packets to Primary and Secondary, and then compare the responses from\n-both side. Then decide whether to start a checkpoint according to some rules.\n-Please refer to docs/colo-proxy.txt for more information.\n-\n-Note:\n-HeartBeat has not been implemented yet, so you need to trigger failover process\n-by using 'x-colo-lost-heartbeat' command.\n-\n-== COLO operation status ==\n-\n-+-----------------+\n-| |\n-| Start COLO |\n-| |\n-+--------+--------+\n- |\n- | Main qmp command:\n- | migrate-set-capabilities with x-colo\n- | migrate\n- |\n- v\n-+--------+--------+\n-| |\n-| COLO running |\n-| |\n-+--------+--------+\n- |\n- | Main qmp command:\n- | x-colo-lost-heartbeat\n- | or\n- | some error happened\n- v\n-+--------+--------+\n-| | send qmp event:\n-| COLO failover | COLO_EXIT\n-| |\n-+-----------------+\n-\n-COLO use the qmp command to switch and report operation status.\n-The diagram just shows the main qmp command, you can get the detail\n-in test procedure.\n-\n-== Test procedure ==\n-Note: Here we are running both instances on the same host for testing,\n-change the IP Addresses if you want to run it on two hosts. Initially\n-127.0.0.1 is the Primary Host and 127.0.0.2 is the Secondary Host.\n-\n-== Startup qemu ==\n-1. Primary:\n-Note: Initially, $imagefolder/primary.qcow2 needs to be copied to all hosts.\n-You don't need to change any IP's here, because 0.0.0.0 listens on any\n-interface. The chardev's with 127.0.0.1 IP's loopback to the local qemu\n-instance.\n-\n-# imagefolder=\"/mnt/vms/colo-test-primary\"\n-\n-# qemu-system-x86_64 -enable-kvm -cpu qemu64,kvmclock=on -m 512 -smp 1 -qmp stdio \\\n- -device piix3-usb-uhci -device usb-tablet -name primary \\\n- -netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \\\n- -device rtl8139,id=e0,netdev=hn0 \\\n- -chardev socket,id=mirror0,host=0.0.0.0,port=9003,server=on,wait=off \\\n- -chardev socket,id=compare1,host=0.0.0.0,port=9004,server=on,wait=on \\\n- -chardev socket,id=compare0,host=127.0.0.1,port=9001,server=on,wait=off \\\n- -chardev socket,id=compare0-0,host=127.0.0.1,port=9001 \\\n- -chardev socket,id=compare_out,host=127.0.0.1,port=9005,server=on,wait=off \\\n- -chardev socket,id=compare_out0,host=127.0.0.1,port=9005 \\\n- -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 \\\n- -object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out \\\n- -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 \\\n- -object iothread,id=iothread1 \\\n- -object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,\\\n-outdev=compare_out0,iothread=iothread1 \\\n- -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\\\n-children.0.file.filename=$imagefolder/primary.qcow2,children.0.driver=qcow2 -S\n-\n-2. Secondary:\n-Note: Active and hidden images need to be created only once and the\n-size should be the same as primary.qcow2. Again, you don't need to change\n-any IP's here, except for the $primary_ip variable.\n-\n-# imagefolder=\"/mnt/vms/colo-test-secondary\"\n-# primary_ip=127.0.0.1\n-\n-# qemu-img create -f qcow2 $imagefolder/secondary-active.qcow2 10G\n-\n-# qemu-img create -f qcow2 $imagefolder/secondary-hidden.qcow2 10G\n-\n-# qemu-system-x86_64 -enable-kvm -cpu qemu64,kvmclock=on -m 512 -smp 1 -qmp stdio \\\n- -device piix3-usb-uhci -device usb-tablet -name secondary \\\n- -netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \\\n- -device rtl8139,id=e0,netdev=hn0 \\\n- -chardev socket,id=red0,host=$primary_ip,port=9003,reconnect-ms=1000 \\\n- -chardev socket,id=red1,host=$primary_ip,port=9004,reconnect-ms=1000 \\\n- -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 \\\n- -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 \\\n- -object filter-rewriter,id=rew0,netdev=hn0,queue=all \\\n- -drive if=none,id=parent0,file.filename=$imagefolder/primary.qcow2,driver=qcow2 \\\n- -drive if=none,id=childs0,driver=replication,mode=secondary,file.driver=qcow2,\\\n-top-id=colo-disk0,file.file.filename=$imagefolder/secondary-active.qcow2,\\\n-file.backing.driver=qcow2,file.backing.file.filename=$imagefolder/secondary-hidden.qcow2,\\\n-file.backing.backing=parent0 \\\n- -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\\\n-children.0=childs0 \\\n- -incoming tcp:0.0.0.0:9998\n-\n-\n-3. On Secondary VM's QEMU monitor, issue command\n-{\"execute\":\"qmp_capabilities\"}\n-{\"execute\": \"migrate-set-capabilities\", \"arguments\": {\"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n-{\"execute\": \"nbd-server-start\", \"arguments\": {\"addr\": {\"type\": \"inet\", \"data\": {\"host\": \"0.0.0.0\", \"port\": \"9999\"} } } }\n-{\"execute\": \"nbd-server-add\", \"arguments\": {\"device\": \"parent0\", \"writable\": true } }\n-\n-Note:\n- a. The qmp command nbd-server-start and nbd-server-add must be run\n- before running the qmp command migrate on primary QEMU\n- b. Active disk, hidden disk and nbd target's length should be the\n- same.\n- c. It is better to put active disk and hidden disk in ramdisk. They\n- will be merged into the parent disk on failover.\n-\n-4. On Primary VM's QEMU monitor, issue command:\n-{\"execute\":\"qmp_capabilities\"}\n-{\"execute\": \"human-monitor-command\", \"arguments\": {\"command-line\": \"drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0\"}}\n-{\"execute\": \"x-blockdev-change\", \"arguments\":{\"parent\": \"colo-disk0\", \"node\": \"replication0\" } }\n-{\"execute\": \"migrate-set-capabilities\", \"arguments\": {\"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n-{\"execute\": \"migrate\", \"arguments\": {\"uri\": \"tcp:127.0.0.2:9998\" } }\n-\n- Note:\n- a. There should be only one NBD Client for each primary disk.\n- b. The qmp command line must be run after running qmp command line in\n- secondary qemu.\n-\n-5. After the above steps, you will see, whenever you make changes to PVM, SVM will be synced.\n-You can issue command '{ \"execute\": \"migrate-set-parameters\" , \"arguments\":{ \"x-checkpoint-delay\": 2000 } }'\n-to change the idle checkpoint period time\n-\n-6. Failover test\n-You can kill one of the VMs and Failover on the surviving VM:\n-\n-If you killed the Secondary, then follow \"Primary Failover\". After that,\n-if you want to resume the replication, follow \"Primary resume replication\"\n-\n-If you killed the Primary, then follow \"Secondary Failover\". After that,\n-if you want to resume the replication, follow \"Secondary resume replication\"\n-\n-== Primary Failover ==\n-The Secondary died, resume on the Primary\n-\n-{\"execute\": \"x-blockdev-change\", \"arguments\":{ \"parent\": \"colo-disk0\", \"child\": \"children.1\"} }\n-{\"execute\": \"human-monitor-command\", \"arguments\":{ \"command-line\": \"drive_del replication0\" } }\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"comp0\" } }\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"iothread1\" } }\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"m0\" } }\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"redire0\" } }\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"redire1\" } }\n-{\"execute\": \"x-colo-lost-heartbeat\" }\n-\n-== Secondary Failover ==\n-The Primary died, resume on the Secondary and prepare to become the new Primary\n-\n-{\"execute\": \"nbd-server-stop\"}\n-{\"execute\": \"x-colo-lost-heartbeat\"}\n-\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"f2\" } }\n-{\"execute\": \"object-del\", \"arguments\":{ \"id\": \"f1\" } }\n-{\"execute\": \"chardev-remove\", \"arguments\":{ \"id\": \"red1\" } }\n-{\"execute\": \"chardev-remove\", \"arguments\":{ \"id\": \"red0\" } }\n-\n-{\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"mirror0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"0.0.0.0\", \"port\": \"9003\" } }, \"server\": true } } } }\n-{\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare1\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"0.0.0.0\", \"port\": \"9004\" } }, \"server\": true } } } }\n-{\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9001\" } }, \"server\": true } } } }\n-{\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare0-0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9001\" } }, \"server\": false } } } }\n-{\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare_out\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9005\" } }, \"server\": true } } } }\n-{\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare_out0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9005\" } }, \"server\": false } } } }\n-\n-== Primary resume replication ==\n-Resume replication after new Secondary is up.\n-\n-Start the new Secondary (Steps 2 and 3 above), then on the Primary:\n-{\"execute\": \"drive-mirror\", \"arguments\":{ \"device\": \"colo-disk0\", \"job-id\": \"resync\", \"target\": \"nbd://127.0.0.2:9999/parent0\", \"mode\": \"existing\", \"format\": \"raw\", \"sync\": \"full\"} }\n-\n-Wait until disk is synced, then:\n-{\"execute\": \"stop\"}\n-{\"execute\": \"block-job-cancel\", \"arguments\":{ \"device\": \"resync\"} }\n-\n-{\"execute\": \"human-monitor-command\", \"arguments\":{ \"command-line\": \"drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0\"}}\n-{\"execute\": \"x-blockdev-change\", \"arguments\":{ \"parent\": \"colo-disk0\", \"node\": \"replication0\" } }\n-\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-mirror\", \"id\": \"m0\", \"netdev\": \"hn0\", \"queue\": \"tx\", \"outdev\": \"mirror0\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire0\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"indev\": \"compare_out\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire1\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"outdev\": \"compare0\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"iothread\", \"id\": \"iothread1\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"colo-compare\", \"id\": \"comp0\", \"primary_in\": \"compare0-0\", \"secondary_in\": \"compare1\", \"outdev\": \"compare_out0\", \"iothread\": \"iothread1\" } }\n-\n-{\"execute\": \"migrate-set-capabilities\", \"arguments\":{ \"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n-{\"execute\": \"migrate\", \"arguments\":{ \"uri\": \"tcp:127.0.0.2:9998\" } }\n-\n-Note:\n-If this Primary previously was a Secondary, then we need to insert the\n-filters before the filter-rewriter by using the\n-\"\"insert\": \"before\", \"position\": \"id=rew0\"\" Options. See below.\n-\n-== Secondary resume replication ==\n-Become Primary and resume replication after new Secondary is up. Note\n-that now 127.0.0.1 is the Secondary and 127.0.0.2 is the Primary.\n-\n-Start the new Secondary (Steps 2 and 3 above, but with primary_ip=127.0.0.2),\n-then on the old Secondary:\n-{\"execute\": \"drive-mirror\", \"arguments\":{ \"device\": \"colo-disk0\", \"job-id\": \"resync\", \"target\": \"nbd://127.0.0.1:9999/parent0\", \"mode\": \"existing\", \"format\": \"raw\", \"sync\": \"full\"} }\n-\n-Wait until disk is synced, then:\n-{\"execute\": \"stop\"}\n-{\"execute\": \"block-job-cancel\", \"arguments\":{ \"device\": \"resync\" } }\n-\n-{\"execute\": \"human-monitor-command\", \"arguments\":{ \"command-line\": \"drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.1,file.port=9999,file.export=parent0,node-name=replication0\"}}\n-{\"execute\": \"x-blockdev-change\", \"arguments\":{ \"parent\": \"colo-disk0\", \"node\": \"replication0\" } }\n-\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-mirror\", \"id\": \"m0\", \"insert\": \"before\", \"position\": \"id=rew0\", \"netdev\": \"hn0\", \"queue\": \"tx\", \"outdev\": \"mirror0\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire0\", \"insert\": \"before\", \"position\": \"id=rew0\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"indev\": \"compare_out\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire1\", \"insert\": \"before\", \"position\": \"id=rew0\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"outdev\": \"compare0\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"iothread\", \"id\": \"iothread1\" } }\n-{\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"colo-compare\", \"id\": \"comp0\", \"primary_in\": \"compare0-0\", \"secondary_in\": \"compare1\", \"outdev\": \"compare_out0\", \"iothread\": \"iothread1\" } }\n-\n-{\"execute\": \"migrate-set-capabilities\", \"arguments\":{ \"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n-{\"execute\": \"migrate\", \"arguments\":{ \"uri\": \"tcp:127.0.0.1:9998\" } }\n-\n-== TODO ==\n-1. Support shared storage.\n-2. Develop the heartbeat part.\n-3. Reduce checkpoint VM’s downtime while doing checkpoint.\ndiff --git a/docs/system/index.rst b/docs/system/index.rst\nindex 427b020483104f6589878bbf255a367ae114c61b..6268c41aea9c74dc3e59d896b5ae082360bfbb1a 100644\n--- a/docs/system/index.rst\n+++ b/docs/system/index.rst\n@@ -41,3 +41,4 @@ or Hypervisor.Framework.\n igvm\n vm-templating\n sriov\n+ qemu-colo\ndiff --git a/docs/system/qemu-colo.rst b/docs/system/qemu-colo.rst\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..4b5fbbf398f8a5c4ea6baad615bde94b2b4678d2\n--- /dev/null\n+++ b/docs/system/qemu-colo.rst\n@@ -0,0 +1,360 @@\n+Qemu COLO Fault Tolerance\n+=========================\n+\n+| Copyright (c) 2016 Intel Corporation\n+| Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.\n+| Copyright (c) 2016 Fujitsu, Corp.\n+\n+This work is licensed under the terms of the GNU GPL, version 2 or later.\n+See the COPYING file in the top-level directory.\n+\n+This document gives an overview of COLO's design and how to use it.\n+\n+Background\n+----------\n+Virtual machine (VM) replication is a well known technique for providing\n+application-agnostic software-implemented hardware fault tolerance,\n+also known as \"non-stop service\".\n+\n+COLO (COarse-grained LOck-stepping) is a high availability solution.\n+Both primary VM (PVM) and secondary VM (SVM) run in parallel. They receive the\n+same request from client, and generate response in parallel too.\n+If the response packets from PVM and SVM are identical, they are released\n+immediately. Otherwise, a VM checkpoint (on demand) is conducted.\n+\n+Architecture\n+------------\n+The architecture of COLO is shown in the diagram below.\n+It consists of a pair of networked physical nodes:\n+The primary node running the PVM, and the secondary node running the SVM\n+to maintain a valid replica of the PVM.\n+PVM and SVM execute in parallel and generate output of response packets for\n+client requests according to the application semantics.\n+\n+The incoming packets from the client or external network are received by the\n+primary node, and then forwarded to the secondary node, so that both the PVM\n+and the SVM are stimulated with the same requests.\n+\n+COLO receives the outbound packets from both the PVM and SVM and compares them\n+before allowing the output to be sent to clients.\n+\n+The SVM is qualified as a valid replica of the PVM, as long as it generates\n+identical responses to all client requests. Once the differences in the outputs\n+are detected between the PVM and SVM, COLO withholds transmission of the\n+outbound packets until it has successfully synchronized the PVM state to the SVM.\n+\n+Overview::\n+\n+ Primary Node Secondary Node\n+ +------------+ +-----------------------+ +------------------------+ +------------+\n+ | | | HeartBeat +<----->+ HeartBeat | | |\n+ | Primary VM | +-----------+-----------+ +-----------+------------+ |Secondary VM|\n+ | | | | | |\n+ | | +-----------|-----------+ +-----------|------------+ | |\n+ | | |QEMU +---v----+ | |QEMU +----v---+ | | |\n+ | | | |Failover| | | |Failover| | | |\n+ | | | +--------+ | | +--------+ | | |\n+ | | | +---------------+ | | +---------------+ | | |\n+ | | | | VM Checkpoint +-------------->+ VM Checkpoint | | | |\n+ | | | +---------------+ | | +---------------+ | | |\n+ |Requests<--------------------------\\ /-----------------\\ /--------------------->Requests|\n+ | | | ^ ^ | | | | | | |\n+ |Responses+---------------------\\ /-|-|------------\\ /-------------------------+Responses|\n+ | | | | | | | | | | | | | | | |\n+ | | | +-----------+ | | | | | | | | | | +----------+ | | |\n+ | | | | COLO disk | | | | | | | | | | | | COLO disk| | | |\n+ | | | | Manager +---------------------------->| Manager | | | |\n+ | | | ++----------+ v v | | | | | v v | +---------++ | | |\n+ | | | |+-----------+-+-+-++| | ++-+--+-+---------+ | | | |\n+ | | | || COLO Proxy || | | COLO Proxy | | | | |\n+ | | | || (compare packet || | |(adjust sequence | | | | |\n+ | | | ||and mirror packet)|| | | and ACK) | | | | |\n+ | | | |+------------+---+-+| | +-----------------+ | | | |\n+ +------------+ +-----------------------+ +------------------------+ +------------+\n+ +------------+ | | | | +------------+\n+ | VM Monitor | | | | | | VM Monitor |\n+ +------------+ | | | | +------------+\n+ +---------------------------------------+ +----------------------------------------+\n+ | Kernel | | | | | Kernel | |\n+ +---------------------------------------+ +----------------------------------------+\n+ | | | |\n+ +--------------v+ +---------v---+--+ +------------------+ +v-------------+\n+ | Storage | |External Network| | External Network | | Storage |\n+ +---------------+ +----------------+ +------------------+ +--------------+\n+\n+Components introduction\n+^^^^^^^^^^^^^^^^^^^^^^^\n+You can see there are several components in COLO's diagram of architecture.\n+Their functions are described below.\n+\n+HeartBeat\n+~~~~~~~~~\n+Runs on both the primary and secondary nodes, to periodically check platform\n+availability. When the primary node suffers a hardware fail-stop failure,\n+the heartbeat stops responding, the secondary node will trigger a failover\n+as soon as it determines the absence.\n+\n+COLO disk Manager\n+~~~~~~~~~~~~~~~~~\n+When primary VM writes data into image, the colo disk manager captures this data\n+and sends it to secondary VM's which makes sure the context of secondary VM's\n+image is consistent with the context of primary VM 's image.\n+For more details, please refer to docs/block-replication.txt.\n+\n+Checkpoint/Failover Controller\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+Modifications of save/restore flow to realize continuous migration,\n+to make sure the state of VM in Secondary side is always consistent with VM in\n+Primary side.\n+\n+COLO Proxy\n+~~~~~~~~~~\n+Delivers packets to Primary and Secondary, and then compare the responses from\n+both side. Then decide whether to start a checkpoint according to some rules.\n+Please refer to docs/colo-proxy.txt for more information.\n+\n+Note:\n+HeartBeat has not been implemented yet, so you need to trigger failover process\n+by using 'x-colo-lost-heartbeat' command.\n+\n+COLO operation status\n+^^^^^^^^^^^^^^^^^^^^^\n+\n+Overview::\n+\n+ +-----------------+\n+ | |\n+ | Start COLO |\n+ | |\n+ +--------+--------+\n+ |\n+ | Main qmp command:\n+ | migrate-set-capabilities with x-colo\n+ | migrate\n+ |\n+ v\n+ +--------+--------+\n+ | |\n+ | COLO running |\n+ | |\n+ +--------+--------+\n+ |\n+ | Main qmp command:\n+ | x-colo-lost-heartbeat\n+ | or\n+ | some error happened\n+ v\n+ +--------+--------+\n+ | | send qmp event:\n+ | COLO failover | COLO_EXIT\n+ | |\n+ +-----------------+\n+\n+\n+COLO use the qmp command to switch and report operation status.\n+The diagram just shows the main qmp command, you can get the detail\n+in test procedure.\n+\n+Test procedure\n+--------------\n+Note: Here we are running both instances on the same host for testing,\n+change the IP Addresses if you want to run it on two hosts. Initially\n+``127.0.0.1`` is the Primary Host and ``127.0.0.2`` is the Secondary Host.\n+\n+Startup qemu\n+^^^^^^^^^^^^\n+**1. Primary**:\n+Note: Initially, ``$imagefolder/primary.qcow2`` needs to be copied to all hosts.\n+You don't need to change any IP's here, because ``0.0.0.0`` listens on any\n+interface. The chardev's with ``127.0.0.1`` IP's loopback to the local qemu\n+instance::\n+\n+ # imagefolder=\"/mnt/vms/colo-test-primary\"\n+\n+ # qemu-system-x86_64 -enable-kvm -cpu qemu64,kvmclock=on -m 512 -smp 1 -qmp stdio \\\n+ -device piix3-usb-uhci -device usb-tablet -name primary \\\n+ -netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \\\n+ -device rtl8139,id=e0,netdev=hn0 \\\n+ -chardev socket,id=mirror0,host=0.0.0.0,port=9003,server=on,wait=off \\\n+ -chardev socket,id=compare1,host=0.0.0.0,port=9004,server=on,wait=on \\\n+ -chardev socket,id=compare0,host=127.0.0.1,port=9001,server=on,wait=off \\\n+ -chardev socket,id=compare0-0,host=127.0.0.1,port=9001 \\\n+ -chardev socket,id=compare_out,host=127.0.0.1,port=9005,server=on,wait=off \\\n+ -chardev socket,id=compare_out0,host=127.0.0.1,port=9005 \\\n+ -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 \\\n+ -object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out \\\n+ -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 \\\n+ -object iothread,id=iothread1 \\\n+ -object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,\\\n+ outdev=compare_out0,iothread=iothread1 \\\n+ -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\\\n+ children.0.file.filename=$imagefolder/primary.qcow2,children.0.driver=qcow2 -S\n+\n+\n+**2. Secondary**:\n+Note: Active and hidden images need to be created only once and the\n+size should be the same as ``primary.qcow2``. Again, you don't need to change\n+any IP's here, except for the ``$primary_ip`` variable::\n+\n+ # imagefolder=\"/mnt/vms/colo-test-secondary\"\n+ # primary_ip=127.0.0.1\n+\n+ # qemu-img create -f qcow2 $imagefolder/secondary-active.qcow2 10G\n+\n+ # qemu-img create -f qcow2 $imagefolder/secondary-hidden.qcow2 10G\n+\n+ # qemu-system-x86_64 -enable-kvm -cpu qemu64,kvmclock=on -m 512 -smp 1 -qmp stdio \\\n+ -device piix3-usb-uhci -device usb-tablet -name secondary \\\n+ -netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \\\n+ -device rtl8139,id=e0,netdev=hn0 \\\n+ -chardev socket,id=red0,host=$primary_ip,port=9003,reconnect-ms=1000 \\\n+ -chardev socket,id=red1,host=$primary_ip,port=9004,reconnect-ms=1000 \\\n+ -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 \\\n+ -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 \\\n+ -object filter-rewriter,id=rew0,netdev=hn0,queue=all \\\n+ -drive if=none,id=parent0,file.filename=$imagefolder/primary.qcow2,driver=qcow2 \\\n+ -drive if=none,id=childs0,driver=replication,mode=secondary,file.driver=qcow2,\\\n+ top-id=colo-disk0,file.file.filename=$imagefolder/secondary-active.qcow2,\\\n+ file.backing.driver=qcow2,file.backing.file.filename=$imagefolder/secondary-hidden.qcow2,\\\n+ file.backing.backing=parent0 \\\n+ -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\\\n+ children.0=childs0 \\\n+ -incoming tcp:0.0.0.0:9998\n+\n+\n+**3.** On Secondary VM's QEMU monitor, issue command::\n+\n+ {\"execute\":\"qmp_capabilities\"}\n+ {\"execute\": \"migrate-set-capabilities\", \"arguments\": {\"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n+ {\"execute\": \"nbd-server-start\", \"arguments\": {\"addr\": {\"type\": \"inet\", \"data\": {\"host\": \"0.0.0.0\", \"port\": \"9999\"} } } }\n+ {\"execute\": \"nbd-server-add\", \"arguments\": {\"device\": \"parent0\", \"writable\": true } }\n+\n+Note:\n+ a. The qmp command ``nbd-server-start`` and ``nbd-server-add`` must be run\n+ before running the qmp command migrate on primary QEMU\n+ b. Active disk, hidden disk and nbd target's length should be the\n+ same.\n+ c. It is better to put active disk and hidden disk in ramdisk. They\n+ will be merged into the parent disk on failover.\n+\n+**4.** On Primary VM's QEMU monitor, issue command::\n+\n+ {\"execute\":\"qmp_capabilities\"}\n+ {\"execute\": \"human-monitor-command\", \"arguments\": {\"command-line\": \"drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0\"}}\n+ {\"execute\": \"x-blockdev-change\", \"arguments\":{\"parent\": \"colo-disk0\", \"node\": \"replication0\" } }\n+ {\"execute\": \"migrate-set-capabilities\", \"arguments\": {\"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n+ {\"execute\": \"migrate\", \"arguments\": {\"uri\": \"tcp:127.0.0.2:9998\" } }\n+\n+Note:\n+ a. There should be only one NBD Client for each primary disk.\n+ b. The qmp command line must be run after running qmp command line in\n+ secondary qemu.\n+\n+**5.** After the above steps, you will see, whenever you make changes to PVM, SVM will be synced.\n+You can issue command ``{ \"execute\": \"migrate-set-parameters\" , \"arguments\":{ \"x-checkpoint-delay\": 2000 } }``\n+to change the idle checkpoint period time\n+\n+Failover test\n+^^^^^^^^^^^^^\n+You can kill one of the VMs and Failover on the surviving VM:\n+\n+If you killed the Secondary, then follow \"Primary Failover\".\n+After that, if you want to resume the replication, follow \"Primary resume replication\"\n+\n+If you killed the Primary, then follow \"Secondary Failover\".\n+After that, if you want to resume the replication, follow \"Secondary resume replication\"\n+\n+Primary Failover\n+~~~~~~~~~~~~~~~~\n+The Secondary died, resume on the Primary::\n+\n+ {\"execute\": \"x-blockdev-change\", \"arguments\":{ \"parent\": \"colo-disk0\", \"child\": \"children.1\"} }\n+ {\"execute\": \"human-monitor-command\", \"arguments\":{ \"command-line\": \"drive_del replication0\" } }\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"comp0\" } }\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"iothread1\" } }\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"m0\" } }\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"redire0\" } }\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"redire1\" } }\n+ {\"execute\": \"x-colo-lost-heartbeat\" }\n+\n+Secondary Failover\n+~~~~~~~~~~~~~~~~~~\n+The Primary died, resume on the Secondary and prepare to become the new Primary::\n+\n+ {\"execute\": \"nbd-server-stop\"}\n+ {\"execute\": \"x-colo-lost-heartbeat\"}\n+\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"f2\" } }\n+ {\"execute\": \"object-del\", \"arguments\":{ \"id\": \"f1\" } }\n+ {\"execute\": \"chardev-remove\", \"arguments\":{ \"id\": \"red1\" } }\n+ {\"execute\": \"chardev-remove\", \"arguments\":{ \"id\": \"red0\" } }\n+\n+ {\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"mirror0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"0.0.0.0\", \"port\": \"9003\" } }, \"server\": true } } } }\n+ {\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare1\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"0.0.0.0\", \"port\": \"9004\" } }, \"server\": true } } } }\n+ {\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9001\" } }, \"server\": true } } } }\n+ {\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare0-0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9001\" } }, \"server\": false } } } }\n+ {\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare_out\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9005\" } }, \"server\": true } } } }\n+ {\"execute\": \"chardev-add\", \"arguments\":{ \"id\": \"compare_out0\", \"backend\": {\"type\": \"socket\", \"data\": {\"addr\": { \"type\": \"inet\", \"data\": { \"host\": \"127.0.0.1\", \"port\": \"9005\" } }, \"server\": false } } } }\n+\n+Primary resume replication\n+~~~~~~~~~~~~~~~~~~~~~~~~~~\n+Resume replication after new Secondary is up.\n+\n+Start the new Secondary (Steps 2 and 3 above), then on the Primary::\n+\n+ {\"execute\": \"drive-mirror\", \"arguments\":{ \"device\": \"colo-disk0\", \"job-id\": \"resync\", \"target\": \"nbd://127.0.0.2:9999/parent0\", \"mode\": \"existing\", \"format\": \"raw\", \"sync\": \"full\"} }\n+\n+Wait until disk is synced, then::\n+\n+ {\"execute\": \"stop\"}\n+ {\"execute\": \"block-job-cancel\", \"arguments\":{ \"device\": \"resync\"} }\n+\n+ {\"execute\": \"human-monitor-command\", \"arguments\":{ \"command-line\": \"drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0\"}}\n+ {\"execute\": \"x-blockdev-change\", \"arguments\":{ \"parent\": \"colo-disk0\", \"node\": \"replication0\" } }\n+\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-mirror\", \"id\": \"m0\", \"netdev\": \"hn0\", \"queue\": \"tx\", \"outdev\": \"mirror0\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire0\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"indev\": \"compare_out\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire1\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"outdev\": \"compare0\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"iothread\", \"id\": \"iothread1\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"colo-compare\", \"id\": \"comp0\", \"primary_in\": \"compare0-0\", \"secondary_in\": \"compare1\", \"outdev\": \"compare_out0\", \"iothread\": \"iothread1\" } }\n+\n+ {\"execute\": \"migrate-set-capabilities\", \"arguments\":{ \"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n+ {\"execute\": \"migrate\", \"arguments\":{ \"uri\": \"tcp:127.0.0.2:9998\" } }\n+\n+Note:\n+If this Primary previously was a Secondary, then we need to insert the\n+filters before the filter-rewriter by using the\n+\"\"insert\": \"before\", \"position\": \"id=rew0\"\" Options. See below.\n+\n+Secondary resume replication\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+Become Primary and resume replication after new Secondary is up. Note\n+that now 127.0.0.1 is the Secondary and 127.0.0.2 is the Primary.\n+\n+Start the new Secondary (Steps 2 and 3 above, but with primary_ip=127.0.0.2),\n+then on the old Secondary::\n+\n+ {\"execute\": \"drive-mirror\", \"arguments\":{ \"device\": \"colo-disk0\", \"job-id\": \"resync\", \"target\": \"nbd://127.0.0.1:9999/parent0\", \"mode\": \"existing\", \"format\": \"raw\", \"sync\": \"full\"} }\n+\n+Wait until disk is synced, then::\n+\n+ {\"execute\": \"stop\"}\n+ {\"execute\": \"block-job-cancel\", \"arguments\":{ \"device\": \"resync\" } }\n+\n+ {\"execute\": \"human-monitor-command\", \"arguments\":{ \"command-line\": \"drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.1,file.port=9999,file.export=parent0,node-name=replication0\"}}\n+ {\"execute\": \"x-blockdev-change\", \"arguments\":{ \"parent\": \"colo-disk0\", \"node\": \"replication0\" } }\n+\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-mirror\", \"id\": \"m0\", \"insert\": \"before\", \"position\": \"id=rew0\", \"netdev\": \"hn0\", \"queue\": \"tx\", \"outdev\": \"mirror0\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire0\", \"insert\": \"before\", \"position\": \"id=rew0\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"indev\": \"compare_out\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"filter-redirector\", \"id\": \"redire1\", \"insert\": \"before\", \"position\": \"id=rew0\", \"netdev\": \"hn0\", \"queue\": \"rx\", \"outdev\": \"compare0\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"iothread\", \"id\": \"iothread1\" } }\n+ {\"execute\": \"object-add\", \"arguments\":{ \"qom-type\": \"colo-compare\", \"id\": \"comp0\", \"primary_in\": \"compare0-0\", \"secondary_in\": \"compare1\", \"outdev\": \"compare_out0\", \"iothread\": \"iothread1\" } }\n+\n+ {\"execute\": \"migrate-set-capabilities\", \"arguments\":{ \"capabilities\": [ {\"capability\": \"x-colo\", \"state\": true } ] } }\n+ {\"execute\": \"migrate\", \"arguments\":{ \"uri\": \"tcp:127.0.0.1:9998\" } }\n+\n+TODO\n+----\n+1. Support shared storage.\n+2. Develop the heartbeat part.\n+3. Reduce checkpoint VM’s downtime while doing checkpoint.\n", "prefixes": [ "v8", "14/17" ] }