Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2194087/?format=api
{ "id": 2194087, "url": "http://patchwork.ozlabs.org/api/patches/2194087/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260206-colo_unit_test_multifd-v6-15-27779dda139d@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": "<20260206-colo_unit_test_multifd-v6-15-27779dda139d@web.de>", "list_archive_url": null, "date": "2026-02-06T20:03:13", "name": "[v6,15/18] 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/20260206-colo_unit_test_multifd-v6-15-27779dda139d@web.de/mbox/", "series": [ { "id": 491328, "url": "http://patchwork.ozlabs.org/api/series/491328/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=491328", "date": "2026-02-06T20:02:58", "name": "migration: Add COLO multifd support and COLO migration unit test", "version": 6, "mbox": "http://patchwork.ozlabs.org/series/491328/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2194087/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2194087/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=sgGdbswT;\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 4f74px0KKSz1xvD\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 07 Feb 2026 07:06:16 +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 1voS3g-0004OD-M2; Fri, 06 Feb 2026 15:04:04 -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 1voS3M-0004Fx-AH\n for qemu-devel@nongnu.org; Fri, 06 Feb 2026 15:03:46 -0500", "from mout.web.de ([212.227.15.3])\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 1voS3E-0008PD-NQ\n for qemu-devel@nongnu.org; Fri, 06 Feb 2026 15:03:42 -0500", "from [127.0.1.1] ([217.247.97.172]) by smtp.web.de (mrweb005\n [213.165.67.108]) with ESMTPSA (Nemesis) id 1M4sbr-1vn58S3JO3-0033gr; Fri, 06\n Feb 2026 21:03:27 +0100" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=web.de;\n s=s29768273; t=1770408208; x=1771013008; i=lukasstraub2@web.de;\n bh=DHQzHBoMt9UcskNHv5moJtho17FjGy9wLz2dMotNemw=;\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=sgGdbswT9yv6B9k/9emuS69saAIul+l9cbjZpbaj7J0BeVGsY1xb5qP3mfxaLRf4\n KPZbVn+CtYeAcBrAADLeed4XPrCBXNOYCQisDZlsGLLO7WnDEH0TZNwi90mOR90cp\n a5zQycTME22Kak9AVwYuJZm0L+kI/eU9Z/tr6TfDE60npx4Of79kkSWrUUqy0JuWN\n zQA9T+/+ClvrDkWWqHcGxQrQilgqdaxWkdD9SvY/m/PDe06f4yfixNmQWSKLV+94b\n 8d3IKAE7069ba/2hLn3aHv7KofSD3XCZhUVxqWWi7MrIEK73em9ZOp5VZfrJpWGVh\n YA/Z3pGu10MsgJd3YQ==", "X-UI-Sender-Class": "814a7b36-bfc1-4dae-8640-3722d8ec6cd6", "From": "Lukas Straub <lukasstraub2@web.de>", "Date": "Fri, 06 Feb 2026 21:03:13 +0100", "Subject": "[PATCH v6 15/18] Convert colo main documentation to restructuredText", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "quoted-printable", "Message-Id": "<20260206-colo_unit_test_multifd-v6-15-27779dda139d@web.de>", "References": "<20260206-colo_unit_test_multifd-v6-0-27779dda139d@web.de>", "In-Reply-To": "<20260206-colo_unit_test_multifd-v6-0-27779dda139d@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=0lpNjifnmfSQfDD2tpoOsffD4RYUt0R59Bfc2oHij+4=;\n b=owEBbQKS/ZANAwAKATWrCyicXbJYAcsmYgBphkkGlT6mmu//SL69eKPfQBaj5g5ukKR+NBk1s\n 7SETaMLRIWJAjMEAAEKAB0WIQSD+rFYoNm4+3Jij6Q1qwsonF2yWAUCaYZJBgAKCRA1qwsonF2y\n WDYGD/99doAkU1Xwq2d6gDfT1oP4bFbHkiMB1fgcxKLgWhTwSMRfQB86i5dDnjeyeBHSWlBtW8y\n TFWl0uFTCVyh0SfzeO5KfOltja3xDe76qW/O17ZGohHjef4q3BQJVL5unGlkOvw35yC6/lUwe9P\n 4+zQVcI3CdHnY6+D9h6FRwQtW1M/5qxKKDPiMsWgABq193I2uOfReZNxmeH1gGPtXCvTsoOPp1n\n LSTcuCKUHyvBX8qbFOsDURB103dcIxROecm4zTPWcwLiA/twfSLgOtSB3n7y46hO9A3fLZehSp8\n KlCsnrXn9YWOIyd3T7BX/IpCgqS/9fjf/BopH8zwTyzaWwIWPMjldFtNYxaN2DeeegM7UHpLA4b\n PJhMY/Y1U995CtldsltRk7z6NODr0rnQIxr49Zj09gy5cIKLF5Y3oasm9FEO5WzxwCMR6j702+q\n 9eMLgoYIaXVWy5SwZlCFBAA1aqU9RruTljZcA8kQowyidXTkqKpedyTWxKM7DO7vnPsTX1WfW7H\n 345Hxpvvld9ioGYHPEnA9wTpt5LNDRfcOoAdepCQc3PajtfvQjBntvKuvgNKd37jaPzs3peNlAH\n Il5xN0MIMoVStr9uPjm3r4mskjq2PUHLZ5d3cnzIHYyxbX32YYUHJVWQqHY81i1zuCNfc0WUFmY\n oHEwx0UfgVu7jjA==", "X-Developer-Key": "i=lukasstraub2@web.de; a=openpgp;\n fpr=83FAB158A0D9B8FB72628FA435AB0B289C5DB258", "X-Provags-ID": "V03:K1:oA/kQDf6UWaeTglfuhLvc7sS8BIUSL6QFMU1/nxA/ALwtqZ1bVp\n 5qp+gHOyGmhAg9n450NBgwLaxBigUn4+uiIOmQU4wM9yuFiebL/rsnRbpancPs2tW4d65Bs\n ffx25blGS/ZmkGxJOmevPNJ3VQC3DWMgPwbEw9ig7K5pxfTivlgjar2pLuEBcWwZ56dwRfe\n bDf8PAB/pkPSWKHPmewXA==", "UI-OutboundReport": "notjunk:1;M01:P0:6TiN8ezCHFc=;tkr9ExRPlQf+lzhnFadZWoHov1y\n 0lJCMOeIjf6fsuJaTuNq/jYO8+i2JIc/0m8PAd9ESDtLENqG+9n0ghxAMvDpmgK4aSYMQk2h5\n Pbqi3a9nBWJtk5FAQL9y0EzfLEIsazs4/uXOgq/RxoP1SnqsfiNViP2+HPzpUMaqNC+I4gaai\n tcDiH4rzWJrU6cbaq3eGRs42sBIscvc2GEk0pKCLXg050OHIu36a9N7jJusLpRlvCyn4m0ZGP\n MPiB9h6f8ciAkw9QqNfBmClQE1Y5YOYE6dHdoln/arlFkGegpwE4TCCaQingopDM7v2+FZV6J\n 6XHi/iMHiz2Otgi6lHwq3G5lU9qbDlALF61t6VzNNg7H0M4HRCiFiGnqrhLTCeY6yJ/8DZo5w\n CTltggIK5n3Dnj+9C8cmfjA/MOewxEDOP4f9xranVDKzNT2Ou2+WPnDJgk/rJ6cSSedqCUWwK\n v1raxHv9sbdOVNa3+FaUpt5+BTGBMi61ekAj8kkDWxE3R7r24HlzBiH6HC+TC3U1dThZYyPbX\n lyFvKNTFpGpXVdlTGIkViQNKgvwKMh+SR3a0mbSX3S6mzzOX+f7lnqYcfHOVj6iXovvsrfNJg\n iCYfruj0NoedwlnNpop8aLe6GBUH5F/pUhf6aNYo21y5DxwAVeJtuPf2PC1ls6GZTRMFPh/wY\n bmSG8yPvZwbmX8sa4ni7hMYXAgFaTMWAailIa1W3KcUT/qQ6Mnr5y+HvpOZ1+5L4iNqd5z9B0\n iInhDjib3GzlOAR7bprZ3HmvAOjpYKqV2Sx3C6ZvBK8ilzaM/DJ5fNA0FEMMdZldi96gIJOFQ\n F1/+Onqsv5z1aQmDHaZyNWGhwcLznluQtxGn1LF+I3fWbDWsM5b4uwFPpgQPdEVoLPKwDE+2K\n lmyatJhvi809YX57XEMYRFxfHwEnkMUnpFnWVDhS+1BaXaD3Ox6TKEvnLc5SDQm6XOXEeFtc/\n Qvmlr+9VHQx3artJ/lg+W1Q+r7g13Fe5ZFaS02s0Iqg/SlVX0uncDkebuMxh0FxhnPqo6ddq3\n +jR4NS0OVrMDH/AXMdBCykjJ7rtkXjG2ZHGmNjKHjcwWyN+QnxpfEYiTfn1vuRdK4kqTrVUo2\n m1HQKgeUp+UZcPDdjW6t3tn4c1nm08KhU5CmNrqq6VFjRLmqVVTtKYQHAtOvuvNGVJcGSQWzz\n SOtb7rh6VKNqgA82HBg/tIJE0sLOvEmg9o/Y2JXHoqQWtxD4G/WvGZuGv2NNyyhiIY63hsc+o\n eEUIc37FMaAO+orESpoU+ciOEk7IdahshLZ7ZDyaimXgoUfQ+1djj3C0n5Ej0CisfDn9YM+HU\n nXt3Ht8NHYyauUsXZLoa1DQkdLiRtTix5uUpp5+DRXsICfFq3tcf5S3Vjt2y7rbgdt3smSEL4\n tkpeMJQI0O+XyQKQwabMYDW+8+SNI66k9vPuVvA0kMFHrsJXKCcmxbgB66oWWqkHcMNZlhtE1\n iGeNldgGV+YnlmrRs2cC4yv/l802R3aCJlSYLrV20tbstdmIIzh4vmm1DVoZsnSYBqWklRrX0\n jGCvK2miV9JgVGDBjVL8Sq17uOws7lY8SVzMimNz6bBL4ldELcdCHraJYmzyTBJFI0AzzgXQg\n 16dqGs4K09LibO6oemkC3X01DCB5sSqbZECiMwNrWOCYhjWYnsK/ymQuVfmpHZC87sNcKCBs7\n Vm0aMxLTszj+38TZBWX8T/NvpMaq5XsukdvYZPYdYSzMoiFxX2ZHeanRxcr5wGdb/aOV1MM9M\n 6lGab4pv2zDeaiZ796HqE4FdUHBON2TXaOTGilB4MQxgt51FA2q2w0wb6ch18r4tekyQSL9pw\n /j0wSQbtBm/AcR9Fp0jZFKl226OTS65LQJf4koaUuOhYL1ec7T4Wcw0YzpJK52KP3uxiweF7v\n BZRaUP+tCISTjRQo4RW8VEJ/hwD/8YkLiAMlYBCFVRXSdyHvFmzv1RuLoNVWLD6yIA2RfyDAo\n 6DgE3aqrtXqLlvs8ZaDaOe9Pe1/GFbs2zsdFk+cWFTJZyGApEhuW9XBgeV0c1KWH24ZU4sWbb\n 9SEolz0lgGsNzbWy4YwOKwxHm409T81OhFDIeDMyuZEEQAAjq6/qMZBMMNLeov/IEWY8dhttQ\n 4mAPsQrFEe0nIMyCMN/+ASTLkmVMYW1lb70fAVTWhlqZEkY2Umgt9lqjX8+E8hbqCrSbT52K4\n u536RV2RtpHQFiD9VGK64odymtOhdTH2jI9SzS2CTBiNjTlOKRQGoWlNUbejF/7zRnn8RvQ8z\n qm2d48eJKsNAbgTdAx43f2W4bUXcd8ccaZFvueYknyV331yM/Z5VLR/4vTuByicZ//Y3118AP\n qqv5S/jIaTRWXpKD3enw+1nRhqvnLFRBmhnnh3DaIkyvQD580RmGbphqJhCg23jB5RrMWtgAk\n by8Ev1y2f+tUsHNwF1SHbPTBWam8iYveU/jnfhCzFc+omfGIft4saOnBVwWxVyeHusR90GdPm\n 4l2t3FkFb+Xmw9MTYTR187468L5m+j9b95UdN26q7PDVF01fo2Kzc90M8gd+IR8EkKYUsOwfI\n lcfOC4J8SZVkan0QAfLDVMwnP76EsggRfl9XjWD5NvjNswFgbmm0umI3WEOWy261t1I9Bo2R3\n o1saZ00G78WVz1h7b7J3mJWs4L93k381CrixYVF6hucZiGvG+Dibe3ndO+Ujxqqo8Hqc6Jps8\n fDEmDdPSEpYR8Mrd2oAuOOrRr0BffjW3+VzgQPej4Ikl/cNiWvjtcv7dD22tC4ffniAyiWYlx\n xOgIyTfKctBEOjbUL4FGVGi21mQOe3CgIJa8Q6fJejwWu4+CqUQiH/pm/CwxAnARP1TZCzJcb\n 9IuFlNqnnbKaOyLrJuLwTxsGzt+0bsX+N6hpzVYNBKGKQtQAM8ou8O8DiNcFu9dXibFGIb33u\n LdXmzen95vZgcxVA0pkfWWTEX1XmRCnuAFfJ6c0un7wznkMkArEgt0SXEqWKSuuoRLKhHDIpp\n JV7Dvma3iRpkA4oCkoCuImjsnQUK22iZ5JIeSBvvBW+JG/xQKL5HKMuL2BqDh5BglV/gePgcG\n rWL3hpjLZ2Yj2W4MK0kwT17XiAE8Pn5SFrL8p1EZk1IrI9GHm7g2NlMcSMGMJBI/qGn1vYbv2\n 4MeWuIvlqPf7o3csmozqBHr/Ez4Ix+JuVeHzarn5EZgzktV8HKq64IHvF1Pjt8iNKwvB3ozB5\n jRUUW2DC/UbFxfmTwwG4fl7YFpAchy/yKE3BsQZK5I+v4xxQ+TlpVpeqytnxcbFbGqvozTW5s\n +RzRMHk+SRy+GTJQHWP6qEUxyHaSXX7RGsl3KTBplVuS9VgW1ESU5HHF+hDaUp9XNed9qqqoR\n dAIePf+1uokeM+kbLy4P/+BMicZL2OjG5CQVbX3Xtj+EKFVydhVC+GxOv2hNzbm6Pe6PNIyza\n Xg1al3vP6iRA3RqpisPHEa/+Ahe/X8ABucej8H3yRsVDaraC5VAZWDECeSiSludZKEWM3P1qx\n 7wA+yIEDrpcaHUNFNXBPhdaoFGAuAlhaVrKrjzL/geM32NYXbGYC14huv3rZA04VyGqZLqZBb\n W9opooDxTX8W+5GZh8d5oRV42gLDmNx31rjnrQnETsPYglVEFznI7AyurAUbkewMn0m1/4U2O\n uqTMJ5fgw0o3cMm1aXMT5st6Y6INol2H5YserUn/DuCgLud3Io+JwH4qEGiv7e6YSfQzjEVle\n eY3dZVcDSFLe6RMH2KNMpxHziUvpP+G6w6S5Y3AKSmYPjj60H0J/QfyqkLI+YVq8zxNHFNSs8\n OV5X2pLpl5vp3is7WNThiIFPLOOHjtstGDzxfA4jk43PPvo5Pj7eniQeH2ikebMytaXIJi9qj\n 4t3bw6YLuSg5L8rH0qWgD+P8Hjg2d9fHxUneHU6mw0H+bQN4ryMDfSa8AevgHfKK1CXtwAoMq\n GKDMUIm+VVmxS4mL1BvOD2qg5wGFAb265B0dM91Kiv4WKah+ST/WkAPL21sIDgOHjQ1Gd6wGk\n f70bMpk3fz+uaC23mM/YYji08aivX+DeYQT30S4sKSkCIzM4TJeoi+Gjz5Lx5XC5MQ9c5uUmy\n an1zIJGNjM3Ud+CkWjW1Ka6BQs9I0gNrWnhDaffVUn12Ta39fK+hcM/sV/4mY0VeWNgL0AvN9\n csiLlGpGOytWlkmtXRSpGKOSVaWth8bipd1Kfzu0Hcgx8nR4FbjgOGBfKshHtWQTyECEGQ9Hn\n 41DRJjRB7oPUuLlFIA6mccTOoAle23corsdlvpuS05K8m4Id4BfjlBlY2GsYCxJyWE49q27Qh\n p2mjnUFwvB7qxAOoNl9OpBBOzcVB63nihiSFY6Aitw7zdoCDPMr28V5X6PuJdQ7rqKQmX+Vj6\n gHQIaU8q3SN8ItwTdDkzeLdny55BXODtbqbfGhv6mFRzqAu+JUWeTgnre7qj1uryDtK+Y6tYg\n 7DIKJGM+Ksmk/GGuOtutzs0jTpOsn9kyH1UvpJUDfE1U1HZo9Bbj0fJs8Otz1bxw6R0ybepRa\n dMqyMVC+Nzz4nGNkpDgp8cpzjPEJhv/HYFArf6xHMwTeFU5II6HNAEUrYvSS0J0raHpsvyCyV\n goumOYqwil3DvH36Yc8yVpIffO87qjTE/aZjVkK/51f1TkH1Gc5iWQqmpQU9SSp/+G4jNN47t\n JaTG+kjpgKJNqHphZ+AVVzmRRYXeRiDaF9xADHxYcBufOXsSUB9gtv1SwGeoxOer9dKGj5X4Q\n iOruis7OGNG29KZvnqV4sYzxE2pQ2AiFP7v12ffCJaxbFIooePZzcjVYASfxuzZsMyRqj2WgU\n b512ZpSyOanCaC3tTcH07OEi0kBWxNbb/Gj/xe/BzpaZAHsu8/2ThTmQeJbDUIAAP6SOer8oS\n rQT3tDN0P8ixxeQw5pqhmPbG0yR/U7YPsm82pMI+U2JrnTLgd3lFMjEsskxh9WTym37J+bwvF\n cOaOZyjP5gk+O0bOqgnDiAuE1IZT2Qopg0wOBLzVQjXl8VxM5R8vSkvFYHLHSSLg+115nVNYG\n Cd7Ng8bssqexYheaGn1knTQ5LKUsAQs5a4RWUebepnw7xK0YOY+NjV8h1FkBZQhlf4uZ0xqJw\n 991RRupq9oFbzLkEIOvn2lwX5yOblnlwuKuhfxEZg6dYkbNwpI6hv2ajKMHrURG/wxA2jej9D\n N75lunxv6zTG+QOUZHpXBuaCfeAR06Jdkcr3UniNxiaGiIMBnHgZcJqckPg5/MAXoET3KkqwE\n Cy6avapjW5HmeBP7T1OoflQZ6YWYQ", "Received-SPF": "pass client-ip=212.227.15.3; 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_H3=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 8e63e0a08fc7417036986f27c2d910eb99d8a96a..f645590b8b940919bdc84ad585ee493f5452fc20 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -3855,7 +3855,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": [ "v6", "15/18" ] }