From nobody Tue Jun 9 21:16:38 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) client-ip=38.145.34.151; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; arc=pass (i=1 dmarc=pass fromdomain=nutanix.com); dmarc=pass(p=none dis=none) header.from=nutanix.com ARC-Seal: i=2; a=rsa-sha256; t=1778669579; cv=pass; d=zohomail.com; s=zohoarc; b=Qc7UaU/FNl/M8zBZjvUhvL0bZWqtm2lxYyMMYuuf2DnuRe9QQtwysAHbbh58I9DKZFIwU8MtUnsHFVKFTaSvSaS0IkKlD1lbf735d5EZH45IglqAuQLA2N1NjRExUYeefY3n+NttLZn5PDrRb0eKPuIZRX7GSO2etxMDbtAartw= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778669579; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=pD16qxZXtv58n/FZ/OwlHYzWuvtcGw0hWZf8JlSSm88=; b=XH3s3Wg45Ylq4NIB2ccg8aqo2ZQrlI6/n6qZzgk4ikKf4OFGw3q2AGGrlC/x6mFp7lygBiG8MenUQsPsKsx9mABe2OVgKbzPRtvje6+TUSSPoqNzNNwIoURLjojJoPRXPqjZ6FHyDzVqz9ZFJgyKPkznA5nfFcOL9Q5nGsZ9k5E= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; arc=pass (i=1 dmarc=pass fromdomain=nutanix.com); dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 1778669579152231.53971011980923; Wed, 13 May 2026 03:52:59 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id CC1A841874; Wed, 13 May 2026 06:52:57 -0400 (EDT) Received: from [172.19.199.9] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id D281541A4F; Wed, 13 May 2026 06:50:06 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 6276E41862; Wed, 13 May 2026 06:49:57 -0400 (EDT) Received: from mx0a-002c1b01.pphosted.com (mx0a-002c1b01.pphosted.com [148.163.151.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id EAB51417E9 for ; Wed, 13 May 2026 06:49:52 -0400 (EDT) Received: from pps.filterd (m0127839.ppops.net [127.0.0.1]) by mx0a-002c1b01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64CNxTFr2530741 for ; Wed, 13 May 2026 03:22:28 -0700 Received: from bl0pr03cu003.outbound.protection.outlook.com (mail-eastusazon11022099.outbound.protection.outlook.com [52.101.53.99]) by mx0a-002c1b01.pphosted.com (PPS) with ESMTPS id 4e3nvdn84u-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT) for ; Wed, 13 May 2026 03:22:28 -0700 (PDT) Received: from DM5PR02MB3831.namprd02.prod.outlook.com (2603:10b6:4:b4::21) by CY8PR02MB9566.namprd02.prod.outlook.com (2603:10b6:930:76::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9891.23; Wed, 13 May 2026 10:22:25 +0000 Received: from DM5PR02MB3831.namprd02.prod.outlook.com ([fe80::b0ba:9ac1:4aed:805d]) by DM5PR02MB3831.namprd02.prod.outlook.com ([fe80::b0ba:9ac1:4aed:805d%6]) with mapi id 15.21.0025.012; Wed, 13 May 2026 10:22:25 +0000 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.9 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=4.0.1 X-Greylist: delayed 1643 seconds by postgrey-1.37 at lists.libvirt.org; Wed, 13 May 2026 06:49:52 EDT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nutanix.com; h= content-transfer-encoding:content-type:date:from:message-id :mime-version:subject:to; s=proofpoint20171006; bh=pD16qxZXtv58n /FZ/OwlHYzWuvtcGw0hWZf8JlSSm88=; b=Z5KzpwhENIUGpzFWYKdZbufrbG2Au zBefp9CsD65s+T/7OuSh8Tnoljc+w2OxS2NqwzUCjqMdl0sIKFqsOR1EfW3Wrdiv fHCIMStlxUkFy4Mboo3ROHoMMux3D+/sYNv2p8G7q2EQ1JfrzG0/Ds6D6/EfngW5 UOAZqZqBIHVOPBDr2qs1C0p+ODb1OBzshVGGLynstbQtHy6RQFd+DT6u4W7z+0jK Q67rmMAUnpnYMHkatLv/MxbWe7pB/ZIIxUpvC8Xx+lUEcKcdB1L155jRqkHMsPXA kuDu0GE2qLo4L1EpgvDowWFQSDenaRG2LQmtp3ACZVqgv0/GwZ/tiwHxg== ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=jUFrNwcyopaap6ga94b5C/HAi300NOqzREgZbZrIGYD2Xd9Qd64bpyNbymgVkruUCnUSeePn66wLNwDwLEFReUdwXlYZd9R8e6O3z6qbrzsk4eD30357zPPT8Mo4ZIIUsUO8FfUzn47tH3KBKJkYnHSSiisncucarld3cW/yYQsLKMnphhOUX33/trNoIEUoRE0TM5Q6+4oXkXe8Vt6JkcGlkAyNyfJxm+lHiIBR9Z9YnfkXojotOGuB5ksWlKYtLwPTv1rz1y+2Hyim9+VXElaTUvFSDGSvuIDAyrbwBp/btzua+8O1DdlUSFjLaOycrYE6efLNAZKC6sYBdkXx4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=pD16qxZXtv58n/FZ/OwlHYzWuvtcGw0hWZf8JlSSm88=; b=K22SVv1q6EUU7gqaVIZr6UzrikPuO2hKesSV2a2rYDcf3Tjm9+NRIKVQhV4sLCOXisXseqsJcYZZSeanouVg3KTGEqrBsw0kUS6cE04kcjjPfQsnEwb9MUcF5TwzeB9fgkXHOcBb/3vXJR5kCQfJrNJ/8OwlH2EVkULRz7JtbPRYKJzzgduRpIEh3EaHmqFb/bMNIsifgyc5O84GsmKYIgkSpG7HFO5RzRxOCAHCWhLRTF/+yXwnr6rF5yJNtPtbJezG3KuDaNOLvbFFHnCOlRUparCSfnYJbY/YMxP3te7ZmCeoprvfmtbb34spMM+701uHVgpLAUSQ4Wyt3vYs1w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nutanix.com; dmarc=pass action=none header.from=nutanix.com; dkim=pass header.d=nutanix.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nutanix.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=pD16qxZXtv58n/FZ/OwlHYzWuvtcGw0hWZf8JlSSm88=; b=uJ71u7qCEjEy5eoOxh66980tH+7rFv1VYJua4fVN7Zl8c2Oxz0PB2+dNeg7vEg2yoW8JZyh55Ts7Ey1wuXGS8hzHzBlge+d8vEhK3Kl8jjWVFJ88cqwa9xKLrfB0HESUA146F51chqFyEvq9gexyMEYd40ljj0mcpMFXefBDca7CbP48FO/V1v4cK0i+mvjPfHR5hK2Hat3TvczT9DEQU7y/VFcT1wpkTWl4hRNloy5X0tu4MLgEu+PlkOPEXwmOrzodk4AqS21xMn9GVxhUKPgy2j50TsUrXcaAXCylyhJNPnfMvguPrJbsyDalFjyk4bVzO9ip+3GFp1oUNy4vdg== From: Lucas Kornicki To: devel@lists.libvirt.org Subject: [PATCH] qemu: Introduce VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE Date: Wed, 13 May 2026 12:20:31 +0200 Message-ID: <20260513102126.1848120-1-lucas.kornicki@nutanix.com> X-Mailer: git-send-email 2.43.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: AM0PR10CA0030.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:208:17c::40) To DM5PR02MB3831.namprd02.prod.outlook.com (2603:10b6:4:b4::21) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM5PR02MB3831:EE_|CY8PR02MB9566:EE_ X-MS-Office365-Filtering-Correlation-Id: 6bcfad25-e048-4ff3-cf42-08deb0d986a9 x-proofpoint-crosstenant: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|3023799003|56012099003|18002099003; X-Microsoft-Antispam-Message-Info: WiKGGIGMoyOr81SP5OPNjA5mkqjNN4olgMDtZGEgj/ZlxVr/JzBxR0aNlVvggyjAYBqu4EeFizQ8kytd2UHlJbPf0QldSugP7jFXVsLQhcrXCEmSmEz8moDGSr1ZrTJNp5wyRvI4EpVj+MCSLcOnDHHJ+Fo99qtTZknUcFMGKnLxX7nMX3eSYrRtNRXwrGmMhoPGT+MP2LUtrf9wY0WadLn0D/uUfnrds77pLEqaa6RYJFDgULDgdc8oVVdFOVnhwOrb3p/4L8C/1KI9Gk3DULhHTgm8cM8CF5BDnQESdXM7ihJs465eWEgAJv5OwprPWrdUq8eyXXhqmTh6OXKMfHHV/JC9NTcWkfYxJYVF5450v2RFAxCXk54BTfBsV/weYdtlcJxsk/u1ZZ+AZshbxCeqNhghi6P4WfGGyi7BVo8gWC7iJFepE9eiFjvBE35FP6Z9n+P2SDfq2dkkCNZ59rvJv+17VcepZ1T7OG59HC2JeoiHZBXFJi9ZeZQ9w/+hzD4EKvE8qkrta7CGookg8W5jxjtVvgvl2Ymd6LwfhqgjJ00kcPbW2EyV2qr58MxV6C41F8MByCutE9aIaeknLQvhESRyM/m6xzcXXC3gG08KIi1AkaOIVVbdiLYdtsL8WSgw5rxiz2e+sCLsWwB/jdmcVSd3Pj6K8c5X5yvWDOB8SIxSRJm2aDNZ+u2K8mhm X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM5PR02MB3831.namprd02.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(376014)(366016)(1800799024)(3023799003)(56012099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?h5B1CsyW6axi5e5ogS6bLOHRpZsEbh+8vzIKyDO10cIJ3hnezk+AoKErhUxW?= =?us-ascii?Q?CqzG0cl2yTAE30drrocNp/+yu41LP9kKm/q1pzSrfOPlLt8gaUeU5AByb1Dv?= =?us-ascii?Q?9xRV/Kx2FkM9ElxlJ8BWo+KhNjnxfuQMiacC39hJLqb88Z7IRtp31iEERFsG?= =?us-ascii?Q?U+6rZLnXzUxIPwdB6Ub0Pvini0X7OG/hJoZ20hAfMDY5h7HhZwVcrOIgZ7PF?= =?us-ascii?Q?ZC+sx1YABEy5URPnO4hGnaU9RKgKPwRYZf0NBEprRlU8ayNBjj9MBz0Iz2lk?= =?us-ascii?Q?HsjNey8Wi4c2yNqML8TlcNtCf7vTc3k7c6e0UZ+Mi51kafPrwxV1HAAGBf4q?= =?us-ascii?Q?2bRyU7VeSciIidKF8hjPcrnx7gzPy95WOoDOjE/PhxfaRttpNjGHHglxpmLD?= =?us-ascii?Q?KAKqVf4A+l6y0NzFiS/4C/7dR/f/xhvCIS1YaGcXV9qtCdzcWx1Sl0sTqX7C?= =?us-ascii?Q?YwBEvaj35bNOkvnrnzQM2diqkJ0cQJq3XMSeNxyxk1U3EUmIqX2URcHpsqhv?= =?us-ascii?Q?YqBU35DGRIF1rRK7iY2fP8ojduPrN2IwCpCDKLc+fuh2mMBHmVVTzvWEC5xG?= =?us-ascii?Q?foj4MnEwf0mgTEQPBurB9ssSKL1ltxiv6ZWaSTUrnO+knopvGQcfD/7jFuTz?= =?us-ascii?Q?MWqm7NvAK9gM8+UR0fibf2m5pOjRlhlrXWQE0KHHnJrSVqhwjxK6TbH02MlJ?= =?us-ascii?Q?8vJdmCighYfwuFuXiw3kugFk8oRKaORdYLqpf58Agjdr8m9h67h0hcTFzs/S?= =?us-ascii?Q?w5jaugEJMNBeaDdWIJV4QJKvSzBuvwsqCQvJcmvz4nMNsd/ErmylSe5mLgVo?= =?us-ascii?Q?vq9s1oa1bCXAab/6f6iWp4bWkItW9ZjMEe5ZxgEndQ/OnoT8mZJyM9T0a4us?= =?us-ascii?Q?bINvavv9HIeGbHLXIo/NYEt/BHLlfppfgDvQ9vraklVbkPTbmm7Uub6InDvM?= =?us-ascii?Q?fto8ksDMEpbA6U+7As0yZaxLlbRTiNnwa+XXrfGl5pDvKmuaes8HV/xqoUr+?= =?us-ascii?Q?RA/ofo3ZR4m58w252jXIUAommN0N29n1uj1+/SUVTeeh2ThvwPGZSMaRFVDk?= =?us-ascii?Q?bc5MpA1uXzKZGmw/zxGbNFRzcD4vaqLIOgIR1OwmRrG949gUYjTXo6hJbMkn?= =?us-ascii?Q?SabhpWf2mPVeY2/dIzFc/I+WB20P/xQF1TxvnOPgo706eINXNghn0KsC8pev?= =?us-ascii?Q?2jMyUUNFERNSZJCF9bfZkNZ+4IoQPE/xnm3gSXdWNLEEmfgpN6fYGm0MJmLn?= =?us-ascii?Q?B7tCMkWoDhQLOzFkZ5xeqGoMaZIC05g4WLkOyL01wwaD4IOWYn751OGKIVuC?= =?us-ascii?Q?6jyCmsOQ/84jHlk5gU1Yrxm+JGOp7LmYkeo5cIoxbseRiwuXleplL2+DTOP0?= =?us-ascii?Q?jeRmZQa/iIi9uru6nISOlk7Ef+U+6udsK5qJNCf6HKlzYtQ6IQA5EUop/DRI?= =?us-ascii?Q?78lc1a9goBiIJYhI3mNNfJM0UoGPobqdjhIZMA+5AOmvqv9bgsQGsGMAhTOm?= =?us-ascii?Q?Z5eoEiD6+uEQPTWKpoKam5ZdG58AzAQlQgal2HCaHl2R2DUoGKVSTM4h+sSW?= =?us-ascii?Q?nz2MrZKSipovdLEaS9hH2jViavjA1L6rvk9ByyAJW2V8B+XjRUe+IfrdHScB?= =?us-ascii?Q?s+2twHqgqv+HV0qZYGqpgME7TzxVWPJ18IrUjo6Qa7kam/5T5LddOcKC6rtn?= =?us-ascii?Q?aa9RgLr+dBHXR/oY3vkt/y3TQTi6WxxdYVkkT+8tdAoSHahQuv3LGl8fWt3Q?= =?us-ascii?Q?DfCjV6m4EcHX3E0f6lfR5RmEnimN+h0=3D?= X-Exchange-RoutingPolicyChecked: DHBvpcH5R8YrpxeeMPNKD60lKMDRwxLWn0kFOxi55S2XF/jouEBUmMmHzds6uizqJ9x0kF9QiT6eCy2mxL8tPr0wUxo72Z5gWiBO3tgHvGodBoykYunzEMMJlk9lq9jlkym+yo2olPop0epU45E0A+UQgpL5NbD8Qe4QYEAS/M4RK6MXvBLZotdLzhoVQnydA6SUCL9Jw8aVcLn9voRqv7XsaQYXj4BhEBJn6IXlyazlZGsa7JruAx7vJPfCKAgipqIawZ9kliqqfkwozGhaXVI5+0V2B3+M+mysoeBZG+JQCTxaaB2Fq2sdm1CnvrrFgkjMp+brhoh/BmFRV0F5HQ== X-OriginatorOrg: nutanix.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6bcfad25-e048-4ff3-cf42-08deb0d986a9 X-MS-Exchange-CrossTenant-AuthSource: DM5PR02MB3831.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 May 2026 10:22:25.1314 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bb047546-786f-4de1-bd75-24e5b6f79043 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 5sMygjf3xHvHRIfez0GwI+jkpHAKiD7dkaxdMKAPubh19ujCrqrmEwxqdKNpUXWFsywsPLAG4Wf63ojosYGSrlaCsvol63Eqx6P7rqiyKNU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY8PR02MB9566 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTEzMDEwOCBTYWx0ZWRfX1GGlU+R4ml2d Ok378/IwnjwiNybYx4MahSu3Sgc9IyZAz7SYbHP9rwxTIP8Ttzyt1HsP/PtOmmafw2pd9qWRpHK +h7IS3o0YwXzGbKDxFEpwYach+5xPeDgGiLc+o7A+Fq2NXSKbK/hFuT2k7kKTmXdDJ46Cv8aqoS biGxAbD3TwUrAAqmdJW1akIzfdR1QldIJZ0Z812pjhcyxKvHXTYLgqZ2yNnK4oWQxUkc2bY7bN8 EFeNYl5SItFxCKfvXlTCLUlgNWuAkMYXwwtLiJGUsfiwdSw7p89nyf95bDdShgdWD/bmtfzfkrk zoxsZYdjt/xhrFnwCPDtKO/enhC1N83+/NrC7b+/PossUtYzHfuM+usqVycSIvlr2tnZZZBXTJQ Is5z1Vdo+zlL02QRexo5/8siloXM7Jyu0XPnSrvquGOrRir1o0xFqnNTSP72caXknjWoLTZFsGt l0jUCFU9/8F3aIbQhnw== X-Proofpoint-GUID: 72JFajjfRrJkGTz7maAxrUoL7fkMvsNl X-Proofpoint-ORIG-GUID: 72JFajjfRrJkGTz7maAxrUoL7fkMvsNl X-Authority-Analysis: v=2.4 cv=FrA1OWrq c=1 sm=1 tr=0 ts=6a0450e4 cx=c_pps a=qlJ2pVgRLkKXdQ82XtY8Hg==:117 a=6eWqkTHjU83fiwn7nKZWdM+Sl24=:19 a=z/mQ4Ysz8XfWz/Q5cLBRGdckG28=:19 a=lCpzRmAYbLLaTzLvsPZ7Mbvzbb8=:19 a=xqWC_Br6kY4A:10 a=NGcC8JguVDcA:10 a=0kUYKlekyDsA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VofLwUrZ8Iiv6rRUPXIb:22 a=y4UcunY2MAxhM4LwGdWI:22 a=pGLkceISAAAA:8 a=64Cc0HZtAAAA:8 a=x2Zofan_TWsQHipuppAA:9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-11_05,2026-05-08_02,2025-10-01_01 X-Proofpoint-Spam-Reason: safe Message-ID-Hash: 7HU4BTHC3I5S5LE5ZSZNPLHEM5PB4KQM X-Message-ID-Hash: 7HU4BTHC3I5S5LE5ZSZNPLHEM5PB4KQM X-MailFrom: lucas.kornicki@nutanix.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: pass (identity @nutanix.com) X-ZM-MESSAGEID: 1778669580451158500 Content-Type: text/plain; charset="utf-8" Add a generic domain event that fires when libvirt detects a state change on any virtio-serial channel of a domain (connected / disconnected). The existing VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE event is restricted to the QEMU guest agent channel ("org.qemu.guest_agent.0"), making it impossible for management applications to observe lifecycle transitions of other channels (custom guest agents, SPICE, etc.) without polling the domain XML status file. The new event is emitted for every virtio-serial channel, including the guest agent channel, and carries the affected channels name. The hypervisor must support virtio-serial port state notifications (e.g. QEMU's VSERPORT_CHANGE event) for the event to be delivered. Forward-port of the v2 series originally posted to libvirt-devel in 2016 by Matt Broadstone . Signed-off-by: Lucas Kornicki --- examples/c/misc/event-test.c | 57 +++++++++++++++++ include/libvirt/libvirt-domain.h | 65 ++++++++++++++++++++ src/conf/domain_event.c | 95 +++++++++++++++++++++++++++++ src/conf/domain_event.h | 12 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 8 +++ src/qemu/qemu_process.c | 17 ++++-- src/remote/remote_daemon_dispatch.c | 34 +++++++++++ src/remote/remote_driver.c | 34 +++++++++++ src/remote/remote_protocol.x | 16 ++++- src/remote_protocol-structs | 8 +++ tools/virsh-domain-event.c | 35 +++++++++++ 12 files changed, 377 insertions(+), 6 deletions(-) diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c index 2ce82ca9e0..cb22c6b619 100644 --- a/examples/c/misc/event-test.c +++ b/examples/c/misc/event-test.c @@ -353,6 +353,45 @@ guestAgentLifecycleEventReasonToString(int event) return "unknown"; } =20 + +static const char * +guestChannelLifecycleEventStateToString(int event) +{ + switch ((virConnectDomainEventChannelLifecycleState) event) { + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_DISCONNECTED: + return "Disconnected"; + + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_CONNECTED: + return "Connected"; + + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST: + break; + } + + return "unknown"; +} + + +static const char * +guestChannelLifecycleEventReasonToString(int event) +{ + switch ((virConnectDomainEventChannelLifecycleReason) event) { + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_UNKNOWN: + return "Unknown"; + + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOMAIN_STARTED: + return "Domain started"; + + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL: + return "Channel event"; + + case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST: + break; + } + + return "unknown"; +} + static const char * storagePoolEventToString(int event) { @@ -869,6 +908,23 @@ myDomainEventAgentLifecycleCallback(virConnectPtr conn= G_GNUC_UNUSED, } =20 =20 +static int +myDomainEventChannelLifecycleCallback(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + const char *channelName, + int state, + int reason, + void *opaque G_GNUC_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) guest channel(%s) state changed: %s re= ason: %s\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), channelNa= me, + guestChannelLifecycleEventStateToString(state), + guestChannelLifecycleEventReasonToString(reason)); + + return 0; +} + + static int myDomainEventDeviceAddedCallback(virConnectPtr conn G_GNUC_UNUSED, virDomainPtr dom, @@ -1183,6 +1239,7 @@ struct domainEventData domainEvents[] =3D { DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFa= ilureCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE, myDomainEv= entMemoryDeviceSizeChangeCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_NIC_MAC_CHANGE, myDomainEventNICMACCh= angeCallback), + DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE, myDomainEventChann= elLifecycleCallback), }; =20 struct storagePoolEventData { diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-dom= ain.h index 4a8e3114b3..fc0fc30e83 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -7568,6 +7568,70 @@ typedef void (*virConnectDomainEventNICMACChangeCall= back)(virConnectPtr conn, const char *newM= AC, void *opaque); =20 + +/** + * virConnectDomainEventChannelLifecycleState: + * + * Since: 12.3.0 + */ +typedef enum { + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_CONNECTED =3D 1, /* c= hannel connected (Since: 12.3.0) */ + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_DISCONNECTED =3D 2, /= * channel disconnected (Since: 12.3.0) */ + +# ifdef VIR_ENUM_SENTINELS + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST /* (Since: 12.3.= 0) */ +# endif +} virConnectDomainEventChannelLifecycleState; + +/** + * virConnectDomainEventChannelLifecycleReason: + * + * The reason values are intentionally numerically aligned with + * virConnectDomainEventAgentLifecycleReason so that the qemu driver + * can pass the same int through both events. + * + * Since: 12.3.0 + */ +typedef enum { + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_UNKNOWN =3D 0, /* un= known state change reason (Since: 12.3.0) */ + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOMAIN_STARTED =3D 1= , /* state changed due to domain start (Since: 12.3.0) */ + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL =3D 2, /* ch= annel state changed (Since: 12.3.0) */ + +# ifdef VIR_ENUM_SENTINELS + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST /* (Since: 12.3= .0) */ +# endif +} virConnectDomainEventChannelLifecycleReason; + +/** + * virConnectDomainEventChannelLifecycleCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @channelName: the name of the channel on which the event occurred + * @state: new state of the guest channel, one of virConnectDomainEventCha= nnelLifecycleState + * @reason: reason for state change, one of virConnectDomainEventChannelLi= fecycleReason + * @opaque: application specified data + * + * This callback occurs when libvirt detects a change in the state of a gu= est + * virtio-serial channel. Unlike VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE which= is + * tied to the QEMU guest agent channel ("org.qemu.guest_agent.0"), this e= vent + * is emitted for every virtio-serial channel attached to the domain, + * including the guest agent channel. + * + * The hypervisor must support virtio-serial port state notifications for = the + * event to be delivered. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE with virConnectDomainEventRegiste= rAny() + * + * Since: 12.3.0 + */ +typedef void (*virConnectDomainEventChannelLifecycleCallback)(virConnectPt= r conn, + virDomainPtr= dom, + const char *= channelName, + int state, + int reason, + void *opaque= ); + /** * VIR_DOMAIN_EVENT_CALLBACK: * @@ -7617,6 +7681,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE =3D 25, /* virConnectDomainEventMe= moryFailureCallback (Since: 6.9.0) */ VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE =3D 26, /* virConnectDom= ainEventMemoryDeviceSizeChangeCallback (Since: 7.9.0) */ VIR_DOMAIN_EVENT_ID_NIC_MAC_CHANGE =3D 27, /* virConnectDomainEventNIC= MACChangeCallback (Since: 11.2.0) */ + VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE =3D 28, /* virConnectDomainEvent= ChannelLifecycleCallback (Since: 12.3.0) */ =20 # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 88087bad4f..38ab902aa2 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -58,6 +58,7 @@ static virClass *virDomainEventBlockThresholdClass; static virClass *virDomainEventMemoryFailureClass; static virClass *virDomainEventMemoryDeviceSizeChangeClass; static virClass *virDomainEventNICMACChangeClass; +static virClass *virDomainEventChannelLifecycleClass; =20 static void virDomainEventDispose(void *obj); static void virDomainEventLifecycleDispose(void *obj); @@ -83,6 +84,7 @@ static void virDomainEventBlockThresholdDispose(void *obj= ); static void virDomainEventMemoryFailureDispose(void *obj); static void virDomainEventMemoryDeviceSizeChangeDispose(void *obj); static void virDomainEventNICMACChangeDispose(void *obj); +static void virDomainEventChannelLifecycleDispose(void *obj); =20 static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -296,6 +298,21 @@ struct _virDomainEventNICMACChange { }; typedef struct _virDomainEventNICMACChange virDomainEventNICMACChange; =20 +struct _virDomainEventChannelLifecycle { + virDomainEvent parent; + + char *channelName; + int state; + int reason; +}; +typedef struct _virDomainEventChannelLifecycle virDomainEventChannelLifecy= cle; + +/* Make sure the AGENT and CHANNEL lifecycle enums stay in sync with each = other. */ +G_STATIC_ASSERT((int)VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_DOMAI= N_STARTED =3D=3D + (int)VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOM= AIN_STARTED); +G_STATIC_ASSERT((int)VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANN= EL =3D=3D + (int)VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHA= NNEL); + static int virDomainEventsOnceInit(void) { @@ -347,6 +364,8 @@ virDomainEventsOnceInit(void) return -1; if (!VIR_CLASS_NEW(virDomainEventNICMACChange, virDomainEventClass)) return -1; + if (!VIR_CLASS_NEW(virDomainEventChannelLifecycle, virDomainEventClass= )) + return -1; return 0; } =20 @@ -582,6 +601,14 @@ virDomainEventNICMACChangeDispose(void *obj) g_free(event->newMAC); } =20 +static void +virDomainEventChannelLifecycleDispose(void *obj) +{ + virDomainEventChannelLifecycle *event =3D obj; + + g_free(event->channelName); +} + static void * virDomainEventNew(virClass *klass, int eventID, @@ -1812,6 +1839,61 @@ virDomainEventNICMACChangeNewFromDom(virDomainPtr do= m, =20 } =20 + +static virObjectEvent * +virDomainEventChannelLifecycleNew(int id, + const char *name, + const unsigned char *uuid, + const char *channelName, + int state, + int reason) +{ + virDomainEventChannelLifecycle *ev; + + if (virDomainEventsInitialize() < 0) + return NULL; + + if (!(ev =3D virDomainEventNew(virDomainEventChannelLifecycleClass, + VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE, + id, name, uuid))) + return NULL; + + ev->channelName =3D g_strdup(channelName); + ev->state =3D state; + ev->reason =3D reason; + + return (virObjectEvent *)ev; +} + + +virObjectEvent * +virDomainEventChannelLifecycleNewFromObj(virDomainObj *obj, + const char *channelName, + int state, + int reason) +{ + return virDomainEventChannelLifecycleNew(obj->def->id, + obj->def->name, + obj->def->uuid, + channelName, + state, + reason); +} + +virObjectEvent * +virDomainEventChannelLifecycleNewFromDom(virDomainPtr dom, + const char *channelName, + int state, + int reason) +{ + return virDomainEventChannelLifecycleNew(dom->id, + dom->name, + dom->uuid, + channelName, + state, + reason); +} + static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, virObjectEvent *event, @@ -2134,6 +2216,19 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, goto cleanup; } =20 + case VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE: + { + virDomainEventChannelLifecycle *channelLifecycleEvent; + + channelLifecycleEvent =3D (virDomainEventChannelLifecycle *)ev= ent; + ((virConnectDomainEventChannelLifecycleCallback)cb)(conn, dom, + channelLif= ecycleEvent->channelName, + channelLif= ecycleEvent->state, + channelLif= ecycleEvent->reason, + cbopaque); + goto cleanup; + } + case VIR_DOMAIN_EVENT_ID_LAST: break; } diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index f31cfb9e42..8764c93902 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -289,6 +289,18 @@ virDomainEventNICMACChangeNewFromDom(virDomainPtr dom, const char *oldMAC, const char *newMAC); =20 +virObjectEvent * +virDomainEventChannelLifecycleNewFromObj(virDomainObj *obj, + const char *channelName, + int state, + int reason); + +virObjectEvent * +virDomainEventChannelLifecycleNewFromDom(virDomainPtr dom, + const char *channelName, + int state, + int reason); + int virDomainEventStateRegister(virConnectPtr conn, virObjectEventState *state, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cf0e71cc6a..7d221f08c4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -761,6 +761,8 @@ virDomainEventBlockJobNewFromDom; virDomainEventBlockJobNewFromObj; virDomainEventBlockThresholdNewFromDom; virDomainEventBlockThresholdNewFromObj; +virDomainEventChannelLifecycleNewFromDom; +virDomainEventChannelLifecycleNewFromObj; virDomainEventControlErrorNewFromDom; virDomainEventControlErrorNewFromObj; virDomainEventDeviceAddedNewFromDom; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 529e9fe3be..dcb664834a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3834,6 +3834,14 @@ processSerialChangedEvent(virQEMUDriver *driver, =20 qemuDomainSaveStatus(vm); =20 + /* queue the generic channel-lifecycle event before the agent-specific= one + * because the latter might goto endjob if qemuConnectAgent() fails */ + virObjectEventStateQueue(driver->domainEventState, + virDomainEventChannelLifecycleNewFromObj(vm, + dev.= data.chr->target.name, + news= tate, + VIR_= CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL)); + if (STREQ_NULLABLE(dev.data.chr->target.name, "org.qemu.guest_agent.0"= )) { if (newstate =3D=3D VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED) { if (qemuConnectAgent(driver, vm) < 0) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index a6d33f6746..ba1d17d91a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2270,11 +2270,18 @@ qemuProcessRefreshChannelVirtioState(virQEMUDriver = *driver, !entry->state) continue; =20 - if (entry->state !=3D VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT && - STREQ_NULLABLE(chr->target.name, "org.qemu.guest_agent.0")= && - (event =3D virDomainEventAgentLifecycleNewFromObj(vm, entr= y->state, - agentReaso= n))) - virObjectEventStateQueue(driver->domainEventState, event); + if (entry->state !=3D VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT) { + if (STREQ_NULLABLE(chr->target.name, "org.qemu.guest_agent= .0") && + (event =3D virDomainEventAgentLifecycleNewFromObj(vm, = entry->state, + agentR= eason))) + virObjectEventStateQueue(driver->domainEventState, eve= nt); + + virObjectEventStateQueue(driver->domainEventState, + virDomainEventChannelLifecycleNew= FromObj(vm, + = chr->target.name, + = entry->state, + = agentReason)); + } =20 chr->state =3D entry->state; } diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon= _dispatch.c index 7e74ff063f..ac0440eb0b 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -1354,6 +1354,39 @@ remoteRelayDomainEventNICMACChange(virConnectPtr con= n, } =20 =20 +static int +remoteRelayDomainEventChannelLifecycle(virConnectPtr conn, + virDomainPtr dom, + const char *channelName, + int state, + int reason, + void *opaque) +{ + daemonClientEventCallback *callback =3D opaque; + remote_domain_event_callback_channel_lifecycle_msg data =3D { 0 }; + + if (callback->callbackID < 0 || + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) + return -1; + + VIR_DEBUG("Relaying domain channel lifecycle event %s %d, callback %d,= " + "name: %s, state %d, reason %d", + dom->name, dom->id, callback->callbackID, channelName, state= , reason); + + data.callbackID =3D callback->callbackID; + make_nonnull_domain(&data.dom, dom); + data.channelName =3D g_strdup(channelName); + data.state =3D state; + data.reason =3D reason; + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNE= L_LIFECYCLE, + (xdrproc_t)xdr_remote_domain_event_callb= ack_channel_lifecycle_msg, + &data); + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] =3D { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), @@ -1383,6 +1416,7 @@ static virConnectDomainEventGenericCallback domainEve= ntCallbacks[] =3D { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryFailure), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryDeviceSizeChange= ), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventNICMACChange), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventChannelLifecycle), }; =20 G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) =3D=3D VIR_DOMAIN_EVENT= _ID_LAST); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ec71eaed87..1fbead5941 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -437,6 +437,11 @@ remoteDomainBuildEventNICMACChange(virNetClientProgram= *prog, virNetClient *client, void *evdata, void *opaque); =20 +static void +remoteDomainBuildEventCallbackChannelLifecycle(virNetClientProgram *prog, + virNetClient *client, + void *evdata, void *opaque); + static virNetClientProgramEvent remoteEvents[] =3D { { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE, remoteDomainBuildEventLifecycle, @@ -659,6 +664,10 @@ static virNetClientProgramEvent remoteEvents[] =3D { remoteDomainBuildEventNICMACChange, sizeof(remote_domain_event_nic_mac_change_msg), (xdrproc_t)xdr_remote_domain_event_nic_mac_change_msg }, + { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE, + remoteDomainBuildEventCallbackChannelLifecycle, + sizeof(remote_domain_event_callback_channel_lifecycle_msg), + (xdrproc_t)xdr_remote_domain_event_callback_channel_lifecycle_msg }, }; =20 static void @@ -5164,6 +5173,31 @@ remoteDomainBuildEventNICMACChange(virNetClientProgr= am *prog G_GNUC_UNUSED, } =20 =20 +static void +remoteDomainBuildEventCallbackChannelLifecycle(virNetClientProgram *prog G= _GNUC_UNUSED, + virNetClient *client G_GNUC= _UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn =3D opaque; + remote_domain_event_callback_channel_lifecycle_msg *msg =3D evdata; + struct private_data *priv =3D conn->privateData; + virDomainPtr dom; + virObjectEvent *event =3D NULL; + + if (!(dom =3D get_nonnull_domain(conn, msg->dom))) + return; + + event =3D virDomainEventChannelLifecycleNewFromDom(dom, + msg->channelName, + msg->state, + msg->reason); + + virObjectUnref(dom); + + virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackI= D); +} + + static int remoteStreamSend(virStreamPtr st, const char *data, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 38a83c64ea..1041cd0fa2 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -4009,6 +4009,14 @@ struct remote_domain_event_nic_mac_change_msg { remote_nonnull_string newMAC; }; =20 +struct remote_domain_event_callback_channel_lifecycle_msg { + int callbackID; + remote_nonnull_domain dom; + remote_nonnull_string channelName; + int state; + int reason; +}; + /*----- Protocol. -----*/ =20 /* Define the program number, protocol version and procedure numbers here.= */ @@ -7120,5 +7128,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE =3D 453 + REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE =3D 453, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE =3D 454 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 0f87d13a5a..7d678afee3 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3337,6 +3337,13 @@ struct remote_domain_event_nic_mac_change_msg { remote_nonnull_string oldMAC; remote_nonnull_string newMAC; }; +struct remote_domain_event_callback_channel_lifecycle_msg { + int callbackID; + remote_nonnull_domain dom; + remote_nonnull_string channelName; + int state; + int reason; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN =3D 1, REMOTE_PROC_CONNECT_CLOSE =3D 2, @@ -3791,4 +3798,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_THROTTLE_GROUP =3D 451, REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP =3D 452, REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE =3D 453, + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE =3D 454, }; diff --git a/tools/virsh-domain-event.c b/tools/virsh-domain-event.c index b9d1cdf019..d0e571d491 100644 --- a/tools/virsh-domain-event.c +++ b/tools/virsh-domain-event.c @@ -655,6 +655,39 @@ virshEventAgentLifecyclePrint(virConnectPtr conn G_GNU= C_UNUSED, virshEventPrint(opaque, &buf); } =20 +VIR_ENUM_DECL(virshEventChannelLifecycleState); +VIR_ENUM_IMPL(virshEventChannelLifecycleState, + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST, + N_("unknown"), + N_("connected"), + N_("disconnected")); + +VIR_ENUM_DECL(virshEventChannelLifecycleReason); +VIR_ENUM_IMPL(virshEventChannelLifecycleReason, + VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST, + N_("unknown"), + N_("domain started"), + N_("channel event")); + +static void +virshEventChannelLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + const char *channelName, + int state, + int reason, + void *opaque) +{ + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, + _("event 'channel-lifecycle' for domain '%1$s': chan= nel name: '%2$s', state: '%3$s' reason: '%4$s'\n"), + virDomainGetName(dom), + channelName, + UNKNOWNSTR(virshEventChannelLifecycleStateTypeToStri= ng(state)), + UNKNOWNSTR(virshEventChannelLifecycleReasonTypeToStr= ing(reason))); + virshEventPrint(opaque, &buf); +} + static void virshEventMigrationIterationPrint(virConnectPtr conn G_GNUC_UNUSED, virDomainPtr dom, @@ -873,6 +906,8 @@ virshDomainEventCallback virshDomainEventCallbacks[] = =3D { VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryDeviceSizeChangePrint), }, { "nic-mac-change", VIR_DOMAIN_EVENT_CALLBACK(virshEventNICMACChangePrint), }, + { "channel-lifecycle", + VIR_DOMAIN_EVENT_CALLBACK(virshEventChannelLifecyclePrint), }, }; G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST =3D=3D G_N_ELEMENTS(virshDomainEv= entCallbacks)); =20 --=20 2.43.0