From nobody Sat May 11 06:37:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340104; cv=none; d=zohomail.com; s=zohoarc; b=dahWZ1N70jI8vfXW64Xw7W3qVdO+/IHqJPi4YPkGhTBqZcFtzpnDGYw2e8jPbgG03VmGO9nNz5KWTFMp/7uUx9fqJBgTs1j71h40jZLhObr8YjXWgxtr2Fsh4zwwu4qS2aIQj/+bAR3daQgKvbIS4i5UvTk/o5xXjiAXSzJPFDM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340104; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=E9ned6Bifusv/TGj9W2uUCoMZKcOaz5VeM3epKYmCew=; b=NINuabuk5vy2LbcbdJSxscJzO81hfNHNAkW4zr2j5RlGK6GFz8Fm8wjqe0zvRfHwH2mftmhtOvVW4m7nWOF1saZ/d4CazgpaFVA1u32W4qUArkwyd8umBNGvEPGF3Bl1nF77LM6y99ve7/xravku1BBuPGffZXbgKRi78G02gv4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1649340104169514.3205094861742; Thu, 7 Apr 2022 07:01:44 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-441-Uhwqm7ySPkir4F43OirNqQ-1; Thu, 07 Apr 2022 10:01:30 -0400 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C9C18833974; Thu, 7 Apr 2022 14:00:37 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id B414940314D; Thu, 7 Apr 2022 14:00:37 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id E30B8194034C; Thu, 7 Apr 2022 14:00:36 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id F0FC71947BBE for ; Thu, 7 Apr 2022 14:00:35 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id E2138403152; Thu, 7 Apr 2022 14:00:35 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 690D5401DB1 for ; Thu, 7 Apr 2022 14:00:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340103; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=E9ned6Bifusv/TGj9W2uUCoMZKcOaz5VeM3epKYmCew=; b=fl44phz+Qb9uh5FLY1+5CtBDa8aYgqRgCk8fLDiiOM+fdD7nUYPA/Uqi2cFbQJv/oAxkaF /LeEFsM0C+9wUsfTlNTdsDPXikiMgMabCqH7D54yT52ljJCB6Ixo4DKirawS4104+GUuqt FOsj0gSJN46m5AtT4Sw1fM7Lm3Sbdbs= X-MC-Unique: Uhwqm7ySPkir4F43OirNqQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 01/11] kbase: index: Split off 'internals' section Date: Thu, 7 Apr 2022 16:00:23 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340105747100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Add a separate column of documents regarding internals of libvirt and move the 'migrationinternals' and 'incrementalbackupinternals' pages under the new heading. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/kbase/index.rst | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 9c4e921f1f..4e18acd4d9 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -62,8 +62,8 @@ Usage Details about snapshotting a VM -Internals / Debugging ---------------------- +Debugging +--------- `Debug logs `__ Configuration of logging and tips on how to file a good bug report. @@ -71,13 +71,17 @@ Internals / Debugging `Systemtap `__ Explanation of how to use systemtap for libvirt tracing. +`Capturing core dumps for QEMU `__ + How to configure libvirt to enable capture of core dumps from + QEMU virtual machines + + +Internals +--------- + `Incremental backup internals `__ Incremental backup implementation details relevant for users `VM migration internals `__ VM migration implementation details, complementing the info in `migration <../migration.html>`__ - -`Capturing core dumps for QEMU `__ - How to configure libvirt to enable capture of core dumps from - QEMU virtual machines --=20 2.35.1 From nobody Sat May 11 06:37:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340050; cv=none; d=zohomail.com; s=zohoarc; b=k9wm9HqsNYgI8uObdWmSUOKsFFOGf/mfxATT/Ie9fzfy85KGXc9ayeYV8lZ+VvCXUpptH4ClaQz86cFHqhIm86E2oDAces4sBVSmAmPqe0yzacXwrHdkdqGh9WKs/b4VNfYmDeY0oVPYk95VIzZqL3QkC2f8gx/7lGCqhI6jzBI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340050; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=aJ636q3Yrq7MGYXBpcfbaV7qldCWrhpzx5mh21j4DC0=; b=XgDwSl4AOXRaWlh9n1IyNBYUCYSs5npudxeNRDPOp/temyBbtrKYanBM1WA6neHZUa0LNhAMtcFvUgMxrG3eAwwJNm3SGNZ5NpenTgllak4zldjflwmd9lM5pzLNiBuexxBaYRkrSgV46wjT7GOI8/o9phUD21WSu/Bn0HOAjXY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1649340050723940.3452169909301; Thu, 7 Apr 2022 07:00:50 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-298-vDcmRFqDMICfCUrV7slrmw-1; Thu, 07 Apr 2022 10:00:45 -0400 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4E839899EC4; Thu, 7 Apr 2022 14:00:38 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3503F403153; Thu, 7 Apr 2022 14:00:38 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id B629B1949763; Thu, 7 Apr 2022 14:00:37 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id F25951940350 for ; Thu, 7 Apr 2022 14:00:36 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id E247D401DB1; Thu, 7 Apr 2022 14:00:36 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5DF1840314D for ; Thu, 7 Apr 2022 14:00:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340049; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=aJ636q3Yrq7MGYXBpcfbaV7qldCWrhpzx5mh21j4DC0=; b=L7ezKlfEA7/C8VfgzIFxHjSqMSHIzpWtxBAkJFnCffS5epM0dwQgYj5XfgSIMuDvtfT47i BYzliVTxLOdib6mVMrisakBY2AsUEyarJS6qivR0Tz6cRpQ8zICQLczc22eXqjlLy/rbU8 YMZn1kKv/MdN2oxrqW0jeO7F9GacoIE= X-MC-Unique: vDcmRFqDMICfCUrV7slrmw-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 02/11] docs: Simplify passing of 'href_base' XSL variable Date: Thu, 7 Apr 2022 16:00:24 +0200 Message-Id: <467cd7ea7925259109a17fe5e397756ac8f2c1d4.1649339910.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340052409100003 Content-Type: text/plain; charset="utf-8"; x-default="true" Historically we had two top level XSL files for top level and nested documents which only differ in what they pass for 'href_base' to the main 'page.xsl' file. We can instead pass the variable as argument from the build system so that we have just one XSL file and also allow for more nested document trees in the future. The '404' page is special even with the current XSL way so we add a special case for it. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/go/meson.build | 5 +++-- docs/internals/meson.build | 5 +++-- docs/kbase/meson.build | 5 +++-- docs/manpages/meson.build | 5 +++-- docs/meson.build | 12 ++++++++---- docs/site.xsl | 12 +----------- docs/subsite.xsl | 24 ------------------------ 7 files changed, 21 insertions(+), 47 deletions(-) delete mode 100644 docs/subsite.xsl diff --git a/docs/go/meson.build b/docs/go/meson.build index 0ae0216ce3..c0e19c4182 100644 --- a/docs/go/meson.build +++ b/docs/go/meson.build @@ -3,7 +3,6 @@ docs_go_files =3D [ 'libvirtxml', ] -html_xslt_gen_xslt =3D subsite_xsl html_xslt_gen_install_dir =3D docs_html_dir / 'go' html_xslt_gen =3D [] @@ -14,6 +13,7 @@ foreach name : docs_go_files 'name': name, 'file': docs_rst2html5_gen.process(rst_file), 'source': 'docs' / 'go' / rst_file, + 'href_base': '../', } endforeach @@ -33,8 +33,9 @@ foreach data : html_xslt_gen '--stringparam', 'pagesrc', data.get('source', ''), '--stringparam', 'builddir', meson.build_root(), '--stringparam', 'timestamp', docs_timestamp, + '--stringparam', 'href_base', data.get('href_base', ''), '--nonet', - html_xslt_gen_xslt, + site_xsl, '@INPUT@', ], depends: data.get('depends', []), diff --git a/docs/internals/meson.build b/docs/internals/meson.build index 2d0ae6195c..298a55dd88 100644 --- a/docs/internals/meson.build +++ b/docs/internals/meson.build @@ -5,7 +5,6 @@ internals_in_files =3D [ 'rpc', ] -html_xslt_gen_xslt =3D subsite_xsl html_xslt_gen_install_dir =3D docs_html_dir / 'internals' html_xslt_gen =3D [] @@ -13,6 +12,7 @@ foreach name : internals_in_files html_xslt_gen +=3D { 'name': name, 'source': 'docs' / 'internals' / name + '.html.in', + 'href_base': '../' } endforeach @@ -32,8 +32,9 @@ foreach data : html_xslt_gen '--stringparam', 'pagesrc', data.get('source', ''), '--stringparam', 'builddir', meson.build_root(), '--stringparam', 'timestamp', docs_timestamp, + '--stringparam', 'href_base', data.get('href_base', ''), '--nonet', - html_xslt_gen_xslt, + site_xsl, '@INPUT@', ], depends: data.get('depends', []), diff --git a/docs/kbase/meson.build b/docs/kbase/meson.build index 4114fc81d1..e37feb6d30 100644 --- a/docs/kbase/meson.build +++ b/docs/kbase/meson.build @@ -24,7 +24,6 @@ docs_kbase_files =3D [ 'virtiofs', ] -html_xslt_gen_xslt =3D subsite_xsl html_xslt_gen_install_dir =3D docs_html_dir / 'kbase' html_xslt_gen =3D [] @@ -35,6 +34,7 @@ foreach name : docs_kbase_files 'name': name, 'file': docs_rst2html5_gen.process(rst_file), 'source': 'docs' / 'kbase' / rst_file, + 'href_base': '../', } endforeach @@ -54,8 +54,9 @@ foreach data : html_xslt_gen '--stringparam', 'pagesrc', data.get('source', ''), '--stringparam', 'builddir', meson.build_root(), '--stringparam', 'timestamp', docs_timestamp, + '--stringparam', 'href_base', data.get('href_base', ''), '--nonet', - html_xslt_gen_xslt, + site_xsl, '@INPUT@', ], depends: data.get('depends', []), diff --git a/docs/manpages/meson.build b/docs/manpages/meson.build index d9fcb6b057..ba673cf472 100644 --- a/docs/manpages/meson.build +++ b/docs/manpages/meson.build @@ -1,4 +1,3 @@ -html_xslt_gen_xslt =3D subsite_xsl html_xslt_gen_install_dir =3D docs_html_dir / 'manpages' html_xslt_gen =3D [] @@ -130,6 +129,7 @@ foreach data : docs_man_files 'name': data['name'], 'file': html_in, 'source': 'docs' / 'manpages' / rst_in_file, + 'href_base': '../', } endforeach @@ -149,8 +149,9 @@ foreach data : html_xslt_gen '--stringparam', 'pagesrc', data.get('source', ''), '--stringparam', 'builddir', meson.build_root(), '--stringparam', 'timestamp', docs_timestamp, + '--stringparam', 'href_base', data.get('href_base', ''), '--nonet', - html_xslt_gen_xslt, + site_xsl, '@INPUT@', ], depends: data.get('depends', []), diff --git a/docs/meson.build b/docs/meson.build index 2295fbf752..75b5e4c08f 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -18,7 +18,6 @@ docs_assets =3D [ ] docs_html_in_files =3D [ - '404', 'docs', 'formatcaps', 'formatdomaincaps', @@ -132,7 +131,6 @@ docs_timestamp =3D run_command( ).stdout().strip() site_xsl =3D files('site.xsl') -subsite_xsl =3D files('subsite.xsl') page_xsl =3D files('page.xsl') newapi_xsl =3D files('newapi.xsl') @@ -218,7 +216,6 @@ docs_rst2html5_gen =3D generator( # html_xslt_gen config -html_xslt_gen_xslt =3D site_xsl html_xslt_gen_install_dir =3D docs_html_dir html_xslt_gen =3D [] @@ -251,6 +248,12 @@ html_xslt_gen +=3D { 'depends': aclperms_gen, } +html_xslt_gen +=3D { + 'name': '404', + 'source': 'docs' / '404.html.in', + 'href_base': '/', +} + hvsupport_html_in =3D custom_target( 'hvsupport.html.in', output: 'hvsupport.html.in', @@ -302,8 +305,9 @@ foreach data : html_xslt_gen '--stringparam', 'pagesrc', data.get('source', ''), '--stringparam', 'builddir', meson.build_root(), '--stringparam', 'timestamp', docs_timestamp, + '--stringparam', 'href_base', data.get('href_base', ''), '--nonet', - html_xslt_gen_xslt, + site_xsl, '@INPUT@', ], depends: data.get('depends', []), diff --git a/docs/site.xsl b/docs/site.xsl index 931e26272f..f56eb67b8a 100644 --- a/docs/site.xsl +++ b/docs/site.xsl @@ -13,21 +13,11 @@ encoding=3D"UTF-8" indent=3D"yes"/> - - - - - - - - - - - + diff --git a/docs/subsite.xsl b/docs/subsite.xsl deleted file mode 100644 index 2bdfcbb9b1..0000000000 --- a/docs/subsite.xsl +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - --=20 2.35.1 From nobody Sat May 11 06:37:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340063; cv=none; d=zohomail.com; s=zohoarc; b=VUxKNvmexZIU9Mzr9qo2tWze34SdmrZVB7RO6SJQXYg2EWcg6IOIKNsKo0ELEKMZJ8UbVMAh6YeTxPaUrU2nkCcHNqiWct2vSPI4pHTrVrsMkU5FsZLd/IW1ggoYro2ihBdVpUZ30xZz9Px1CEZxuoGIFUJa3l3q3ItRsvSQBZc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340063; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=hCB7y19KQMgCfqt5dCkgk0X+px1pm6lbXZKuCNW7zoc=; b=e9ToMSF/Tj5DVaAwvoxsY1/kzE1H35NC7mNAKdJ4mU8HSkJmdEzbNgY9r8qjjkchVVTzqSmG2MoM+SseVyjvhV+N0FyvcYvL55z22O5fHDkBm1sdSBGjaxW0knfaXcgnQE0igZT3wBE7h3+s5PxCsKY23Xs93THnUEuKmWsOa68= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1649340063043260.6070692359938; Thu, 7 Apr 2022 07:01:03 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-345-LskxV7UYNyCGA7HJ0MjADQ-1; Thu, 07 Apr 2022 10:00:59 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9DC9738009E6; Thu, 7 Apr 2022 14:00:39 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8AEA0C28114; Thu, 7 Apr 2022 14:00:39 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 3B99F1949761; Thu, 7 Apr 2022 14:00:39 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 1F8E1194034B for ; Thu, 7 Apr 2022 14:00:38 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 0D90740314D; Thu, 7 Apr 2022 14:00:38 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7F95B403153 for ; Thu, 7 Apr 2022 14:00:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340062; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=hCB7y19KQMgCfqt5dCkgk0X+px1pm6lbXZKuCNW7zoc=; b=gYn1MXLtqkxrhkbuGbVom5Oy44lVj4C+L/W5BzLHkwCgu3X3czSsF3YOtT3UeK80yrbHvh nXjLuvlqbZ1wBQagmY5ilDvk4mJGmA3p0YBrknJIZasf4GB+yLk8aQvBuvZMTHKnzOpRte 9PF81KSlQuLQ00oYmBFnuLx3DL9dDpg= X-MC-Unique: LskxV7UYNyCGA7HJ0MjADQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 03/11] docs: kbase: Section of 'internals' documents into a subfolder Date: Thu, 7 Apr 2022 16:00:25 +0200 Message-Id: <0a9525a8b7b3323fdaecb37979ef54f0872ced73.1649339910.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.8 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340064502100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Add an 'internals' subfolder to 'docs/kbase' to house all the documents under internals. The output files are still under 'docs/kbase'. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/kbase/index.rst | 4 +- .../incremental-backup.rst} | 0 docs/kbase/internals/meson.build | 55 +++++++++++++++++++ .../migration.rst} | 0 docs/kbase/meson.build | 4 +- 5 files changed, 59 insertions(+), 4 deletions(-) rename docs/kbase/{incrementalbackupinternals.rst =3D> internals/increment= al-backup.rst} (100%) create mode 100644 docs/kbase/internals/meson.build rename docs/kbase/{migrationinternals.rst =3D> internals/migration.rst} (1= 00%) diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 4e18acd4d9..c6748e8883 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -79,9 +79,9 @@ Debugging Internals --------- -`Incremental backup internals `__ +`Incremental backup internals `__ Incremental backup implementation details relevant for users -`VM migration internals `__ +`VM migration internals `__ VM migration implementation details, complementing the info in `migration <../migration.html>`__ diff --git a/docs/kbase/incrementalbackupinternals.rst b/docs/kbase/interna= ls/incremental-backup.rst similarity index 100% rename from docs/kbase/incrementalbackupinternals.rst rename to docs/kbase/internals/incremental-backup.rst diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.= build new file mode 100644 index 0000000000..923e262706 --- /dev/null +++ b/docs/kbase/internals/meson.build @@ -0,0 +1,55 @@ +docs_kbase_internals_files =3D [ + 'incremental-backup', + 'migration', +] + + +html_xslt_gen_install_dir =3D docs_html_dir / 'kbase' / 'internals' +html_xslt_gen =3D [] + +foreach name : docs_kbase_internals_files + rst_file =3D '@0@.rst'.format(name) + + html_xslt_gen +=3D { + 'name': name, + 'file': docs_rst2html5_gen.process(rst_file), + 'source': 'docs' / 'kbase' / 'internals' / rst_file, + 'href_base': '../../', + } +endforeach + +# keep the XSLT processing code block in sync with docs/meson.build + +# --- begin of XSLT processing --- + +foreach data : html_xslt_gen + html_filename =3D data['name'] + '.html' + + html_file =3D custom_target( + html_filename, + input: data.get('file', data['name'] + '.html.in'), + output: html_filename, + command: [ + xsltproc_prog, + '--stringparam', 'pagesrc', data.get('source', ''), + '--stringparam', 'builddir', meson.build_root(), + '--stringparam', 'timestamp', docs_timestamp, + '--stringparam', 'href_base', data.get('href_base', ''), + '--nonet', + site_xsl, + '@INPUT@', + ], + depends: data.get('depends', []), + depend_files: [ page_xsl ], + capture: true, + install: true, + install_dir: html_xslt_gen_install_dir, + ) + + install_web_deps +=3D html_file + install_web_files +=3D html_file.full_path() + ':' + html_xslt_gen_insta= ll_dir +endforeach + +html_xslt_gen =3D [] + +# --- end of XSLT processing --- diff --git a/docs/kbase/migrationinternals.rst b/docs/kbase/internals/migra= tion.rst similarity index 100% rename from docs/kbase/migrationinternals.rst rename to docs/kbase/internals/migration.rst diff --git a/docs/kbase/meson.build b/docs/kbase/meson.build index e37feb6d30..269bf64a94 100644 --- a/docs/kbase/meson.build +++ b/docs/kbase/meson.build @@ -2,7 +2,6 @@ docs_kbase_files =3D [ 'backing_chains', 'debuglogs', 'domainstatecapture', - 'incrementalbackupinternals', 'index', 'kvm-realtime', 'launch_security_sev', @@ -12,7 +11,6 @@ docs_kbase_files =3D [ 'locking-sanlock', 'memorydevices', 'merging_disk_image_chains', - 'migrationinternals', 'qemu-core-dump', 'qemu-passthrough-security', 'rpm-deployment', @@ -73,3 +71,5 @@ endforeach html_xslt_gen =3D [] # --- end of XSLT processing --- + +subdir('internals') --=20 2.35.1 From nobody Sat May 11 06:37:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340065; cv=none; d=zohomail.com; s=zohoarc; b=nCfH1rpoPA4hbpS+aNv8Nf8elRTGjQM+rSN10T4PlzqVnNjqJDPMOc1a+d28BQzPvYRoUSv+jo/MjCXXqSlioRcAxJrK2lDa9jHOlU8zg4mag3Cqvhe3beepRyaGRx6zMrgLKBTXk/UlEKzwupfJqRKc6lWRz11FTw2Ozcf5qsc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340065; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ytEo7YKGWQgHNBQUksS97MIzAxg10lh0D6FenPl8BoE=; b=bJuLM+cN+Rox9iAJ+V6meXwoIPTcsf1KD7bX+SOMzZMT/EwBsIYavQkmYwNZUE6IcqJEwxrX6HAw50s3vegYceoSIEhtvS6HMeNBge8D+eF6QXx2N67DsTc2MbnYflnFa/GsBzVVh55ohWjfWOFSOwckSVM5mhGFYVvB18Mq2O8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1649340065770214.43453135148184; Thu, 7 Apr 2022 07:01:05 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-590-fe4bAbgcPwKLLUbt_seRNQ-1; Thu, 07 Apr 2022 10:01:01 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D97C32A2AD59; Thu, 7 Apr 2022 14:00:42 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id BF82740470D5; Thu, 7 Apr 2022 14:00:42 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 838E61949761; Thu, 7 Apr 2022 14:00:42 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 73A46194034B for ; Thu, 7 Apr 2022 14:00:39 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 62974403171; Thu, 7 Apr 2022 14:00:39 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 71AB340314D for ; Thu, 7 Apr 2022 14:00:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340064; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=ytEo7YKGWQgHNBQUksS97MIzAxg10lh0D6FenPl8BoE=; b=PeseU15qvgCu0Tt78SDHQk7siM6cvzLG5FSL8NdA1IRjpao2ZES3jxBoeQQntuYLgLLAY6 m3gh5M9zX5Fx4bE05DttWIw2ijm4aM36I/h6XVuN1rAWIeUa2pBUnFAddiYn6C6DDDg8zO A3t59GEBaabYWdZamLENzCIR8ivuo+I= X-MC-Unique: fe4bAbgcPwKLLUbt_seRNQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 04/11] docs: Convert 'docs' index page to rst Date: Thu, 7 Apr 2022 16:00:26 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340066610100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Along with the conversion we need to adapt the stylesheets to apply to the new document similarly to how we do that in the knowledge base. Note that one visible difference is that now a 'Documentation' heading is visible on top of the page. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/css/libvirt.css | 17 ++-- docs/docs.html.in | 188 ------------------------------------------- docs/docs.rst | 175 ++++++++++++++++++++++++++++++++++++++++ docs/meson.build | 2 +- 4 files changed, 188 insertions(+), 194 deletions(-) delete mode 100644 docs/docs.html.in create mode 100644 docs/docs.rst diff --git a/docs/css/libvirt.css b/docs/css/libvirt.css index b08271ea4d..2ae80f8595 100644 --- a/docs/css/libvirt.css +++ b/docs/css/libvirt.css @@ -105,8 +105,8 @@ } #index.document, -#docs.document, #hvsupport.document, +#documentation.document, #knowledge-base.document { width: inherit; @@ -397,6 +397,7 @@ h6:hover > a.headerlink { } div.panel, +#documentation .section, #knowledge-base .section { width: 24%; @@ -406,6 +407,7 @@ div.panel, } div.panel h2, +#documentation .section h1, #knowledge-base .section h1 { margin-top: 0px; padding: 0.5em; @@ -423,15 +425,12 @@ div.panel h2, height: 300px; } +#documentation.document > h1, #knowledge-base.document > h1 { text-align: center; padding: 1em; } -#docs.document h1 { - visibility: hidden; -} - br.clear { clear: both; border: 0px; @@ -485,11 +484,13 @@ br.clear { } div.panel dd, +#documentation dd, #knowledge-base dd { font-size: smaller; } div.panel a, +#documentation a, #knowledge-base a { text-decoration: none; } @@ -497,6 +498,9 @@ div.panel a, div.panel ul, div.panel p, div.panel dl, +#documentation ul, +#documentation p, +#documentation dl, #knowledge-base ul, #knowledge-base p, #knowledge-base dl { @@ -505,16 +509,19 @@ div.panel dl, } div.panel ul, +#documentation ul, #knowledge-base ul { margin-left: 1em; } div.panel dt, +#documentation dt, #knowledge-base dt { margin: 0px; } div.panel dd, +#documentation dd, #knowledge-base dd { margin: 0px; margin-bottom: 1em; diff --git a/docs/docs.html.in b/docs/docs.html.in deleted file mode 100644 index ff7a95fae7..0000000000 --- a/docs/docs.html.in +++ /dev/null @@ -1,188 +0,0 @@ - - - - -

Documentation

-
-

Deployment / operation

- -
-
Applications
-
Applications known to use libvirt
- -
Manual pages
-
Manual pages for libvirt tools / daemons
- -
Windows
-
Downloads for Windows
- -
macOS
-
Working with libvirt on macOS
- -
Migration
-
Migrating guests between machines
- -
Daemons
-
Overview of the daemons provided by libvirt
- -
Remote access
-
Enable remote access over TCP
- -
Authentication
-
Configure authentication for the libvirt daemon
- -
Access control
-
Configure access control libvirt APIs with polkit
- -
Logging
-
The library and the daemon logging support
- -
Audit log
-
Audit trail logs for host operations
- -
Firewall
-
Firewall and network filter configuration
- -
Hooks
-
Hooks for system specific management
- -
NSS module
-
Enable domain host name translation to IP addresses
- -
FAQ
-
Frequently asked questions
-
- -
- -
-

Application development

-
-
API reference
-
Reference manual for the C public API, split in - common, - domain, - domain c= heckpoint, - domain sna= pshot, - error, - event, - host, - interface, - network, - node device, - network filter, - secret, - storage, - stream - and - admin, - QEMU, - LXC libs -
- -
Language bindings and API modules
-
Bindings of the libvirt API for - c#, - go, - java, - ocaml, - perl, - python, - php, - ruby - and integration API modules for - D-Bus
- - -
XML schemas
-
Description of the XML schemas for - domains, - networks, - network ports, - network filtering, - storage, - storage encryption, - capabilities, - domain capabilities, - storage pool capabilities, - node devices, - secrets, - snapshots, - checkpoints, - backup jobs
- -
URI format
-
The URI formats used for connecting to libvirt
- -
CGroups
-
Control groups integration
- -
Drivers
-
Hypervisor specific driver information
- -
Support guarantees
-
Details of support status for various interfaces
- -
Driver support
-
matrix of API support per hypervisor per release
- -
Knowledge Base
-
Task oriented guides to key features
-
-
- -
-

Project development

-
-
Contributor guidelines
-
General hacking guidelines for contributors
- -
Docs style guide
-
Style guidelines for reStructuredText docs
- -
Project strategy
-
Sets a vision for future direction & technical choices
- -
CI Testing
-
Details of the Continuous Integration testing strategy
- -
Bug reports
-
How and where to report bugs and request features
- -
Compiling
-
How to compile libvirt
- -
Goals
-
Terminology and goals of libvirt API
- -
API concepts
-
The libvirt API concepts
- -
API extensions
-
Adding new public libvirt APIs
- -
Event loop and worker poo= l
-
Libvirt's event loop and worker pool mode
- -
Spawning commands
-
Spawning commands from libvirt driver code
- -
RPC protocol & APIs
-
RPC protocol information and API / dispatch guide
- -
Lock managers
-
Use lock managers to protect disk content
- -
Functional testing
-
Testing libvirt with TCK test suite and - Libvirt-test-API
- -
New repo setup
-
Procedure for configuring new git repositories for libvirt
-
-
- -
- - - diff --git a/docs/docs.rst b/docs/docs.rst new file mode 100644 index 0000000000..299c26d09b --- /dev/null +++ b/docs/docs.rst @@ -0,0 +1,175 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Documentation +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Deployment / operation +---------------------- + +`Applications `__ + Applications known to use libvirt + +`Manual pages `__ + Manual pages for libvirt tools / daemons + +`Windows `__ + Downloads for Windows + +`macOS `__ + Working with libvirt on macOS + +`Migration `__ + Migrating guests between machines + +`Daemons `__ + Overview of the daemons provided by libvirt + +`Remote access `__ + Enable remote access over TCP + +`TLS certs `__ + Generate and deploy x509 certificates for TLS + +`Authentication `__ + Configure authentication for the libvirt daemon + +`Access control `__ + Configure access control libvirt APIs with `polkit `__ + +`Logging `__ + The library and the daemon logging support + +`Audit log `__ + Audit trail logs for host operations + +`Firewall `__ + Firewall and network filter configuration + +`Hooks `__ + Hooks for system specific management + +`NSS module `__ + Enable domain host name translation to IP addresses + +`FAQ `__ + Frequently asked questions + +Application development +----------------------- + +`API reference `__ + Reference manual for the C public API, split in + `common `__, + `domain `__, + `domain checkpoint `__, + `domain snapshot `__, + `error `__, + `event `__, + `host `__, + `interface `__, + `network `__, + `node device `__, + `network filter `__, + `secret `__, + `storage `__, + `stream `__ and + `admin `__, + `QEMU `__, + `LXC `__ libs + +`Language bindings and API modules `__ + Bindings of the libvirt API for + `c# `__, + `go `__, + `java `__, + `ocaml `__, + `perl `__, + `python `__, + `php `__, + `ruby `__ + and integration API modules for + `D-Bus `__ + +`XML schemas `__ + Description of the XML schemas for + `domains `__, + `networks `__, + `network ports `__, + `network filtering `__, + `storage `__, + `storage encryption `__, + `capabilities `__, + `domain capabilities `__, + `storage pool capabilities `__, + `node devices `__, + `secrets `__, + `snapshots `__, + `checkpoints `__, + `backup jobs `__ + +`URI format `__ + The URI formats used for connecting to libvirt + +`CGroups `__ + Control groups integration + +`Drivers `__ + Hypervisor specific driver information + +`Support guarantees `__ + Details of support status for various interfaces + +`Driver support `__ + matrix of API support per hypervisor per release + +`Knowledge Base `__ + Task oriented guides to key features + +Project development +------------------- + +`Contributor guidelines `__ + General hacking guidelines for contributors + +`Docs style guide `__ + Style guidelines for reStructuredText docs + +`Project strategy `__ + Sets a vision for future direction & technical choices + +`CI Testing `__ + Details of the Continuous Integration testing strategy + +`Bug reports `__ + How and where to report bugs and request features + +`Compiling `__ + How to compile libvirt + +`Goals `__ + Terminology and goals of libvirt API + +`API concepts `__ + The libvirt API concepts + +`API extensions `__ + Adding new public libvirt APIs + +`Event loop and worker pool `__ + Libvirt's event loop and worker pool mode + +`Spawning commands `__ + Spawning commands from libvirt driver code + +`RPC protocol & APIs `__ + RPC protocol information and API / dispatch guide + +`Lock managers `__ + Use lock managers to protect disk content + +`Functional testing `__ + Testing libvirt with + `TCK test suite `__ and + `Libvirt-test-API `__ + +`New repo setup `__ + Procedure for configuring new git repositories for libvirt diff --git a/docs/meson.build b/docs/meson.build index 75b5e4c08f..9e69a0dc05 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -18,7 +18,6 @@ docs_assets =3D [ ] docs_html_in_files =3D [ - 'docs', 'formatcaps', 'formatdomaincaps', 'formatnetwork', @@ -53,6 +52,7 @@ docs_rst_files =3D [ 'csharp', 'daemons', 'dbus', + 'docs', 'downloads', 'drivers', 'drvbhyve', --=20 2.35.1 From nobody Sat May 11 06:37:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340069; cv=none; d=zohomail.com; s=zohoarc; b=g0Tp/ySnk8CrCn56IkfoFqEx+WpAZDTjc41uMp7X43FkayhhEeYii/AFNLVh7CZDSHdhWdbSh9KL5udAZRRfUlxIikWSPffQ/gIkE4vLrZ5ATSaDTyf5DPEesgp+kLNgGwbVxcX5OCLYVVRbtQwes2eKsPZ3cZIKJWbeTUdJ3W0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340069; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=2DQo/suXzBNebHq2VVb03TE2J9ma0DgHX8guaIDjRzM=; b=brJykrIo/GVG3nKGUQARG5n5qLaWa8NWBVqyKh9D5yB/jFeZAHON9ttovT3I3v/ONn38BX7UnHQaVgfDDtstsLIlSmrJMxVrI5SGFdha/+0whPTfnRuFvdxJ6/E5oXpup9R45DsII/KcB/7/UXwaervNg1Kpg4iIrkWLAs5WahU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1649340069791757.9990884244692; Thu, 7 Apr 2022 07:01:09 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-674-4NMS1yl7Plm4PwLoa1dI0Q-1; Thu, 07 Apr 2022 10:01:04 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 329ED899ECF; Thu, 7 Apr 2022 14:00:44 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1AD014118EEB; Thu, 7 Apr 2022 14:00:44 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id E28241949761; Thu, 7 Apr 2022 14:00:43 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 640AA1947BBE for ; Thu, 7 Apr 2022 14:00:41 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 55173403152; Thu, 7 Apr 2022 14:00:41 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id E9EBD416374 for ; Thu, 7 Apr 2022 14:00:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340068; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=2DQo/suXzBNebHq2VVb03TE2J9ma0DgHX8guaIDjRzM=; b=amxqiI8r8a1s4IEXOuU53dRUdiKSMPXPHrlT20/SuZK9VJXdw+1qa/vsjmgjj0hIXc47x7 mhE7wcSVYGp1MBMuROzOCNT2S+CH1rUst6hNySzlse9cdWWruVYhimEO7FxKENWNUNZBfT dHNs2xhTw74+mq0FNmXHYzZHZjYOLdQ= X-MC-Unique: 4NMS1yl7Plm4PwLoa1dI0Q-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 05/11] docs: Convert 'internals/command' to rst and move it to 'kbase/internals' Date: Thu, 7 Apr 2022 16:00:27 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340071652100005 Content-Type: text/plain; charset="utf-8"; x-default="true" Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/docs.rst | 3 - docs/internals/command.html.in | 596 ------------------------------- docs/internals/meson.build | 1 - docs/kbase/index.rst | 3 + docs/kbase/internals/command.rst | 465 ++++++++++++++++++++++++ docs/kbase/internals/meson.build | 1 + 6 files changed, 469 insertions(+), 600 deletions(-) delete mode 100644 docs/internals/command.html.in create mode 100644 docs/kbase/internals/command.rst diff --git a/docs/docs.rst b/docs/docs.rst index 299c26d09b..a92c7c26ab 100644 --- a/docs/docs.rst +++ b/docs/docs.rst @@ -157,9 +157,6 @@ Project development `Event loop and worker pool `__ Libvirt's event loop and worker pool mode -`Spawning commands `__ - Spawning commands from libvirt driver code - `RPC protocol & APIs `__ RPC protocol information and API / dispatch guide diff --git a/docs/internals/command.html.in b/docs/internals/command.html.in deleted file mode 100644 index d9f53933c6..0000000000 --- a/docs/internals/command.html.in +++ /dev/null @@ -1,596 +0,0 @@ - - - - -

Spawning processes / commands from libvirt drivers

- -
    - -

    - This page describes the usage of libvirt APIs for - spawning processes / commands from libvirt drivers. - All code is required to use these APIs -

    - -

    Problems with standard POSIX APIs

    - -

    - The POSIX specification includes a number of APIs for - spawning processes / commands, but they suffer from - a number of flaws -

    - -
      -
    • fork+exec: The lowest & most flexible - level, but very hard to use correctly / safely. It - is easy to leak file descriptors, have unexpected - signal handler behaviour and not handle edge cases. - Furthermore, it is not portable to mingw. -
    • -
    • system: Convenient if you don't care - about capturing command output, but has the serious - downside that the command string is interpreted by - the shell. This makes it very dangerous to use, because - improperly validated user input can lead to exploits - via shell meta characters. -
    • -
    • popen: Inherits the flaws of - system, and has no option for bi-directional - communication. -
    • -
    • posix_spawn: A half-way house between - simplicity of system() and the flexibility of fork+exec. - It does not allow for a couple of important features - though, such as running a hook between the fork+exec - stage, or closing all open file descriptors.
    • -
    - -

    - Due to the problems mentioned with each of these, - libvirt driver code must not use any - of the above APIs. Historically libvirt provided a - higher level API known as virExec. This was wrapper - around fork+exec, in a similar style to posix_spawn, - but with a few more features. -

    - -

    - This wrapper still suffered from a number of problems. - Handling command cleanup via waitpid() is overly - complex & error prone for most usage. Building up the - argv[] + env[] string arrays is quite cumbersome and - error prone, particularly wrt memory leak / OOM handling. -

    - -

    The libvirt command execution API

    - -

    - There is now a high level API that provides a safe and - flexible way to spawn commands, which prevents the most - common errors & is easy to code against. This - code is provided in the src/util/vircommand.h - header which can be imported using #include "vircommand.h" -

    - -

    Defining commands in libvirt

    - -

    - The first step is to declare what command is to be - executed. The command name can be either a fully - qualified path, or a bare command name. In the latter - case it will be resolved wrt the $PATH - environment variable. -

    - -
    -virCommand *cmd =3D virCommandNew("/usr/bin/dnsmasq");
    -
    - -

    - There is no need to check for allocation failure after - virCommandNew. This will be detected and - reported at a later time. -

    - -

    Adding arguments to the command

    - -

    - There are a number of APIs for adding arguments to a - command. To add a direct string arg -

    - -
    -virCommandAddArg(cmd, "-strict-order");
    -
    - -

    - If an argument takes an attached value of the form - -arg=3Dval, then this can be done using -

    - -
    -virCommandAddArgPair(cmd, "--conf-file", "/etc/dnsmasq.conf");
    -
    - -

    - If an argument needs to be formatted as if by - printf: -

    - -
    -virCommandAddArgFormat(cmd, "%d", count);
    -
    - -

    - To add an entire NULL terminated array of arguments in one go, - there are two options. -

    - -
    -const char *const args[] =3D {
    -    "--strict-order", "--except-interface", "lo", NULL
    -};
    -virCommandAddArgSet(cmd, args);
    -virCommandAddArgList(cmd, "--domain", "localdomain", NULL);
    -
    - -

    - This can also be done at the time of initial construction of - the virCommand * object: -

    - -
    -const char *const args[] =3D {
    -    "/usr/bin/dnsmasq",
    -    "--strict-order", "--except-interface",
    -    "lo", "--domain", "localdomain", NULL
    -};
    -virCommand *cmd1 =3D virCommandNewArgs(cmd, args);
    -virCommand *cmd2 =3D virCommandNewArgList("/usr/bin/dnsmasq",
    -                                          "--domain", "localdomain", NULL);
    -
    - -

    Setting up the environment

    - -

    - By default a command will inherit all environment variables - from the current process. Generally this is not desirable - and a customized environment will be more suitable. Any - customization done via the following APIs will prevent - inheritance of any existing environment variables unless - explicitly allowed. The first step is usually to pass through - a small number of variables from the current process. -

    - -
    -virCommandAddEnvPassCommon(cmd);
    -
    - -

    - This has now set up a clean environment for the child, passing - through PATH, LD_PRELOAD, - LD_LIBRARY_PATH, HOME, - USER, LOGNAME and TMPDIR. - Furthermore it will explicitly set LC_ALL=3DC to - avoid unexpected localization of command output. Further - variables can be passed through from parent explicitly: -

    - -
    -virCommandAddEnvPass(cmd, "DISPLAY");
    -virCommandAddEnvPass(cmd, "XAUTHORITY");
    -
    - -

    - To define an environment variable in the child with an - separate key / value: -

    - -
    -virCommandAddEnvPair(cmd, "TERM", "xterm");
    -
    - -

    - If the key/value pair is pre-formatted in the right - format, it can be set directly -

    - -
    -virCommandAddEnvString(cmd, "TERM=3Dxterm");
    -
    - -

    Miscellaneous other options

    - -

    - Normally the spawned command will retain the current - process and process group as its parent. If the current - process dies, the child will then (usually) be terminated - too. If this cleanup is not desired, then the command - should be marked as daemonized: -

    - -
    -virCommandDaemonize(cmd);
    -
    - -

    - When daemonizing a command, the PID visible from the - caller will be that of the intermediate process, not - the actual damonized command. If the PID of the real - command is required then a pidfile can be requested -

    - -
    -virCommandSetPidFile(cmd, "/var/run/dnsmasq.pid");
    -
    - -

    - This PID file is guaranteed to be written before - the intermediate process exits. Moreover, the daemonized - process will inherit the FD of the opened and locked PID - file. -

    - -

    Reducing command privileges

    - -

    - Normally a command will inherit all privileges of - the current process. To restrict what a command can - do, it is possible to request that all its capabilities - are cleared. With this done it will only be able to - access resources for which it has explicit DAC permissions -

    - -
    -virCommandClearCaps(cmd);
    -
    - -

    Managing file handles

    - -

    - To prevent unintended resource leaks to child processes, the - child defaults to closing all open file handles, and setting - stdin/out/err to /dev/null. It is possible to - allow an open file handle to be passed into the child, while - controlling whether that handle remains open in the parent or - guaranteeing that the handle will be closed in the parent after - virCommandRun, virCommandRunAsync, or virCommandFree. -

    - -
    -int sharedfd =3D open("cmd.log", "w+");
    -int childfd =3D open("conf.txt", "r");
    -virCommandPassFD(cmd, sharedfd, 0);
    -virCommandPassFD(cmd, childfd,
    -                 VIR_COMMAND_PASS_FD_CLOSE_PARENT);
    -if (VIR_CLOSE(sharedfd) < 0)
    -    goto cleanup;
    -
    - -

    - With this, both file descriptors sharedfd and childfd in the - current process remain open as the same file descriptors in the - child. Meanwhile, after the child is spawned, sharedfd remains - open in the parent, while childfd is closed. -

    - -

    - For stdin/out/err it is sometimes necessary to map a file - handle. If a mapped file handle is a pipe fed or consumed by - the caller, then the caller should use virCommandDaemonize or - virCommandRunAsync rather than virCommandRun to avoid deadlock - (mapping a regular file is okay with virCommandRun). To attach - file descriptor 7 in the current process to stdin in the child: -

    - -
    -virCommandSetInputFD(cmd, 7);
    -
    - -

    - Equivalently to redirect stdout or stderr in the child, - pass in a pointer to the desired handle -

    - -
    -int outfd =3D open("out.log", "w+");
    -int errfd =3D open("err.log", "w+");
    -virCommandSetOutputFD(cmd, &outfd);
    -virCommandSetErrorFD(cmd, &errfd);
    -
    - -

    - Alternatively it is possible to request that a pipe be - created to fetch stdout/err in the parent, by initializing - the FD to -1. -

    - -
    -int outfd =3D -1;
    -int errfd =3D -1
    -virCommandSetOutputFD(cmd, &outfd);
    -virCommandSetErrorFD(cmd, &errfd);
    -
    - -

    - Once the command is running, outfd - and errfd will be initialized with - valid file handles that can be read from. It is - permissible to pass the same pointer for both outfd - and errfd, in which case both standard streams in - the child will share the same fd in the parent. -

    - -

    - Normally, file descriptors opened to collect output from a child - process perform blocking I/O, but the parent process can request - non-blocking mode: -

    - -
    -virCommandNonblockingFDs(cmd);
    -
    - -

    Feeding & capturing strings to/from the chil= d

    - -

    - Often dealing with file handles for stdin/out/err is - unnecessarily complex; an alternative is to let virCommandRun - perform the I/O and interact via string buffers. Use of a buffer - only works with virCommandRun, and cannot be mixed with pipe - file descriptors. That is, the choice is generally between - managing all I/O in the caller (any fds not specified are tied - to /dev/null), or letting virCommandRun manage all I/O via - strings (unspecified stdin is tied to /dev/null, and unspecified - output streams get logged but are otherwise discarded). -

    - -

    - It is possible to specify a string buffer to act as the data - source for the child's stdin, if there are no embedded NUL - bytes, and if the command will be run with virCommandRun: -

    - -
    -const char *input =3D "Hello World\n";
    -virCommandSetInputBuffer(cmd, input);
    -
    - -

    - Similarly it is possible to request that the child's - stdout/err be redirected into a string buffer, if the - output is not expected to contain NUL bytes, and if - the command will be run with virCommandRun: -

    - -
    -char *output =3D NULL, *errors =3D NULL;
    -virCommandSetOutputBuffer(cmd, &output);
    -virCommandSetErrorBuffer(cmd, &errors);
    -
    - -

    - Once the command has finished executing, these buffers will - contain the output. Allocation is guaranteed if virCommandRun - or virCommandWait succeed (if there was no output, then the - buffer will contain an allocated empty string); if the command - failed, then the buffers usually contain a best-effort - allocation of collected information (however, on an - out-of-memory condition, the buffer may still be NULL). The - caller is responsible for freeing registered buffers, since the - buffers are designed to persist beyond virCommandFree. It - is possible to pass the same pointer to both - virCommandSetOutputBuffer and virCommandSetErrorBuffer, in which - case the child process interleaves output into a single string. -

    - -

    Setting working directory

    - -

    - Daemonized commands are always run with "/" as the current - working directory. All other commands default to running in the - same working directory as the parent process, but an alternate - directory can be specified: -

    - -
    -virCommandSetWorkingDirectory(cmd, LOCALSTATEDIR);
    -
    - -

    Any additional hooks

    - -

    - If anything else is needed, it is possible to request a hook - function that is called in the child after the fork, as the - last thing before changing directories, dropping capabilities, - and executing the new process. If hook(opaque) returns - non-zero, then the child process will not be run. -

    - -
    -virCommandSetPreExecHook(cmd, hook, opaque);
    -
    - -

    Logging commands

    - -

    - Sometimes, it is desirable to log what command will be run, or - even to use virCommand solely for creation of a single - consolidated string without running anything. -

    - -
    -int logfd =3D ...;
    -char *timestamp =3D virTimestamp();
    -char *string =3D NULL;
    -
    -dprintf(logfd, "%s: ", timestamp);
    -VIR_FREE(timestamp);
    -virCommandWriteArgLog(cmd, logfd);
    -
    -string =3D virCommandToString(cmd, false);
    -if (string)
    -    VIR_DEBUG("about to run %s", string);
    -VIR_FREE(string);
    -if (virCommandRun(cmd, NULL) < 0)
    -    return -1;
    -
    - -

    Running commands synchronously

    - -

    - For most commands, the desired behaviour is to spawn - the command, wait for it to complete & exit and then - check that its exit status is zero -

    - -
    -if (virCommandRun(cmd, NULL) < 0)
    -   return -1;
    -
    - -

    - Note: if the command has been daemonized - this will only block & wait for the intermediate process, - not the real command. virCommandRun will - report on any errors that have occurred upon this point - with all previous API calls. If the command fails to - run, or exits with non-zero status an error will be - reported via normal libvirt error infrastructure. If a - non-zero exit status can represent a success condition, - it is possible to request the exit status and perform - that check manually instead of letting virCommandRun - raise the error. By default, the captured status is only - for a normal exit (death from a signal is treated as an error), - but a caller can use virCommandRawStatus to get - encoded status that includes any terminating signals. -

    - -
    -int status;
    -if (virCommandRun(cmd, &status) < 0)
    -    return -1;
    -if (status =3D=3D 1) {
    -  ...do stuff...
    -}
    -
    -virCommandRawStatus(cmd2);
    -if (virCommandRun(cmd2, &status) < 0)
    -    return -1;
    -if (WIFEXITED(status) && WEXITSTATUS(status) =3D=3D 1) {
    -  ...do stuff...
    -}
    -
    - -

    Running commands asynchronously

    - -

    - In certain complex scenarios, particularly special - I/O handling is required for the child's stdin/err/out - it will be necessary to run the command asynchronously - and wait for completion separately. -

    - -
    -pid_t pid;
    -if (virCommandRunAsync(cmd, &pid) < 0)
    -   return -1;
    -
    -... do something while pid is running ...
    -
    -int status;
    -if (virCommandWait(cmd, &status) < 0)
    -   return -1;
    -
    -if (WEXITSTATUS(status)...) {
    -   ..do stuff..
    -}
    -
    - -

    - As with virCommandRun, the status - arg for virCommandWait can be omitted, in which - case it will validate that exit status is zero and raise an - error if not. -

    - -

    - There are two approaches to child process cleanup, determined by - how long you want to keep the virCommand object in scope. -

    - -

    1. If the virCommand object will outlast the child process, - then pass NULL for the pid argument, and the child process will - automatically be reaped at virCommandFree, unless you reap it - sooner via virCommandWait or virCommandAbort. -

    - -

    2. If the child process must exist on at least one code path - after virCommandFree, then pass a pointer for the pid argument. - Later, to clean up the child, call virPidWait or virPidAbort. - Before virCommandFree, you can still use virCommandWait or - virCommandAbort to reap the process. -

    - -

    Releasing resources

    - -

    - Once the command has been executed, or if execution - has been abandoned, it is necessary to release - resources associated with the virCommand * - object. This is done with: -

    - -
    -virCommandFree(cmd);
    -
    - -

    - There is no need to check if cmd is NULL - before calling virCommandFree. This scenario - is handled automatically. If the command is still running, - it will be forcibly killed and cleaned up (via waitpid). -

    - -

    Complete examples

    - -

    - This shows a complete example usage of the APIs roughly - using the libvirt source src/util/hooks.c -

    - -
    -int runhook(const char *drvstr, const char *id,
    -            const char *opstr, const char *subopstr,
    -            const char *extra)
    -{
    -  g_autofree char *path =3D NULL;
    -  g_autoptr(virCommand) cmd =3D NULL;
    -
    -  virBuildPath(&path, LIBVIRT_HOOK_DIR, drvstr);
    -
    -  cmd =3D virCommandNew(path);
    -
    -  virCommandAddEnvPassCommon(cmd);
    -
    -  virCommandAddArgList(cmd, id, opstr, subopstr, extra, NULL);
    -
    -  virCommandSetInputBuffer(cmd, input);
    -
    -  return virCommandRun(cmd, NULL);
    -}
    -
    - -

    - In this example, the command is being run synchronously. - A pre-formatted string is being fed to the command as - its stdin. The command takes four arguments, and has a - minimal set of environment variables passed down. In - this example, the code does not require any error checking. - All errors are reported by the virCommandRun - method, and the exit status from this is returned to - the caller to handle as desired. -

    - - - diff --git a/docs/internals/meson.build b/docs/internals/meson.build index 298a55dd88..e5f4bb0a4b 100644 --- a/docs/internals/meson.build +++ b/docs/internals/meson.build @@ -1,5 +1,4 @@ internals_in_files =3D [ - 'command', 'eventloop', 'locking', 'rpc', diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index c6748e8883..01ec5a070d 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -85,3 +85,6 @@ Internals `VM migration internals `__ VM migration implementation details, complementing the info in `migration <../migration.html>`__ + +`Spawning commands `__ + Spawning commands from libvirt driver code diff --git a/docs/kbase/internals/command.rst b/docs/kbase/internals/comman= d.rst new file mode 100644 index 0000000000..738fb5930a --- /dev/null +++ b/docs/kbase/internals/command.rst @@ -0,0 +1,465 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D +Spawning processes / commands from libvirt drivers +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D + +.. contents:: + +This page describes the usage of libvirt APIs for spawning processes / com= mands +from libvirt drivers. All code is required to use these APIs + +Problems with standard POSIX APIs +--------------------------------- + +The POSIX specification includes a number of APIs for spawning processes / +commands, but they suffer from a number of flaws + +- ``fork+exec``: The lowest & most flexible level, but very hard to use + correctly / safely. It is easy to leak file descriptors, have unexpected + signal handler behaviour and not handle edge cases. Furthermore, it is = not + portable to mingw. +- ``system``: Convenient if you don't care about capturing command output= , but + has the serious downside that the command string is interpreted by the = shell. + This makes it very dangerous to use, because improperly validated user = input + can lead to exploits via shell meta characters. +- ``popen``: Inherits the flaws of ``system``, and has no option for + bi-directional communication. +- ``posix_spawn``: A half-way house between simplicity of system() and the + flexibility of fork+exec. It does not allow for a couple of important + features though, such as running a hook between the fork+exec stage, or + closing all open file descriptors. + +Due to the problems mentioned with each of these, libvirt driver code **mu= st not +use** any of the above APIs. Historically libvirt provided a higher level = API +known as virExec. This was wrapper around fork+exec, in a similar style to +posix_spawn, but with a few more features. + +This wrapper still suffered from a number of problems. Handling command cl= eanup +via waitpid() is overly complex & error prone for most usage. Building up = the +argv[] + env[] string arrays is quite cumbersome and error prone, particul= arly +wrt memory leak / OOM handling. + +The libvirt command execution API +--------------------------------- + +There is now a high level API that provides a safe and flexible way to spa= wn +commands, which prevents the most common errors & is easy to code against.= This +code is provided in the ``src/util/vircommand.h`` header which can be impo= rted +using ``#include "vircommand.h"`` + +Defining commands in libvirt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The first step is to declare what command is to be executed. The command n= ame +can be either a fully qualified path, or a bare command name. In the latte= r case +it will be resolved wrt the ``$PATH`` environment variable. + +:: + + virCommand *cmd =3D virCommandNew("/usr/bin/dnsmasq"); + +There is no need to check for allocation failure after ``virCommandNew``. = This +will be detected and reported at a later time. + +Adding arguments to the command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are a number of APIs for adding arguments to a command. To add a dir= ect +string arg + +:: + + virCommandAddArg(cmd, "-strict-order"); + +If an argument takes an attached value of the form ``-arg=3Dval``, then th= is can +be done using + +:: + + virCommandAddArgPair(cmd, "--conf-file", "/etc/dnsmasq.conf"); + +If an argument needs to be formatted as if by ``printf``: + +:: + + virCommandAddArgFormat(cmd, "%d", count); + +To add an entire NULL terminated array of arguments in one go, there are t= wo +options. + +:: + + const char *const args[] =3D { + "--strict-order", "--except-interface", "lo", NULL + }; + virCommandAddArgSet(cmd, args); + virCommandAddArgList(cmd, "--domain", "localdomain", NULL); + +This can also be done at the time of initial construction of the +``virCommand *`` object: + +:: + + const char *const args[] =3D { + "/usr/bin/dnsmasq", + "--strict-order", "--except-interface", + "lo", "--domain", "localdomain", NULL + }; + virCommand *cmd1 =3D virCommandNewArgs(cmd, args); + virCommand *cmd2 =3D virCommandNewArgList("/usr/bin/dnsmasq", + "--domain", "localdomain", NU= LL); + +Setting up the environment +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default a command will inherit all environment variables from the curre= nt +process. Generally this is not desirable and a customized environment will= be +more suitable. Any customization done via the following APIs will prevent +inheritance of any existing environment variables unless explicitly allowe= d. The +first step is usually to pass through a small number of variables from the +current process. + +:: + + virCommandAddEnvPassCommon(cmd); + +This has now set up a clean environment for the child, passing through ``P= ATH``, +``LD_PRELOAD``, ``LD_LIBRARY_PATH``, ``HOME``, ``USER``, ``LOGNAME`` and +``TMPDIR``. Furthermore it will explicitly set ``LC_ALL=3DC`` to avoid une= xpected +localization of command output. Further variables can be passed through fr= om +parent explicitly: + +:: + + virCommandAddEnvPass(cmd, "DISPLAY"); + virCommandAddEnvPass(cmd, "XAUTHORITY"); + +To define an environment variable in the child with an separate key / valu= e: + +:: + + virCommandAddEnvPair(cmd, "TERM", "xterm"); + +If the key/value pair is pre-formatted in the right format, it can be set +directly + +:: + + virCommandAddEnvString(cmd, "TERM=3Dxterm"); + +Miscellaneous other options +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Normally the spawned command will retain the current process and process g= roup +as its parent. If the current process dies, the child will then (usually) = be +terminated too. If this cleanup is not desired, then the command should be +marked as daemonized: + +:: + + virCommandDaemonize(cmd); + +When daemonizing a command, the PID visible from the caller will be that o= f the +intermediate process, not the actual damonized command. If the PID of the = real +command is required then a pidfile can be requested + +:: + + virCommandSetPidFile(cmd, "/var/run/dnsmasq.pid"); + +This PID file is guaranteed to be written before the intermediate process = exits. +Moreover, the daemonized process will inherit the FD of the opened and loc= ked +PID file. + +Reducing command privileges +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Normally a command will inherit all privileges of the current process. To +restrict what a command can do, it is possible to request that all its +capabilities are cleared. With this done it will only be able to access +resources for which it has explicit DAC permissions + +:: + + virCommandClearCaps(cmd); + +Managing file handles +~~~~~~~~~~~~~~~~~~~~~ + +To prevent unintended resource leaks to child processes, the child default= s to +closing all open file handles, and setting stdin/out/err to ``/dev/null``.= It is +possible to allow an open file handle to be passed into the child, while +controlling whether that handle remains open in the parent or guaranteeing= that +the handle will be closed in the parent after virCommandRun, virCommandRun= Async, +or virCommandFree. + +:: + + int sharedfd =3D open("cmd.log", "w+"); + int childfd =3D open("conf.txt", "r"); + virCommandPassFD(cmd, sharedfd, 0); + virCommandPassFD(cmd, childfd, + VIR_COMMAND_PASS_FD_CLOSE_PARENT); + if (VIR_CLOSE(sharedfd) < 0) + goto cleanup; + +With this, both file descriptors sharedfd and childfd in the current proce= ss +remain open as the same file descriptors in the child. Meanwhile, after the +child is spawned, sharedfd remains open in the parent, while childfd is cl= osed. + +For stdin/out/err it is sometimes necessary to map a file handle. If a map= ped +file handle is a pipe fed or consumed by the caller, then the caller shoul= d use +virCommandDaemonize or virCommandRunAsync rather than virCommandRun to avo= id +deadlock (mapping a regular file is okay with virCommandRun). To attach fi= le +descriptor 7 in the current process to stdin in the child: + +:: + + virCommandSetInputFD(cmd, 7); + +Equivalently to redirect stdout or stderr in the child, pass in a pointer = to the +desired handle + +:: + + int outfd =3D open("out.log", "w+"); + int errfd =3D open("err.log", "w+"); + virCommandSetOutputFD(cmd, &outfd); + virCommandSetErrorFD(cmd, &errfd); + +Alternatively it is possible to request that a pipe be created to fetch +stdout/err in the parent, by initializing the FD to -1. + +:: + + int outfd =3D -1; + int errfd =3D -1 + virCommandSetOutputFD(cmd, &outfd); + virCommandSetErrorFD(cmd, &errfd); + +Once the command is running, ``outfd`` and ``errfd`` will be initialized w= ith +valid file handles that can be read from. It is permissible to pass the sa= me +pointer for both outfd and errfd, in which case both standard streams in t= he +child will share the same fd in the parent. + +Normally, file descriptors opened to collect output from a child process p= erform +blocking I/O, but the parent process can request non-blocking mode: + +:: + + virCommandNonblockingFDs(cmd); + +Feeding & capturing strings to/from the child +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Often dealing with file handles for stdin/out/err is unnecessarily complex= ; an +alternative is to let virCommandRun perform the I/O and interact via string +buffers. Use of a buffer only works with virCommandRun, and cannot be mixe= d with +pipe file descriptors. That is, the choice is generally between managing a= ll I/O +in the caller (any fds not specified are tied to /dev/null), or letting +virCommandRun manage all I/O via strings (unspecified stdin is tied to +/dev/null, and unspecified output streams get logged but are otherwise +discarded). + +It is possible to specify a string buffer to act as the data source for the +child's stdin, if there are no embedded NUL bytes, and if the command will= be +run with virCommandRun: + +:: + + const char *input =3D "Hello World\n"; + virCommandSetInputBuffer(cmd, input); + +Similarly it is possible to request that the child's stdout/err be redirec= ted +into a string buffer, if the output is not expected to contain NUL bytes, = and if +the command will be run with virCommandRun: + +:: + + char *output =3D NULL, *errors =3D NULL; + virCommandSetOutputBuffer(cmd, &output); + virCommandSetErrorBuffer(cmd, &errors); + +Once the command has finished executing, these buffers will contain the ou= tput. +Allocation is guaranteed if virCommandRun or virCommandWait succeed (if th= ere +was no output, then the buffer will contain an allocated empty string); if= the +command failed, then the buffers usually contain a best-effort allocation = of +collected information (however, on an out-of-memory condition, the buffer = may +still be NULL). The caller is responsible for freeing registered buffers, = since +the buffers are designed to persist beyond virCommandFree. It is possible = to +pass the same pointer to both virCommandSetOutputBuffer and +virCommandSetErrorBuffer, in which case the child process interleaves outp= ut +into a single string. + +Setting working directory +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Daemonized commands are always run with "/" as the current working directo= ry. +All other commands default to running in the same working directory as the +parent process, but an alternate directory can be specified: + +:: + + virCommandSetWorkingDirectory(cmd, LOCALSTATEDIR); + +Any additional hooks +~~~~~~~~~~~~~~~~~~~~ + +If anything else is needed, it is possible to request a hook function that= is +called in the child after the fork, as the last thing before changing +directories, dropping capabilities, and executing the new process. If +hook(opaque) returns non-zero, then the child process will not be run. + +:: + + virCommandSetPreExecHook(cmd, hook, opaque); + +Logging commands +~~~~~~~~~~~~~~~~ + +Sometimes, it is desirable to log what command will be run, or even to use +virCommand solely for creation of a single consolidated string without run= ning +anything. + +:: + + int logfd =3D ...; + char *timestamp =3D virTimestamp(); + char *string =3D NULL; + + dprintf(logfd, "%s: ", timestamp); + VIR_FREE(timestamp); + virCommandWriteArgLog(cmd, logfd); + + string =3D virCommandToString(cmd, false); + if (string) + VIR_DEBUG("about to run %s", string); + VIR_FREE(string); + if (virCommandRun(cmd, NULL) < 0) + return -1; + +Running commands synchronously +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For most commands, the desired behaviour is to spawn the command, wait for= it to +complete & exit and then check that its exit status is zero + +:: + + if (virCommandRun(cmd, NULL) < 0) + return -1; + +**Note:** if the command has been daemonized this will only block & wait f= or the +intermediate process, not the real command. ``virCommandRun`` will report = on any +errors that have occurred upon this point with all previous API calls. If = the +command fails to run, or exits with non-zero status an error will be repor= ted +via normal libvirt error infrastructure. If a non-zero exit status can rep= resent +a success condition, it is possible to request the exit status and perform= that +check manually instead of letting ``virCommandRun`` raise the error. By de= fault, +the captured status is only for a normal exit (death from a signal is trea= ted as +an error), but a caller can use ``virCommandRawStatus`` to get encoded sta= tus +that includes any terminating signals. + +:: + + int status; + if (virCommandRun(cmd, &status) < 0) + return -1; + if (status =3D=3D 1) { + ...do stuff... + } + + virCommandRawStatus(cmd2); + if (virCommandRun(cmd2, &status) < 0) + return -1; + if (WIFEXITED(status) && WEXITSTATUS(status) =3D=3D 1) { + ...do stuff... + } + +Running commands asynchronously +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In certain complex scenarios, particularly special I/O handling is require= d for +the child's stdin/err/out it will be necessary to run the command asynchro= nously +and wait for completion separately. + +:: + + pid_t pid; + if (virCommandRunAsync(cmd, &pid) < 0) + return -1; + + ... do something while pid is running ... + + int status; + if (virCommandWait(cmd, &status) < 0) + return -1; + + if (WEXITSTATUS(status)...) { + ..do stuff.. + } + +As with ``virCommandRun``, the ``status`` arg for ``virCommandWait`` can be +omitted, in which case it will validate that exit status is zero and raise= an +error if not. + +There are two approaches to child process cleanup, determined by how long = you +want to keep the virCommand object in scope. + +1. If the virCommand object will outlast the child process, then pass NULL= for +the pid argument, and the child process will automatically be reaped at +virCommandFree, unless you reap it sooner via virCommandWait or virCommand= Abort. + +2. If the child process must exist on at least one code path after +virCommandFree, then pass a pointer for the pid argument. Later, to clean = up the +child, call virPidWait or virPidAbort. Before virCommandFree, you can stil= l use +virCommandWait or virCommandAbort to reap the process. + +Releasing resources +~~~~~~~~~~~~~~~~~~~ + +Once the command has been executed, or if execution has been abandoned, it= is +necessary to release resources associated with the ``virCommand *`` object= . This +is done with: + +:: + + virCommandFree(cmd); + +There is no need to check if ``cmd`` is NULL before calling ``virCommandFr= ee``. +This scenario is handled automatically. If the command is still running, i= t will +be forcibly killed and cleaned up (via waitpid). + +Complete examples +----------------- + +This shows a complete example usage of the APIs roughly using the libvirt = source +src/util/hooks.c + +:: + + int runhook(const char *drvstr, const char *id, + const char *opstr, const char *subopstr, + const char *extra) + { + g_autofree char *path =3D NULL; + g_autoptr(virCommand) cmd =3D NULL; + + virBuildPath(&path, LIBVIRT_HOOK_DIR, drvstr); + + cmd =3D virCommandNew(path); + + virCommandAddEnvPassCommon(cmd); + + virCommandAddArgList(cmd, id, opstr, subopstr, extra, NULL); + + virCommandSetInputBuffer(cmd, input); + + return virCommandRun(cmd, NULL); + } + +In this example, the command is being run synchronously. A pre-formatted s= tring +is being fed to the command as its stdin. The command takes four arguments= , and +has a minimal set of environment variables passed down. In this example, t= he +code does not require any error checking. All errors are reported by the +``virCommandRun`` method, and the exit status from this is returned to the +caller to handle as desired. diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.= build index 923e262706..3486b21852 100644 --- a/docs/kbase/internals/meson.build +++ b/docs/kbase/internals/meson.build @@ -1,4 +1,5 @@ docs_kbase_internals_files =3D [ + 'command', 'incremental-backup', 'migration', ] --=20 2.35.1 From nobody Sat May 11 06:37:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340155; cv=none; d=zohomail.com; s=zohoarc; b=e7V6t2803eTWE7n+LT3qWPjSeU7ZpD3Dkzn55O2b8+l+W0VeeHnBW4ti71dhYGNskJcCzZUgdsEWO7KvNkQzB7EZ4RAHTGY5oEglDwd1tsM5fbD7eochkcsQjxA7upNc83feJ9gRGADXKHzn/lSJIzkcBSh6wRkiv1+cxvi92UY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340155; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=qWY+HJgaG/5W4xHYyQJxT84xJswyyA6jHYq6yYEopnQ=; b=iooxAG94UseS2eZ+XbqRq43HlhIV476CCRsDLCXRmoa+7RTGS1Rjd83NC5LQAl6+Vwz1To//M4D5OEEkwEq4LBG2patdewehgyGMv6BVzZrjQa1t2AgxzWSla6FXTnHwajU04khOT3xg3seFjIMVk1iW8fikG4OMApctjXmc6Ts= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1649340155791690.344927855409; Thu, 7 Apr 2022 07:02:35 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-131-8e99mPZJO2amQNCW8INKAQ-1; Thu, 07 Apr 2022 10:01:17 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BAE0D833960; Thu, 7 Apr 2022 14:00:44 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id A66C34118EFA; Thu, 7 Apr 2022 14:00:44 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 415E91949763; Thu, 7 Apr 2022 14:00:44 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 9D7B11940347 for ; Thu, 7 Apr 2022 14:00:42 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 81681403372; Thu, 7 Apr 2022 14:00:42 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id BD08E40314D for ; Thu, 7 Apr 2022 14:00:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340154; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=qWY+HJgaG/5W4xHYyQJxT84xJswyyA6jHYq6yYEopnQ=; b=hfc/a4m/RzvYuRINUno3tTsuzJhtZB7IX8ckZNohR3arK86YX+i98HahyrFasnF5c1tRvl aU5pbMpYFxva84nARMueR4wgEu4nz9ZxV0/TVJcMT7ypWRzKEjbc5ccKwOvwhfUHQXZkjA 23w1g3qDV2GzDyNwXzoByMQOkxtanC4= X-MC-Unique: 8e99mPZJO2amQNCW8INKAQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 06/11] docs: Convert 'internals/eventloop' page to rst and move it to 'kbase/internals' Date: Thu, 7 Apr 2022 16:00:28 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340157377100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/docs.rst | 3 - docs/internals/eventloop.html.in | 106 ----------------------------- docs/internals/meson.build | 1 - docs/kbase/index.rst | 3 + docs/kbase/internals/eventloop.rst | 84 +++++++++++++++++++++++ docs/kbase/internals/meson.build | 1 + 6 files changed, 88 insertions(+), 110 deletions(-) delete mode 100644 docs/internals/eventloop.html.in create mode 100644 docs/kbase/internals/eventloop.rst diff --git a/docs/docs.rst b/docs/docs.rst index a92c7c26ab..4496206d6a 100644 --- a/docs/docs.rst +++ b/docs/docs.rst @@ -154,9 +154,6 @@ Project development `API extensions `__ Adding new public libvirt APIs -`Event loop and worker pool `__ - Libvirt's event loop and worker pool mode - `RPC protocol & APIs `__ RPC protocol information and API / dispatch guide diff --git a/docs/internals/eventloop.html.in b/docs/internals/eventloop.ht= ml.in deleted file mode 100644 index 1a24254fc5..0000000000 --- a/docs/internals/eventloop.html.in +++ /dev/null @@ -1,106 +0,0 @@ - - - - -

    Libvirt's event loop

    - -
      - -

      - This page describes the event loop approach used in - libvirt. Both server and client. -

      - -

      Event driven programming

      - -

      Traditionally, a program simply ran once, then terminated. - This type of program was very common in the early days of - computing, and lacked any form of user interactivity. This is - still used frequently, particularly in small one purpose - programs.

      - -

      However, that approach is not suitable for all the types - of applications. For instance graphical applications spend - most of their run time waiting for an input from user. Only - after it happened (in our example a button was clicked, a key - pressed, etc.) an event is generated to which they respond - by executing desired function. If generalized, this is how - many long running programs (daemons) work. Even those who are - not waiting for direct user input and have no graphical - interface. Such as Libvirt.

      - - 3D"event - -

      In Libvirt this approach is used in combination with - poll(2) as all the communication with its - clients (and domains it manages too) happens through sockets. - Therefore whenever new client connects, it is given exclusive - file descriptor which is then watched for incoming events, - e.g. messages.

      - -

      The event loop API

      - -

      To work with event loop from our code we have plenty of - APIs.

      - -
        -
      • virEventAddHandle: Registers a - callback for monitoring file handle events.
      • -
      • virEventUpdateHandle: Change set of events - monitored file handle is being watched for.
      • -
      • virEventRemoveHandle: Unregisters - previously registered file handle so that it is no - longer monitored for any events.
      • -
      • virEventAddTimeout: Registers a - callback for timer event.
      • -
      • virEventUpdateTimeout: Changes frequency - for a timer.
      • -
      • virEventRemoveTimeout: Unregisters - a timer.
      • -
      - -

      For more information on these APIs continue reading here.

      - -

      Worker pool

      - -

      Looking back at the image above we can see one big - limitation. While processing a message event loop is blocked - and for an outside observer unresponsive. This is not - acceptable for Libvirt. Therefore we have came up with the - following solution.

      - - 3D"event - -

      The event loop does only necessary minimum and hand over - message processing to another thread. In fact, there can be - as many processing threads as configured increasing - processing power.

      - -

      To break this high level description into smaller pieces, - here is what happens when user calls an API:

      -
        -
      1. User (or management application) calls a Libvirt API. - Depending on the connection URI, this may or may not - involve server. Well, for the sake of our - demonstration we assume the former.
      2. -
      3. Remote driver encodes the API among it's arguments - into an RPC message and sends - it to the server.
      4. -
      5. Here, server is waiting in poll(2) for - an event, like incoming message.
      6. -
      7. As soon as the first bytes of message are received, - even loop wakes up and server starts reading the - whole message.
      8. -
      9. Once fully read, the event loop notifies threads - known as worker threads from which one picks the incoming - message, decodes and process it.
      10. -
      11. As soon as API execution is finished, a reply is sent - to the client.
      12. -
      - -

      In case that there's no free worker to process an incoming - message in step 5, message is placed at the end of a message - queue and is processed in next iteration.

      - - diff --git a/docs/internals/meson.build b/docs/internals/meson.build index e5f4bb0a4b..5baf444bf9 100644 --- a/docs/internals/meson.build +++ b/docs/internals/meson.build @@ -1,5 +1,4 @@ internals_in_files =3D [ - 'eventloop', 'locking', 'rpc', ] diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 01ec5a070d..47cfc0505c 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -88,3 +88,6 @@ Internals `Spawning commands `__ Spawning commands from libvirt driver code + +`Event loop and worker pool `__ + Libvirt's event loop and worker pool mode diff --git a/docs/kbase/internals/eventloop.rst b/docs/kbase/internals/even= tloop.rst new file mode 100644 index 0000000000..f25e97ab14 --- /dev/null +++ b/docs/kbase/internals/eventloop.rst @@ -0,0 +1,84 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Libvirt's event loop +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. contents:: + +This page describes the event loop approach used in libvirt. Both server a= nd +client. + +Event driven programming +------------------------ + +Traditionally, a program simply ran once, then terminated. This type of pr= ogram +was very common in the early days of computing, and lacked any form of user +interactivity. This is still used frequently, particularly in small one pu= rpose +programs. + +However, that approach is not suitable for all the types of applications. = For +instance graphical applications spend most of their run time waiting for an +input from user. Only after it happened (in our example a button was click= ed, a +key pressed, etc.) an event is generated to which they respond by executing +desired function. If generalized, this is how many long running programs +(daemons) work. Even those who are not waiting for direct user input and h= ave no +graphical interface. Such as Libvirt. + +.. image:: ../images/event_loop_simple.png + :alt: event loop + +In Libvirt this approach is used in combination with ``poll(2)`` as all the +communication with its clients (and domains it manages too) happens through +sockets. Therefore whenever new client connects, it is given exclusive file +descriptor which is then watched for incoming events, e.g. messages. + +The event loop API +------------------ + +To work with event loop from our code we have plenty of APIs. + +- ``virEventAddHandle``: Registers a callback for monitoring file handle + events. +- ``virEventUpdateHandle``: Change set of events monitored file handle is= being + watched for. +- ``virEventRemoveHandle``: Unregisters previously registered file handle= so + that it is no longer monitored for any events. +- ``virEventAddTimeout``: Registers a callback for timer event. +- ``virEventUpdateTimeout``: Changes frequency for a timer. +- ``virEventRemoveTimeout``: Unregisters a timer. + +For more information on these APIs continue reading +`here <../html/libvirt-libvirt-event.html>`__. + +Worker pool +----------- + +Looking back at the image above we can see one big limitation. While proce= ssing +a message event loop is blocked and for an outside observer unresponsive. = This +is not acceptable for Libvirt. Therefore we have came up with the following +solution. + +.. image:: ../images/event_loop_worker.png + :alt: event loop + +The event loop does only necessary minimum and hand over message processin= g to +another thread. In fact, there can be as many processing threads as config= ured +increasing processing power. + +To break this high level description into smaller pieces, here is what hap= pens +when user calls an API: + +#. User (or management application) calls a Libvirt API. Depending on the + connection URI, this may or may not involve server. Well, for the sake = of our + demonstration we assume the former. +#. Remote driver encodes the API among it's arguments into an `RPC + message `__ and sends it to the server. +#. Here, server is waiting in ``poll(2)`` for an event, like incoming mess= age. +#. As soon as the first bytes of message are received, even loop wakes up = and + server starts reading the whole message. +#. Once fully read, the event loop notifies threads known as worker thread= s from + which one picks the incoming message, decodes and process it. +#. As soon as API execution is finished, a reply is sent to the client. + +In case that there's no free worker to process an incoming message in step= 5, +message is placed at the end of a message queue and is processed in next +iteration. diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.= build index 3486b21852..5f61f5dba4 100644 --- a/docs/kbase/internals/meson.build +++ b/docs/kbase/internals/meson.build @@ -1,5 +1,6 @@ docs_kbase_internals_files =3D [ 'command', + 'eventloop', 'incremental-backup', 'migration', ] --=20 2.35.1 From nobody Sat May 11 06:37:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340123; cv=none; d=zohomail.com; s=zohoarc; b=YQ5uttScyX+zUR4hbTv2Qg420Y3qf4NrQh9iXYBBt5cLCGU1Quggt0lNbIL5OJ33cX7EEEK46Ti2I6qEmUtt2J1UQBQ0BpdW4Gmapit3L/UZk2Eo1oslmYTDtFAPqADVxcfXEmOyBQSjS4lU3w31MU2vOlrtW191abzi5oh8HEs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340123; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=JPk2+uDclVr3Uxblz4Cj1hAF5VBdzDzMahHhau/bgtw=; b=eJATXr+RAYe5kXjZ0tSKfqMG9MBruJVSO/Zi1By3byikMx5+Sohdmxir2Hq9qflQRKObSA2qQgV51UcFZtaQ4Z0bx5qbn5OEv8+9a52TfF0D4J3DLIh5Y4t+JajHN2DhCbsfCDciHGncFZUHrD/kJKHGJfEIJEOn5L4xRLuYn+I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1649340123415438.103779934813; Thu, 7 Apr 2022 07:02:03 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-571-CiPH5u0TPhuExgUAbn9q1g-1; Thu, 07 Apr 2022 10:01:00 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6608C1C0B107; Thu, 7 Apr 2022 14:00:45 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4D52C482CD0; Thu, 7 Apr 2022 14:00:45 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 269711949763; Thu, 7 Apr 2022 14:00:45 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id B186B1947BBE for ; Thu, 7 Apr 2022 14:00:43 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 80664401DB1; Thu, 7 Apr 2022 14:00:43 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0ADCD403171 for ; Thu, 7 Apr 2022 14:00:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340122; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=JPk2+uDclVr3Uxblz4Cj1hAF5VBdzDzMahHhau/bgtw=; b=b+6ygMGrsJEOd+1PrW8FaMHRJg469G84V4dMTATFwC0rFInZiaM6mDfv0Aat/qoXqF9mSb 3WyXjcEu6ZVmRUV6hQ7CA5v02BPVj3Q6fKv3xs+V7h7ID1GVoVomy/TFOyXAT9/Mxtq6uT A5L4EGXE2xqL31ajonUz9KzzglcD6Nc= X-MC-Unique: CiPH5u0TPhuExgUAbn9q1g-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 07/11] docs: Convert 'internals/locking' page to rst and move it to 'kbase/internals' Date: Thu, 7 Apr 2022 16:00:29 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340125128100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/docs.rst | 3 - docs/internals/locking.html.in | 267 ------------------------------- docs/internals/meson.build | 1 - docs/kbase/index.rst | 3 + docs/kbase/internals/locking.rst | 190 ++++++++++++++++++++++ docs/kbase/internals/meson.build | 1 + docs/kbase/meson.build | 1 - 7 files changed, 194 insertions(+), 272 deletions(-) delete mode 100644 docs/internals/locking.html.in create mode 100644 docs/kbase/internals/locking.rst diff --git a/docs/docs.rst b/docs/docs.rst index 4496206d6a..3387dacce8 100644 --- a/docs/docs.rst +++ b/docs/docs.rst @@ -157,9 +157,6 @@ Project development `RPC protocol & APIs `__ RPC protocol information and API / dispatch guide -`Lock managers `__ - Use lock managers to protect disk content - `Functional testing `__ Testing libvirt with `TCK test suite `__ and diff --git a/docs/internals/locking.html.in b/docs/internals/locking.html.in deleted file mode 100644 index d10efdf26e..0000000000 --- a/docs/internals/locking.html.in +++ /dev/null @@ -1,267 +0,0 @@ - - - - -

      Resource Lock Manager

      - -
        - -

        - This page describes the design of the resource lock manager - that is used for locking disk images, to ensure exclusive - access to content. -

        - -

        Goals

        - -

        - The high level goal is to prevent the same disk image being - used by more than one QEMU instance at a time (unless the - disk is marked as shareable, or readonly). The scenarios - to be prevented are thus: -

        - -
          -
        1. - Two different guests running configured to point at the - same disk image. -
        2. -
        3. - One guest being started more than once on two different - machines due to admin mistake -
        4. -
        5. - One guest being started more than once on a single machine - due to libvirt driver bug on a single machine. -
        6. -
        - -

        Requirements

        - -

        - The high level goal leads to a set of requirements - for the lock manager design -

        - -
          -
        1. - A lock must be held on a disk whenever a QEMU process - has the disk open -
        2. -
        3. - The lock scheme must allow QEMU to be configured with - readonly, shared write, or exclusive writable disks -
        4. -
        5. - A lock handover must be performed during the migration - process where 2 QEMU processes will have the same disk - open concurrently. -
        6. -
        7. - The lock manager must be able to identify and kill the - process accessing the resource if the lock is revoked. -
        8. -
        9. - Locks can be acquired for arbitrary VM related resources, - as determined by the management application. -
        10. -
        - -

        Design

        - -

        - Within a lock manager the following series of operations - will need to be supported. -

        - -
          -
        • - Register object - Register the identity of an object against which - locks will be acquired -
        • -
        • - Add resource - Associate a resource with an object for future - lock acquisition / release -
        • -
        • - Acquire locks - Acquire the locks for all resources associated - with the object -
        • -
        • - Release locks - Release the locks for all resources associated - with the object -
        • -
        • - Inquire locks - Get a representation of the state of the locks - for all resources associated with the object -
        • -
        - -

        Plugin Implementations

        - -

        - Lock manager implementations are provided as LGPLv2+ - licensed, dlopen()able library modules. The plugins - will be loadable from the following location: -

        - -
        -/usr/{lib,lib64}/libvirt/lock_manager/$NAME.so
        -
        - -

        - The lock manager plugin must export a single ELF - symbol named virLockDriverImpl, which is - a static instance of the virLockDriver - struct. The struct is defined in the header file -

        - -
        -#include <libvirt/plugins/lock_manager.h>
        -    
        - -

        - All callbacks in the struct must be initialized - to non-NULL pointers. The semantics of each - callback are defined in the API docs embedded - in the previously mentioned header file -

        - -

        QEMU Driver integration

        - -

        - With the QEMU driver, the lock plugin will be set - in the /etc/libvirt/qemu.conf configuration - file by specifying the lock manager name. -

        - -
        -lockManager=3D"sanlock"
        -    
        - -

        - By default the lock manager will be a 'no op' implementation - for backwards compatibility -

        - -

        Lock usage patterns

        - -

        - The following pseudo code illustrates the common - patterns of operations invoked on the lock - manager plugin callbacks. -

        - -

        Lock acquisition

        - -

        - Initial lock acquisition will be performed from the - process that is to own the lock. This is typically - the QEMU child process, in between the fork+exec - pairing. When adding further resources on the fly, - to an existing object holding locks, this will be - done from the libvirtd process. -

        - -
        -virLockManagerParam params[] =3D {
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UUID,
        -    .key =3D "uuid",
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
        -    .key =3D "name",
        -    .value =3D { .str =3D dom->def->name },
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
        -    .key =3D "id",
        -    .value =3D { .i =3D dom->def->id },
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
        -    .key =3D "pid",
        -    .value =3D { .i =3D dom->pid },
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING,
        -    .key =3D "uri",
        -    .value =3D { .cstr =3D driver->uri },
        -  },
        -};
        -mgr =3D virLockManagerNew(lockPlugin,
        -                        VIR_LOCK_MANAGER_TYPE_DOMAIN,
        -                        ARRAY_CARDINALITY(params),
        -                        params,
        -                        0)));
        -
        -foreach (initial disks)
        -    virLockManagerAddResource(mgr,
        -                              VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
        -                              $path, 0, NULL, $flags);
        -
        -if (virLockManagerAcquire(lock, NULL, 0) < 0);
        -  ...abort...
        -    
        - -

        Lock release

        - -

        - The locks are all implicitly released when the process - that acquired them exits, however, a process may - voluntarily give up the lock by running -

        - -
        -char *state =3D NULL;
        -virLockManagerParam params[] =3D {
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UUID,
        -    .key =3D "uuid",
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
        -    .key =3D "name",
        -    .value =3D { .str =3D dom->def->name },
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
        -    .key =3D "id",
        -    .value =3D { .i =3D dom->def->id },
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
        -    .key =3D "pid",
        -    .value =3D { .i =3D dom->pid },
        -  },
        -  { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING,
        -    .key =3D "uri",
        -    .value =3D { .cstr =3D driver->uri },
        -  },
        -};
        -mgr =3D virLockManagerNew(lockPlugin,
        -                        VIR_LOCK_MANAGER_TYPE_DOMAIN,
        -                        ARRAY_CARDINALITY(params),
        -                        params,
        -                        0)));
        -
        -foreach (initial disks)
        -    virLockManagerAddResource(mgr,
        -                              VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
        -                              $path, 0, NULL, $flags);
        -
        -virLockManagerRelease(mgr, & state, 0);
        -    
        - -

        - The returned state string can be passed to the - virLockManagerAcquire method to - later re-acquire the exact same locks. This - state transfer is commonly used when performing - live migration of virtual machines. By validating - the state the lock manager can ensure no other - VM has re-acquire the same locks on a different - host. The state can also be obtained without - releasing the locks, by calling the - virLockManagerInquire method. -

        - - - diff --git a/docs/internals/meson.build b/docs/internals/meson.build index 5baf444bf9..68a2e70a3d 100644 --- a/docs/internals/meson.build +++ b/docs/internals/meson.build @@ -1,5 +1,4 @@ internals_in_files =3D [ - 'locking', 'rpc', ] diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 47cfc0505c..2125bf4252 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -91,3 +91,6 @@ Internals `Event loop and worker pool `__ Libvirt's event loop and worker pool mode + +`Lock managers `__ + Use lock managers to protect disk content diff --git a/docs/kbase/internals/locking.rst b/docs/kbase/internals/lockin= g.rst new file mode 100644 index 0000000000..50d2b92d57 --- /dev/null +++ b/docs/kbase/internals/locking.rst @@ -0,0 +1,190 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Resource Lock Manager +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. contents:: + +This page describes the design of the resource lock manager that is used f= or +locking disk images, to ensure exclusive access to content. + +Goals +----- + +The high level goal is to prevent the same disk image being used by more t= han +one QEMU instance at a time (unless the disk is marked as shareable, or +readonly). The scenarios to be prevented are thus: + +#. Two different guests running configured to point at the same disk image. +#. One guest being started more than once on two different machines due to= admin + mistake +#. One guest being started more than once on a single machine due to libvi= rt + driver bug on a single machine. + +Requirements +------------ + +The high level goal leads to a set of requirements for the lock manager de= sign + +#. A lock must be held on a disk whenever a QEMU process has the disk open +#. The lock scheme must allow QEMU to be configured with readonly, shared = write, + or exclusive writable disks +#. A lock handover must be performed during the migration process where 2 = QEMU + processes will have the same disk open concurrently. +#. The lock manager must be able to identify and kill the process accessin= g the + resource if the lock is revoked. +#. Locks can be acquired for arbitrary VM related resources, as determined= by + the management application. + +Design +------ + +Within a lock manager the following series of operations will need to be +supported. + +- **Register object** Register the identity of an object against which lo= cks + will be acquired +- **Add resource** Associate a resource with an object for future lock + acquisition / release +- **Acquire locks** Acquire the locks for all resources associated with t= he + object +- **Release locks** Release the locks for all resources associated with t= he + object +- **Inquire locks** Get a representation of the state of the locks for all + resources associated with the object + +Plugin Implementations +---------------------- + +Lock manager implementations are provided as LGPLv2+ licensed, dlopen()able +library modules. The plugins will be loadable from the following location: + +:: + + /usr/{lib,lib64}/libvirt/lock_manager/$NAME.so + +The lock manager plugin must export a single ELF symbol named +``virLockDriverImpl``, which is a static instance of the ``virLockDriver`` +struct. The struct is defined in the header file + +:: + + #include + +All callbacks in the struct must be initialized to non-NULL pointers. The +semantics of each callback are defined in the API docs embedded in the +previously mentioned header file + +QEMU Driver integration +----------------------- + +With the QEMU driver, the lock plugin will be set in the +``/etc/libvirt/qemu.conf`` configuration file by specifying the lock manag= er +name. + +:: + + lockManager=3D"sanlock" + +By default the lock manager will be a 'no op' implementation for backwards +compatibility + +Lock usage patterns +------------------- + +The following pseudo code illustrates the common patterns of operations in= voked +on the lock manager plugin callbacks. + +Lock acquisition +~~~~~~~~~~~~~~~~ + +Initial lock acquisition will be performed from the process that is to own= the +lock. This is typically the QEMU child process, in between the fork+exec +pairing. When adding further resources on the fly, to an existing object h= olding +locks, this will be done from the libvirtd process. + +:: + + virLockManagerParam params[] =3D { + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UUID, + .key =3D "uuid", + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_STRING, + .key =3D "name", + .value =3D { .str =3D dom->def->name }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT, + .key =3D "id", + .value =3D { .i =3D dom->def->id }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT, + .key =3D "pid", + .value =3D { .i =3D dom->pid }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING, + .key =3D "uri", + .value =3D { .cstr =3D driver->uri }, + }, + }; + mgr =3D virLockManagerNew(lockPlugin, + VIR_LOCK_MANAGER_TYPE_DOMAIN, + ARRAY_CARDINALITY(params), + params, + 0))); + + foreach (initial disks) + virLockManagerAddResource(mgr, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + $path, 0, NULL, $flags); + + if (virLockManagerAcquire(lock, NULL, 0) < 0); + ...abort... + +Lock release +~~~~~~~~~~~~ + +The locks are all implicitly released when the process that acquired them = exits, +however, a process may voluntarily give up the lock by running + +:: + + char *state =3D NULL; + virLockManagerParam params[] =3D { + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UUID, + .key =3D "uuid", + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_STRING, + .key =3D "name", + .value =3D { .str =3D dom->def->name }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT, + .key =3D "id", + .value =3D { .i =3D dom->def->id }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT, + .key =3D "pid", + .value =3D { .i =3D dom->pid }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING, + .key =3D "uri", + .value =3D { .cstr =3D driver->uri }, + }, + }; + mgr =3D virLockManagerNew(lockPlugin, + VIR_LOCK_MANAGER_TYPE_DOMAIN, + ARRAY_CARDINALITY(params), + params, + 0))); + + foreach (initial disks) + virLockManagerAddResource(mgr, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + $path, 0, NULL, $flags); + + virLockManagerRelease(mgr, & state, 0); + +The returned state string can be passed to the ``virLockManagerAcquire`` m= ethod +to later re-acquire the exact same locks. This state transfer is commonly = used +when performing live migration of virtual machines. By validating the stat= e the +lock manager can ensure no other VM has re-acquire the same locks on a dif= ferent +host. The state can also be obtained without releasing the locks, by calli= ng the +``virLockManagerInquire`` method. diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.= build index 5f61f5dba4..8195d7caf0 100644 --- a/docs/kbase/internals/meson.build +++ b/docs/kbase/internals/meson.build @@ -2,6 +2,7 @@ docs_kbase_internals_files =3D [ 'command', 'eventloop', 'incremental-backup', + 'locking', 'migration', ] diff --git a/docs/kbase/meson.build b/docs/kbase/meson.build index 269bf64a94..eb9c9544d6 100644 --- a/docs/kbase/meson.build +++ b/docs/kbase/meson.build @@ -36,7 +36,6 @@ foreach name : docs_kbase_files } endforeach -# keep the XSLT processing code block in sync with docs/meson.build # --- begin of XSLT processing --- --=20 2.35.1 From nobody Sat May 11 06:37:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340068; cv=none; d=zohomail.com; s=zohoarc; b=UCqYz3xZeRUziNnLEA43k1x8b90/7iM5k+EUYSNCQC3tChhUwAxX/SPlYCIP776NiPnruG5ORVjE7oNXrbO0zFKy1s004O++GN7uKio5rLl39xWaJmkOfrdh6XxLtthLYEQPDm4TAumJQc9hv6oCsQm0SBnAmB2YOpVWYcvHpGM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340068; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=sehjY60NtXOZPMh20iNI0L4djCmP8DOvaZPbFTKsXEY=; b=PWKv5iLv8r2NNgEKM6ZM+5c3/semWewwf9RZBJ/Ja2XgijvXwvv2WymtobF/QVaxDC7Y+ufD/oBwzhOBWNGu9cA3vx7akUWSqtV/k/JklLA9pMV5886ooKT7V+qt2t8vFnXynTFvFDiBDNuQJDJ1Hq+sghRf9ooeFoc0WN9oboc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 164934006818120.649136408190543; Thu, 7 Apr 2022 07:01:08 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-497-IwU-8NINPjmzalu1E1c_iw-1; Thu, 07 Apr 2022 10:01:03 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 161591066560; Thu, 7 Apr 2022 14:00:48 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id F13C1404729C; Thu, 7 Apr 2022 14:00:47 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id A07681949761; Thu, 7 Apr 2022 14:00:47 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 80EA51940350 for ; Thu, 7 Apr 2022 14:00:45 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 6C910403153; Thu, 7 Apr 2022 14:00:45 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id F1F42401DB1 for ; Thu, 7 Apr 2022 14:00:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340067; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=sehjY60NtXOZPMh20iNI0L4djCmP8DOvaZPbFTKsXEY=; b=duUtwCB2b5ROTcKrcgHhuDIWCUhRfoLkgJd59AXTlQ70EvVATygdH34nDwQTKiB8dm1sJW D5y8o7UHqoQxk4CXvNd9Wr+oaLWKwJ54RYfxOSXm1OETxotHme4wTMw/7RLK63EFLji07J uhhl61VLMPuKosIUk3Do/E3IfWxIt2M= X-MC-Unique: IwU-8NINPjmzalu1E1c_iw-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 08/11] docs: Convert 'internals/rpc' page to RST and move it to 'kbase/internals' Date: Thu, 7 Apr 2022 16:00:30 +0200 Message-Id: <4b67323b57fe4049cbfe0dfa94b140007f5f6f71.1649339910.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340069642100003 Content-Type: text/plain; charset="utf-8"; x-default="true" Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/api.rst | 2 +- docs/docs.rst | 3 - docs/internals/meson.build | 1 - docs/internals/rpc.html.in | 914 ------------------------------- docs/kbase/index.rst | 3 + docs/kbase/internals/meson.build | 1 + docs/kbase/internals/rpc.rst | 781 ++++++++++++++++++++++++++ 7 files changed, 786 insertions(+), 919 deletions(-) delete mode 100644 docs/internals/rpc.html.in create mode 100644 docs/kbase/internals/rpc.rst diff --git a/docs/api.rst b/docs/api.rst index d9f01fb403..325b9b840c 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -219,7 +219,7 @@ Daemon and Remote Access Access to libvirt drivers is primarily handled by the libvirtd daemon through the `remote `__ driver via an -`RPC `__. Some hypervisors do support client-side +`RPC `__. Some hypervisors do support client-side connections and responses, such as Test, OpenVZ, VMware, VirtualBox (vbox), ESX, Hyper-V, Xen, and Virtuozzo. The libvirtd daemon service is started on the host at system boot time and can also be restarted at any diff --git a/docs/docs.rst b/docs/docs.rst index 3387dacce8..0a698913be 100644 --- a/docs/docs.rst +++ b/docs/docs.rst @@ -154,9 +154,6 @@ Project development `API extensions `__ Adding new public libvirt APIs -`RPC protocol & APIs `__ - RPC protocol information and API / dispatch guide - `Functional testing `__ Testing libvirt with `TCK test suite `__ and diff --git a/docs/internals/meson.build b/docs/internals/meson.build index 68a2e70a3d..cbf0623c08 100644 --- a/docs/internals/meson.build +++ b/docs/internals/meson.build @@ -1,5 +1,4 @@ internals_in_files =3D [ - 'rpc', ] html_xslt_gen_install_dir =3D docs_html_dir / 'internals' diff --git a/docs/internals/rpc.html.in b/docs/internals/rpc.html.in deleted file mode 100644 index ceb7dba5f2..0000000000 --- a/docs/internals/rpc.html.in +++ /dev/null @@ -1,914 +0,0 @@ - - - - -

        libvirt RPC infrastructure

        - -
          - -

          - libvirt includes a basic protocol and code to implement - an extensible, secure client/server RPC service. This was - originally designed for communication between the libvirt - client library and the libvirtd daemon, but the code is - now isolated to allow reuse in other areas of libvirt code. - This document provides an overview of the protocol and - structure / operation of the internal RPC library APIs. -

          - - -

          RPC protocol

          - -

          - libvirt uses a simple, variable length, packet based RPC protocol. - All structured data within packets is encoded using the - XDR standard - as currently defined by RFC 4506. - On any connection running the RPC protocol, there can be multiple - programs active, each supporting one or more versions. A program - defines a set of procedures that it supports. The procedures can - support call+reply method invocation, asynchronous events, - and generic data streams. Method invocations can be overlapped, - so waiting for a reply to one will not block the receipt of the - reply to another outstanding method. The protocol was loosely - inspired by the design of SunRPC. The definition of the RPC - protocol is in the file src/rpc/virnetprotocol.x - in the libvirt source tree. -

          - -

          Packet framing

          - -

          - On the wire, there is no explicit packet framing marker. Instead - each packet is preceded by an unsigned 32-bit integer giving - the total length of the packet in bytes. This length includes - the 4-bytes of the length word itself. Conceptually the framing - looks like this: -

          - -
          -|~~~   Packet 1   ~~~|~~~   Packet 2   ~~~|~~~  Packet 3    ~~~|~~~
          -
          -+-------+------------+-------+------------+-------+------------+...
          -| n=3DU32 | (n-4) * U8 | n=3DU32 | (n-4) * U8 | n=3DU32 | (n-4) * U8 |
          -+-------+------------+-------+------------+-------+------------+...
          -
          -|~ Len ~|~   Data   ~|~ Len ~|~   Data   ~|~ Len ~|~   Data   ~|~
          -
          -
          - -

          Packet data

          - -

          - The data in each packet is split into two parts, a short - fixed length header, followed by a variable length payload. - So a packet from the illustration above is more correctly - shown as -

          - -
          -
          -+-------+-------------+---------------....---+
          -| n=3DU32 | 6*U32       | (n-(7*4))*U8         |
          -+-------+-------------+---------------....---+
          -
          -|~ Len ~|~  Header   ~|~  Payload     ....  ~|
          -
          - - -

          Packet header

          -

          - The header contains 6 fields, encoded as signed/unsigned 32-bit - integers. -

          - -
          -+---------------+
          -| program=3DU32   |
          -+---------------+
          -| version=3DU32   |
          -+---------------+
          -| procedure=3DS32 |
          -+---------------+
          -| type=3DS32      |
          -+---------------+
          -| serial=3DU32    |
          -+---------------+
          -| status=3DS32    |
          -+---------------+
          -    
          - -
          -
          program
          -
          - This is an arbitrarily chosen number that will uniquely - identify the "service" running over the stream. -
          -
          version
          -
          - This is the version number of the program, by convention - starting from '1'. When an incompatible change is made - to a program, the version number is incremented. Ideally - both versions will then be supported on the wire in - parallel for backwards compatibility. -
          -
          procedure
          -
          - This is an arbitrarily chosen number that will uniquely - identify the method call, or event associated with the - packet. By convention, procedure numbers start from 1 - and are assigned monotonically thereafter. -
          -
          type
          -
          -

          - This can be one of the following enumeration values -

          -
            -
          1. call: invocation of a method call
          2. -
          3. reply: completion of a method call
          4. -
          5. event: an asynchronous event
          6. -
          7. stream: control info or data from a stream
          8. -
          -
          -
          serial
          -
          - This is a number that starts from 1 and increases - each time a method call packet is sent. A reply or - stream packet will have a serial number matching the - original method call packet serial. Events always - have the serial number set to 0. -
          -
          status
          -
          -

          - This can one of the following enumeration values -

          -
            -
          1. ok: a normal packet. this is always set for method calls or = events. - For replies it indicates successful completion of the method. = For - streams it indicates confirmation of the end of file on the st= ream.
          2. -
          3. error: for replies this indicates that the method call failed - and error information is being returned. For streams this indi= cates - that not all data was sent and the stream has aborted
          4. -
          5. continue: for streams this indicates that further data packe= ts - will be following
          6. -
          -
          -
          - -

          Packet payload

          - -

          - The payload of a packet will vary depending on the type - and status fields from the header. -

          - -
            -
          • type=3Dcall: the in parameters for the method call, XDR encoded<= /li> -
          • type=3Dcall-with-fds: number of file handles, then the in parame= ters for the method call, XDR encoded, followed by the file handles
          • -
          • type=3Dreply+status=3Dok: the return value and/or out parameters= for the method call, XDR encoded
          • -
          • type=3Dreply+status=3Derror: the error information for the metho= d, a virErrorPtr XDR encoded
          • -
          • type=3Dreply-with-fds+status=3Dok: number of file handles, the r= eturn value and/or out parameters for the method call, XDR encoded, followe= d by the file handles
          • -
          • type=3Dreply-with-fds+status=3Derror: number of file handles, th= e error information for the method, a virErrorPtr XDR encoded, followed by = the file handles
          • -
          • type=3Devent: the parameters for the event, XDR encoded
          • -
          • type=3Dstream+status=3Dok: no payload
          • -
          • type=3Dstream+status=3Derror: the error information for the meth= od, a virErrorPtr XDR encoded
          • -
          • type=3Dstream+status=3Dcontinue: the raw bytes of data for the s= tream. No XDR encoding
          • -
          - -

          - With the two packet types that support passing file descriptors, in - between the header and the payload there will be a 4-byte integer - specifying the number of file descriptors which are being sent. - The actual file handles are sent after the payload has been sent. - Each file handle has a single dummy byte transmitted as a carrier - for the out of band file descriptor. While the sender should always - send '\0' as the dummy byte value, the receiver ought to ignore the - value for the sake of robustness. -

          - -

          - For the exact payload information for each procedure, consult the XD= R protocol - definition for the program+version in question -

          - -

          Wire examples

          - -

          - The following diagrams illustrate some example packet exchanges - between a client and server -

          - -

          Method call

          - -

          - A single method call and successful - reply, for a program=3D8, version=3D1, procedure=3D3, which 10 bytes= worth - of input args, and 4 bytes worth of return values. The overall input - packet length is 4 + 24 + 10 =3D=3D 38, and output packet length 32 -

          - -
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. |  --> S  (call)
          -       +--+-----------------------+-----------+
          -
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo |  <-- S  (reply)
          -       +--+-----------------------+--------+
          -    
          - -

          Method call with error

          - -

          - An unsuccessful method call will instead return an error object -

          - -
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. |  --> S   (call)
          -       +--+-----------------------+-----------+
          -
          -       +--+-----------------------+--------------------------+
          -C <--  |48| 8 | 1 | 3 | 2 | 1 | 0 | .o.oOo.o.oOo.o.oOo.o.oOo |  <-- =
          S  (error)
          -       +--+-----------------------+--------------------------+
          -    
          - -

          Method call with upload stream - -

          - A method call which also involves uploading some data over - a stream will result in -

          - -
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. |  --> S  (call)
          -       +--+-----------------------+-----------+
          -
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo |  <-- S  (reply)
          -       +--+-----------------------+--------+
          -
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       ...
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+
          -C -->  |24| 8 | 1 | 3 | 3 | 1 | 0 | --> S  (stream finish)
          -       +--+-----------------------+
          -       +--+-----------------------+
          -C <--  |24| 8 | 1 | 3 | 3 | 1 | 0 | <-- S  (stream finish)
          -       +--+-----------------------+
          -    
          - -

          Method call bidirectional stream<= /h4> - -

          - A method call which also involves a bi-directional stream will - result in -

          - -
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. |  --> S  (call)
          -       +--+-----------------------+-----------+
          -
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo |  <-- S  (reply)
          -       +--+-----------------------+--------+
          -
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C <--  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  <-- S =
           (stream data down)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C <--  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  <-- S =
           (stream data down)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C <--  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  <-- S =
           (stream data down)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C <--  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  <-- S =
           (stream data down)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       ..
          -       +--+-----------------------+-------------....-------+
          -C -->  |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. |  --> S =
           (stream data up)
          -       +--+-----------------------+-------------....-------+
          -       +--+-----------------------+
          -C -->  |24| 8 | 1 | 3 | 3 | 1 | 0 | --> S  (stream finish)
          -       +--+-----------------------+
          -       +--+-----------------------+
          -C <--  |24| 8 | 1 | 3 | 3 | 1 | 0 | <-- S  (stream finish)
          -       +--+-----------------------+
          -    
          - - -

          Method calls overlapping

          -
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. |  --> S  (call 1)
          -       +--+-----------------------+-----------+
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 2 | 0 | .o.oOo.o. |  --> S  (call 2)
          -       +--+-----------------------+-----------+
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 2 | 0 | .o.oOo |  <-- S  (reply 2)
          -       +--+-----------------------+--------+
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 3 | 0 | .o.oOo.o. |  --> S  (call 3)
          -       +--+-----------------------+-----------+
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 3 | 0 | .o.oOo |  <-- S  (reply 3)
          -       +--+-----------------------+--------+
          -       +--+-----------------------+-----------+
          -C -->  |38| 8 | 1 | 3 | 0 | 4 | 0 | .o.oOo.o. |  --> S  (call 4)
          -       +--+-----------------------+-----------+
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo |  <-- S  (reply 1)
          -       +--+-----------------------+--------+
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 4 | 0 | .o.oOo |  <-- S  (reply 4)
          -       +--+-----------------------+--------+
          -    
          - -

          Method call with passed FD

          - -

          - A single method call with 2 passed file descriptors and successful - reply, for a program=3D8, version=3D1, procedure=3D3, which 10 bytes= worth - of input args, and 4 bytes worth of return values. The number of - file descriptors is encoded as a 32-bit int. Each file descriptor - then has a 1 byte dummy payload. The overall input - packet length is 4 + 24 + 4 + 2 + 10 =3D=3D 44, and output packet le= ngth 32. -

          - -
          -       +--+-----------------------+---------------+-------+
          -C -->  |44| 8 | 1 | 3 | 0 | 1 | 0 | 2 | .o.oOo.o. | 0 | 0 |  --> S  =
          (call)
          -       +--+-----------------------+---------------+-------+
          -
          -       +--+-----------------------+--------+
          -C <--  |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo |  <-- S  (reply)
          -       +--+-----------------------+--------+
          -    
          - - -

          RPC security

          - -

          - There are various things to consider to ensure an implementation - of the RPC protocol can be satisfactorily secured -

          - -

          Authentication/encryption

          - -

          - The basic RPC protocol does not define or require any specific - authentication/encryption capabilities. A generic solution to - providing encryption for the protocol is to run the protocol - over a TLS encrypted data stream. x509 certificate checks can - be done to form a crude authentication mechanism. It is also - possible for an RPC program to negotiate an encryption / - authentication capability, such as SASL, which may then also - provide per-packet data encryption. Finally the protocol data - stream can of course be tunnelled over transports such as SSH. -

          - -

          Data limits

          - -

          - Although the protocol itself defines many arbitrary sized data value= s in the - payloads, to avoid denial of service attack there are a number of si= ze limit - checks prior to encoding or decoding data. There is a limit on the m= aximum - size of a single RPC message, limit on the maximum string length, an= d limits - on any other parameter which uses a variable length array. These lim= its can - be raised, subject to agreement between client/server, without other= wise - breaking compatibility of the RPC data on the wire. -

          - -

          Data validation

          - -

          - It is important that all data be fully validated before performing - any actions based on the data. When reading an RPC packet, the - first four bytes must be read and the max packet size limit validate= d, - before any attempt is made to read the variable length packet data. - After a complete packet has been read, the header must be decoded - and all 6 fields fully validated, before attempting to dispatch - the payload. Once dispatched, the payload can be decoded and passed - on to the appropriate API for execution. The RPC code must not take - any action based on the payload, since it has no way to validate - the semantics of the payload data. It must delegate this to the - execution API (e.g. corresponding libvirt public API). -

          - -

          RPC internal APIs

          - -

          - The generic internal RPC library code lives in the src/rpc/ - directory of the libvirt source tree. Unless otherwise noted, the - objects are all threadsafe. The core object types and their - purposes are: -

          - -

          Overview of RPC objects

          - -

          - The following is a high level overview of the role of each - of the main RPC objects -

          - -
          -
          virNetSASLContext * (virnetsaslcontext.h)
          -
          The virNetSASLContext APIs maintain SASL state for a network - service (server or client). This is primarily used on the server - to provide an access control list of SASL usernames permitted as - clients. -
          - -
          virNetSASLSession * (virnetsaslcontext.h)
          -
          The virNetSASLSession APIs maintain SASL state for a single - network connection (socket). This is used to perform the multi-step - SASL handshake and perform encryption/decryption of data once - authenticated, via integration with virNetSocket. -
          - -
          virNetTLSContext * (virnettlscontext.h)
          -
          The virNetTLSContext APIs maintain TLS state for a network - service (server or client). This is primarily used on the server - to provide an access control list of x509 distinguished names, as - well as diffie-hellman keys. It can also do validation of - x509 certificates prior to initiating a connection, in order - to improve detection of configuration errors. -
          - -
          virNetTLSSession * (virnettlscontext.h)
          -
          The virNetTLSSession APIs maintain TLS state for a single - network connection (socket). This is used to perform the multi-step - TLS handshake and perform encryption/decryption of data once - authenticated, via integration with virNetSocket. -
          - -
          virNetSocket * (virnetsocket.h)
          -
          The virNetSocket APIs provide a higher level wrapper around - the raw BSD sockets and getaddrinfo APIs. They allow for creation - of both server and client sockets. Data transports supported are - TCP, UNIX, SSH tunnel or external command tunnel. Internally the - TCP socket impl uses the getaddrinfo info APIs to ensure correct - protocol-independent behaviour, thus supporting both IPv4 and IPv6. - The socket APIs can be associated with a virNetSASLSession *or - virNetTLSSession *object to allow seamless encryption/decryption - of all writes and reads. For UNIX sockets it is possible to obtain - the remote client user ID and process ID. Integration with the - libvirt event loop also allows use of callbacks for notification - of various I/O conditions -
          - -
          virNetMessage * (virnetmessage.h)
          -
          The virNetMessage APIs provide a wrapper around the libxdr - API calls, to facilitate processing and creation of RPC - packets. There are convenience APIs for encoding/encoding the - packet headers, encoding/decoding the payload using an XDR - filter, encoding/decoding a raw payload (for streams), and - encoding a virErrorPtr object. There is also a means to - add to/serve from a linked-list queue of messages.
          - -
          virNetClient * (virnetclient.h)
          -
          The virNetClient APIs provide a way to connect to a - remote server and run one or more RPC protocols over - the connection. Connections can be made over TCP, UNIX - sockets, SSH tunnels, or external command tunnels. There - is support for both TLS and SASL session encryption. - The client also supports management of multiple data streams - over each connection. Each client object can be used from - multiple threads concurrently, with method calls/replies - being interleaved on the wire as required. -
          - -
          virNetClientProgram * (virnetclientprogram.h)
          -
          The virNetClientProgram APIs are used to register a - program+version with the connection. This then enables - invocation of method calls, receipt of asynchronous - events and use of data streams, within that program+version. - When created a set of callbacks must be supplied to take - care of dispatching any incoming asynchronous events. -
          - -
          virNetClientStream * (virnetclientstream.h)
          -
          The virNetClientStream APIs are used to control transmission and - receipt of data over a stream active on a client. Streams provide - a low latency, unlimited length, bi-directional raw data exchange - mechanism layered over the RPC connection -
          - -
          virNetServer * (virnetserver.h)
          -
          The virNetServer APIs are used to manage a network server. A - server exposed one or more programs, over one or more services. - It manages multiple client connections invoking multiple RPC - calls in parallel, with dispatch across multiple worker threads. -
          - -
          virNetDaemon * (virnetdaemon.h)
          -
          The virNetDaemon APIs are used to manage a daemon process. A - daemon is a process that might expose one or more servers. It - handles most process-related details, network-related should - be part of the underlying server. -
          - -
          virNetServerClient * (virnetserverclient.h)
          -
          The virNetServerClient APIs are used to manage I/O related - to a single client network connection. It handles initial - validation and routing of incoming RPC packets, and transmission - of outgoing packets. -
          - -
          virNetServerProgram * (virnetserverprogram.h)
          -
          The virNetServerProgram APIs are used to provide the implementat= ion - of a single program/version set. Primarily this includes a set of - callbacks used to actually invoke the APIs corresponding to - program procedure numbers. It is responsible for all the serializa= tion - of payloads to/from XDR.
          - -
          virNetServerService * (virnetserverservice.h)
          -
          The virNetServerService APIs are used to connect the server to - one or more network protocols. A single service may involve multip= le - sockets (ie both IPv4 and IPv6). A service also has an associated - authentication policy for incoming clients. -
          -
          - -

          Client RPC dispatch

          - -

          - The client RPC code must allow for multiple overlapping RPC method - calls to be invoked, transmission and receipt of data for multiple - streams and receipt of asynchronous events. Understandably this - involves coordination of multiple threads. -

          - -

          - The core requirement in the client dispatch code is that only - one thread is allowed to be performing I/O on the socket at - any time. This thread is said to be "holding the buck". When - any other thread comes along and needs to do I/O it must place - its packets on a queue and delegate processing of them to the - thread that has the buck. This thread will send out the method - call, and if it sees a reply will pass it back to the waiting - thread. If the other thread's reply hasn't arrived, by the time - the main thread has got its own reply, then it will transfer - responsibility for I/O to the thread that has been waiting the - longest. It is said to be "passing the buck" for I/O. -

          - -

          - When no thread is performing any RPC method call, or sending - stream data there is still a need to monitor the socket for - incoming I/O related to asynchronous events, or stream data - receipt. For this task, a watch is registered with the event - loop which triggers whenever the socket is readable. This - watch is automatically disabled whenever any other thread - grabs the buck, and re-enabled when the buck is released. -

          - -

          Example with buck passing

          - -

          - In the first example, a second thread issues an API call - while the first thread holds the buck. The reply to the - first call arrives first, so the buck is passed to the - second thread. -

          - -
          -        Thread-1
          -           |
          -           V
          -       Call API1()
          -           |
          -           V
          -       Grab Buck
          -           |           Thread-2
          -           V              |
          -       Send method1       V
          -           |          Call API2()
          -           V              |
          -        Wait I/O          V
          -           |<--------Queue method2
          -           V              |
          -       Send method2       V
          -           |          Wait for buck
          -           V              |
          -        Wait I/O          |
          -           |              |
          -           V              |
          -       Recv reply1        |
          -           |              |
          -           V              |
          -       Pass the buck----->|
          -           |              V
          -           V           Wait I/O
          -       Return API1()      |
          -                          V
          -                      Recv reply2
          -                          |
          -                          V
          -                     Release the buck
          -                          |
          -                          V
          -                      Return API2()
          -    
          - -

          Example without buck passing - -

          - In this second example, a second thread issues an API call - which is sent and replied to, before the first thread's - API call has completed. The first thread thus notifies - the second that its reply is ready, and there is no need - to pass the buck -

          - -
          -        Thread-1
          -           |
          -           V
          -       Call API1()
          -           |
          -           V
          -       Grab Buck
          -           |           Thread-2
          -           V              |
          -       Send method1       V
          -           |          Call API2()
          -           V              |
          -        Wait I/O          V
          -           |<--------Queue method2
          -           V              |
          -       Send method2       V
          -           |          Wait for buck
          -           V              |
          -        Wait I/O          |
          -           |              |
          -           V              |
          -       Recv reply2        |
          -           |              |
          -           V              |
          -      Notify reply2------>|
          -           |              V
          -           V          Return API2()
          -        Wait I/O
          -           |
          -           V
          -       Recv reply1
          -           |
          -           V
          -     Release the buck
          -           |
          -           V
          -       Return API1()
          -    
          - -

          Example with async events

          - -

          - In this example, only one thread is present and it has to - deal with some async events arriving. The events are actually - dispatched to the application from the event loop thread -

          - -
          -        Thread-1
          -           |
          -           V
          -       Call API1()
          -           |
          -           V
          -       Grab Buck
          -           |
          -           V
          -       Send method1
          -           |
          -           V
          -        Wait I/O
          -           |          Event thread
          -           V              ...
          -       Recv event1         |
          -           |               V
          -           V          Wait for timer/fd
          -       Queue event1        |
          -           |               V
          -           V           Timer fires
          -        Wait I/O           |
          -           |               V
          -           V           Emit event1
          -       Recv reply1         |
          -           |               V
          -           V          Wait for timer/fd
          -       Return API1()       |
          -                          ...
          -    
          - -

          Server RPC dispatch

          - -

          - The RPC server code must support receipt of incoming RPC requests fr= om - multiple client connections, and parallel processing of all RPC - requests, even many from a single client. This goal is achieved thro= ugh - a combination of event driven I/O, and multiple processing threads. -

          - -

          - The main libvirt event loop thread is responsible for performing all - socket I/O. It will read incoming packets from clients and will - transmit outgoing packets to clients. It will handle the I/O to/from - streams associated with client API calls. When doing client I/O it - will also pass the data through any applicable encryption layer - (through use of the virNetSocket / virNetTLSSession and virNetSASLSe= ssion - integration). What is paramount is that the event loop thread never - do any task that can take a non-trivial amount of time. -

          - -

          - When reading packets, the event loop will first read the 4 byte leng= th - word. This is validated to make sure it does not exceed the maximum - permissible packet size, and the client is set to allow receipt of t= he - rest of the packet data. Once a complete packet has been received, t= he - next step is to decode the RPC header. The header is validated to - ensure the request is sensible, ie the server should not receive a - method reply from a client. If the client has not yet authenticated, - an access control list check is also performed to make sure the proc= edure - is one of those allowed prior to auth. If the packet is a method - call, it will be placed on a global processing queue. The event loop - thread is now done with the packet for the time being. -

          - -

          - The server has a pool of worker threads, which wait for method call - packets to be queued. One of them will grab the new method call off - the queue for processing. The first step is to decode the payload of - the packet to extract the method call arguments. The worker does not - attempt to do any semantic validation of the arguments, except to ma= ke - sure the size of any variable length fields is below defined limits. -

          - -

          - The worker now invokes the libvirt API call that corresponds to the - procedure number in the packet header. The worker is thus kept busy - until the API call completes. The implementation of the API call - is responsible for doing semantic validation of parameters and any - MAC security checks on the objects affected. -

          - -

          - Once the API call has completed, the worker thread will take the - return value and output parameters, or error object and encode - them into a reply packet. Again it does not attempt to do any - semantic validation of output data, aside from variable length - field limit checks. The worker thread puts the reply packet on - the transmission queue for the client. The worker is now finished - and goes back to wait for another incoming method call. -

          - -

          - The main event loop is back in charge and when the client socket - becomes writable, it will start sending the method reply packet - back to the client. -

          - -

          - At any time the libvirt connection object can emit asynchronous - events. These are handled by callbacks in the main event thread. - The callback will simply encode the event parameters into a new - data packet and place the packet on the client transmission - queue. -

          - -

          - Incoming and outgoing stream packets are also directly handled - by the main event thread. When an incoming stream packet is - received, instead of placing it in the global dispatch queue - for the worker threads, it is sidetracked into a per-stream - processing queue. When the stream becomes writable, queued - incoming stream packets will be processed, passing their data - payload on the stream. Conversely when the stream becomes - readable, chunks of data will be read from it, encoded into - new outgoing packets, and placed on the client's transmit - queue. -

          - -

          Example with overlapping methods

          - -

          - This example illustrates processing of two incoming methods with - overlapping execution -

          - -
          -   Event thread    Worker 1       Worker 2
          -       |               |              |
          -       V               V              V
          -    Wait I/O       Wait Job       Wait Job
          -       |               |              |
          -       V               |              |
          -   Recv method1        |              |
          -       |               |              |
          -       V               |              |
          -   Queue method1       V              |
          -       |          Serve method1       |
          -       V               |              |
          -    Wait I/O           V              |
          -       |           Call API1()        |
          -       V               |              |
          -   Recv method2        |              |
          -       |               |              |
          -       V               |              |
          -   Queue method2       |              V
          -       |               |         Serve method2
          -       V               V              |
          -    Wait I/O      Return API1()       V
          -       |               |          Call API2()
          -       |               V              |
          -       V         Queue reply1         |
          -   Send reply1         |              |
          -       |               V              V
          -       V           Wait Job       Return API2()
          -    Wait I/O           |              |
          -       |              ...             V
          -       V                          Queue reply2
          -   Send reply2                        |
          -       |                              V
          -       V                          Wait Job
          -    Wait I/O                          |
          -       |                             ...
          -      ...
          -    
          - -

          Example with stream data

          - -

          - This example illustrates processing of stream data -

          - -
          -   Event thread
          -       |
          -       V
          -    Wait I/O
          -       |
          -       V
          -   Recv stream1
          -       |
          -       V
          -   Queue stream1
          -       |
          -       V
          -    Wait I/O
          -       |
          -       V
          -   Recv stream2
          -       |
          -       V
          -   Queue stream2
          -       |
          -       V
          -    Wait I/O
          -       |
          -       V
          -   Write stream1
          -       |
          -       V
          -   Write stream2
          -       |
          -       V
          -    Wait I/O
          -       |
          -      ...
          -    
          - - - diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 2125bf4252..31711d908b 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -94,3 +94,6 @@ Internals `Lock managers `__ Use lock managers to protect disk content + +`RPC protocol & APIs `__ + RPC protocol information and API / dispatch guide diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.= build index 8195d7caf0..879c4b2de8 100644 --- a/docs/kbase/internals/meson.build +++ b/docs/kbase/internals/meson.build @@ -4,6 +4,7 @@ docs_kbase_internals_files =3D [ 'incremental-backup', 'locking', 'migration', + 'rpc', ] diff --git a/docs/kbase/internals/rpc.rst b/docs/kbase/internals/rpc.rst new file mode 100644 index 0000000000..02bc880044 --- /dev/null +++ b/docs/kbase/internals/rpc.rst @@ -0,0 +1,781 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +libvirt RPC infrastructure +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +.. contents:: + +libvirt includes a basic protocol and code to implement an extensible, sec= ure +client/server RPC service. This was originally designed for communication +between the libvirt client library and the libvirtd daemon, but the code i= s now +isolated to allow reuse in other areas of libvirt code. This document prov= ides +an overview of the protocol and structure / operation of the internal RPC +library APIs. + +RPC protocol +------------ + +libvirt uses a simple, variable length, packet based RPC protocol. All +structured data within packets is encoded using the `XDR +standard `__ as +currently defined by `RFC 4506 `__. O= n any +connection running the RPC protocol, there can be multiple programs active= , each +supporting one or more versions. A program defines a set of procedures tha= t it +supports. The procedures can support call+reply method invocation, asynchr= onous +events, and generic data streams. Method invocations can be overlapped, so +waiting for a reply to one will not block the receipt of the reply to anot= her +outstanding method. The protocol was loosely inspired by the design of Sun= RPC. +The definition of the RPC protocol is in the file ``src/rpc/virnetprotocol= .x`` +in the libvirt source tree. + +`Packet framing `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On the wire, there is no explicit packet framing marker. Instead each pack= et is +preceded by an unsigned 32-bit integer giving the total length of the pack= et in +bytes. This length includes the 4-bytes of the length word itself. Concept= ually +the framing looks like this: + +:: + + |~~~ Packet 1 ~~~|~~~ Packet 2 ~~~|~~~ Packet 3 ~~~|~~~ + + +-------+------------+-------+------------+-------+------------+... + | n=3DU32 | (n-4) * U8 | n=3DU32 | (n-4) * U8 | n=3DU32 | (n-4) * U8 | + +-------+------------+-------+------------+-------+------------+... + + |~ Len ~|~ Data ~|~ Len ~|~ Data ~|~ Len ~|~ Data ~|~ + +`Packet data `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The data in each packet is split into two parts, a short fixed length head= er, +followed by a variable length payload. So a packet from the illustration a= bove +is more correctly shown as + +:: + + + +-------+-------------+---------------....---+ + | n=3DU32 | 6*U32 | (n-(7*4))*U8 | + +-------+-------------+---------------....---+ + + |~ Len ~|~ Header ~|~ Payload .... ~| + +`Packet header `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The header contains 6 fields, encoded as signed/unsigned 32-bit integers. + +:: + + +---------------+ + | program=3DU32 | + +---------------+ + | version=3DU32 | + +---------------+ + | procedure=3DS32 | + +---------------+ + | type=3DS32 | + +---------------+ + | serial=3DU32 | + +---------------+ + | status=3DS32 | + +---------------+ + +``program`` + This is an arbitrarily chosen number that will uniquely identify the + "service" running over the stream. +``version`` + This is the version number of the program, by convention starting from = '1'. + When an incompatible change is made to a program, the version number is + incremented. Ideally both versions will then be supported on the wire in + parallel for backwards compatibility. +``procedure`` + This is an arbitrarily chosen number that will uniquely identify the me= thod + call, or event associated with the packet. By convention, procedure num= bers + start from 1 and are assigned monotonically thereafter. +``type`` + This can be one of the following enumeration values + + #. call: invocation of a method call + #. reply: completion of a method call + #. event: an asynchronous event + #. stream: control info or data from a stream + +``serial`` + This is a number that starts from 1 and increases each time a method ca= ll + packet is sent. A reply or stream packet will have a serial number matc= hing + the original method call packet serial. Events always have the serial n= umber + set to 0. +``status`` + This can one of the following enumeration values + + #. ok: a normal packet. this is always set for method calls or events. = For + replies it indicates successful completion of the method. For stream= s it + indicates confirmation of the end of file on the stream. + #. error: for replies this indicates that the method call failed and er= ror + information is being returned. For streams this indicates that not a= ll + data was sent and the stream has aborted + #. continue: for streams this indicates that further data packets will = be + following + +`Packet payload `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The payload of a packet will vary depending on the ``type`` and ``status`` +fields from the header. + +- type=3Dcall: the in parameters for the method call, XDR encoded +- type=3Dcall-with-fds: number of file handles, then the in parameters fo= r the + method call, XDR encoded, followed by the file handles +- type=3Dreply+status=3Dok: the return value and/or out parameters for th= e method + call, XDR encoded +- type=3Dreply+status=3Derror: the error information for the method, a vi= rErrorPtr + XDR encoded +- type=3Dreply-with-fds+status=3Dok: number of file handles, the return v= alue + and/or out parameters for the method call, XDR encoded, followed by the= file + handles +- type=3Dreply-with-fds+status=3Derror: number of file handles, the error + information for the method, a virErrorPtr XDR encoded, followed by the = file + handles +- type=3Devent: the parameters for the event, XDR encoded +- type=3Dstream+status=3Dok: no payload +- type=3Dstream+status=3Derror: the error information for the method, a v= irErrorPtr + XDR encoded +- type=3Dstream+status=3Dcontinue: the raw bytes of data for the stream. = No XDR + encoding + +With the two packet types that support passing file descriptors, in betwee= n the +header and the payload there will be a 4-byte integer specifying the numbe= r of +file descriptors which are being sent. The actual file handles are sent af= ter +the payload has been sent. Each file handle has a single dummy byte transm= itted +as a carrier for the out of band file descriptor. While the sender should = always +send '\0' as the dummy byte value, the receiver ought to ignore the value = for +the sake of robustness. + +For the exact payload information for each procedure, consult the XDR prot= ocol +definition for the program+version in question + +Wire examples +~~~~~~~~~~~~~ + +The following diagrams illustrate some example packet exchanges between a = client +and server + +Method call +^^^^^^^^^^^ + +A single method call and successful reply, for a program=3D8, version=3D1, +procedure=3D3, which 10 bytes worth of input args, and 4 bytes worth of re= turn +values. The overall input packet length is 4 + 24 + 10 =3D=3D 38, and outp= ut packet +length 32 + +:: + + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. | --> S (call) + +--+-----------------------+-----------+ + + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo | <-- S (reply) + +--+-----------------------+--------+ + +Method call with error +^^^^^^^^^^^^^^^^^^^^^^ + +An unsuccessful method call will instead return an error object + +:: + + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. | --> S (call) + +--+-----------------------+-----------+ + + +--+-----------------------+--------------------------+ + C <-- |48| 8 | 1 | 3 | 2 | 1 | 0 | .o.oOo.o.oOo.o.oOo.o.oOo | <-- S = (error) + +--+-----------------------+--------------------------+ + +Method call with upload stream +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A method call which also involves uploading some data over a stream will r= esult +in + +:: + + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. | --> S (call) + +--+-----------------------+-----------+ + + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo | <-- S (reply) + +--+-----------------------+--------+ + + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + ... + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+ + C --> |24| 8 | 1 | 3 | 3 | 1 | 0 | --> S (stream finish) + +--+-----------------------+ + +--+-----------------------+ + C <-- |24| 8 | 1 | 3 | 3 | 1 | 0 | <-- S (stream finish) + +--+-----------------------+ + +Method call bidirectional stream +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A method call which also involves a bi-directional stream will result in + +:: + + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. | --> S (call) + +--+-----------------------+-----------+ + + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo | <-- S (reply) + +--+-----------------------+--------+ + + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C <-- |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | <-- S (s= tream data down) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C <-- |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | <-- S (s= tream data down) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C <-- |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | <-- S (s= tream data down) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C <-- |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | <-- S (s= tream data down) + +--+-----------------------+-------------....-------+ + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + .. + +--+-----------------------+-------------....-------+ + C --> |38| 8 | 1 | 3 | 3 | 1 | 2 | .o.oOo.o.oOo....o.oOo. | --> S (s= tream data up) + +--+-----------------------+-------------....-------+ + +--+-----------------------+ + C --> |24| 8 | 1 | 3 | 3 | 1 | 0 | --> S (stream finish) + +--+-----------------------+ + +--+-----------------------+ + C <-- |24| 8 | 1 | 3 | 3 | 1 | 0 | <-- S (stream finish) + +--+-----------------------+ + +Method calls overlapping +^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 1 | 0 | .o.oOo.o. | --> S (call 1) + +--+-----------------------+-----------+ + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 2 | 0 | .o.oOo.o. | --> S (call 2) + +--+-----------------------+-----------+ + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 2 | 0 | .o.oOo | <-- S (reply 2) + +--+-----------------------+--------+ + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 3 | 0 | .o.oOo.o. | --> S (call 3) + +--+-----------------------+-----------+ + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 3 | 0 | .o.oOo | <-- S (reply 3) + +--+-----------------------+--------+ + +--+-----------------------+-----------+ + C --> |38| 8 | 1 | 3 | 0 | 4 | 0 | .o.oOo.o. | --> S (call 4) + +--+-----------------------+-----------+ + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo | <-- S (reply 1) + +--+-----------------------+--------+ + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 4 | 0 | .o.oOo | <-- S (reply 4) + +--+-----------------------+--------+ + +Method call with passed FD +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A single method call with 2 passed file descriptors and successful reply, = for a +program=3D8, version=3D1, procedure=3D3, which 10 bytes worth of input arg= s, and 4 +bytes worth of return values. The number of file descriptors is encoded as= a +32-bit int. Each file descriptor then has a 1 byte dummy payload. The over= all +input packet length is 4 + 24 + 4 + 2 + 10 =3D=3D 44, and output packet le= ngth 32. + +:: + + +--+-----------------------+---------------+-------+ + C --> |44| 8 | 1 | 3 | 0 | 1 | 0 | 2 | .o.oOo.o. | 0 | 0 | --> S (ca= ll) + +--+-----------------------+---------------+-------+ + + +--+-----------------------+--------+ + C <-- |32| 8 | 1 | 3 | 1 | 1 | 0 | .o.oOo | <-- S (reply) + +--+-----------------------+--------+ + +RPC security +------------ + +There are various things to consider to ensure an implementation of the RPC +protocol can be satisfactorily secured + +Authentication/encryption +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The basic RPC protocol does not define or require any specific +authentication/encryption capabilities. A generic solution to providing +encryption for the protocol is to run the protocol over a TLS encrypted da= ta +stream. x509 certificate checks can be done to form a crude authentication +mechanism. It is also possible for an RPC program to negotiate an encrypti= on / +authentication capability, such as SASL, which may then also provide per-p= acket +data encryption. Finally the protocol data stream can of course be tunnell= ed +over transports such as SSH. + +Data limits +~~~~~~~~~~~ + +Although the protocol itself defines many arbitrary sized data values in t= he +payloads, to avoid denial of service attack there are a number of size lim= it +checks prior to encoding or decoding data. There is a limit on the maximum= size +of a single RPC message, limit on the maximum string length, and limits on= any +other parameter which uses a variable length array. These limits can be ra= ised, +subject to agreement between client/server, without otherwise breaking +compatibility of the RPC data on the wire. + +Data validation +~~~~~~~~~~~~~~~ + +It is important that all data be fully validated before performing any act= ions +based on the data. When reading an RPC packet, the first four bytes must b= e read +and the max packet size limit validated, before any attempt is made to rea= d the +variable length packet data. After a complete packet has been read, the he= ader +must be decoded and all 6 fields fully validated, before attempting to dis= patch +the payload. Once dispatched, the payload can be decoded and passed on to = the +appropriate API for execution. The RPC code must not take any action based= on +the payload, since it has no way to validate the semantics of the payload = data. +It must delegate this to the execution API (e.g. corresponding libvirt pub= lic +API). + +RPC internal APIs +----------------- + +The generic internal RPC library code lives in the ``src/rpc/`` directory = of the +libvirt source tree. Unless otherwise noted, the objects are all threadsaf= e. The +core object types and their purposes are: + +Overview of RPC objects +~~~~~~~~~~~~~~~~~~~~~~~ + +The following is a high level overview of the role of each of the main RPC +objects + +``virNetSASLContext *`` (virnetsaslcontext.h) + The virNetSASLContext APIs maintain SASL state for a network service (s= erver + or client). This is primarily used on the server to provide an access c= ontrol + list of SASL usernames permitted as clients. +``virNetSASLSession *`` (virnetsaslcontext.h) + The virNetSASLSession APIs maintain SASL state for a single network + connection (socket). This is used to perform the multi-step SASL handsh= ake + and perform encryption/decryption of data once authenticated, via integ= ration + with virNetSocket. +``virNetTLSContext *`` (virnettlscontext.h) + The virNetTLSContext APIs maintain TLS state for a network service (ser= ver or + client). This is primarily used on the server to provide an access cont= rol + list of x509 distinguished names, as well as diffie-hellman keys. It ca= n also + do validation of x509 certificates prior to initiating a connection, in= order + to improve detection of configuration errors. +``virNetTLSSession *`` (virnettlscontext.h) + The virNetTLSSession APIs maintain TLS state for a single network conne= ction + (socket). This is used to perform the multi-step TLS handshake and perf= orm + encryption/decryption of data once authenticated, via integration with + virNetSocket. +``virNetSocket *`` (virnetsocket.h) + The virNetSocket APIs provide a higher level wrapper around the raw BSD + sockets and getaddrinfo APIs. They allow for creation of both server and + client sockets. Data transports supported are TCP, UNIX, SSH tunnel or + external command tunnel. Internally the TCP socket impl uses the getadd= rinfo + info APIs to ensure correct protocol-independent behaviour, thus suppor= ting + both IPv4 and IPv6. The socket APIs can be associated with a + virNetSASLSession \*or virNetTLSSession \*object to allow seamless + encryption/decryption of all writes and reads. For UNIX sockets it is + possible to obtain the remote client user ID and process ID. Integratio= n with + the libvirt event loop also allows use of callbacks for notification of + various I/O conditions +``virNetMessage *`` (virnetmessage.h) + The virNetMessage APIs provide a wrapper around the libxdr API calls, to + facilitate processing and creation of RPC packets. There are convenienc= e APIs + for encoding/encoding the packet headers, encoding/decoding the payload= using + an XDR filter, encoding/decoding a raw payload (for streams), and encod= ing a + virErrorPtr object. There is also a means to add to/serve from a linked= -list + queue of messages. +``virNetClient *`` (virnetclient.h) + The virNetClient APIs provide a way to connect to a remote server and r= un one + or more RPC protocols over the connection. Connections can be made over= TCP, + UNIX sockets, SSH tunnels, or external command tunnels. There is suppor= t for + both TLS and SASL session encryption. The client also supports manageme= nt of + multiple data streams over each connection. Each client object can be u= sed + from multiple threads concurrently, with method calls/replies being + interleaved on the wire as required. +``virNetClientProgram *`` (virnetclientprogram.h) + The virNetClientProgram APIs are used to register a program+version wit= h the + connection. This then enables invocation of method calls, receipt of + asynchronous events and use of data streams, within that program+versio= n. + When created a set of callbacks must be supplied to take care of dispat= ching + any incoming asynchronous events. +``virNetClientStream *`` (virnetclientstream.h) + The virNetClientStream APIs are used to control transmission and receip= t of + data over a stream active on a client. Streams provide a low latency, + unlimited length, bi-directional raw data exchange mechanism layered ov= er the + RPC connection +``virNetServer *`` (virnetserver.h) + The virNetServer APIs are used to manage a network server. A server exp= osed + one or more programs, over one or more services. It manages multiple cl= ient + connections invoking multiple RPC calls in parallel, with dispatch acro= ss + multiple worker threads. +``virNetDaemon *`` (virnetdaemon.h) + The virNetDaemon APIs are used to manage a daemon process. A daemon is a + process that might expose one or more servers. It handles most + process-related details, network-related should be part of the underlyi= ng + server. +``virNetServerClient *`` (virnetserverclient.h) + The virNetServerClient APIs are used to manage I/O related to a single = client + network connection. It handles initial validation and routing of incomi= ng RPC + packets, and transmission of outgoing packets. +``virNetServerProgram *`` (virnetserverprogram.h) + The virNetServerProgram APIs are used to provide the implementation of a + single program/version set. Primarily this includes a set of callbacks = used + to actually invoke the APIs corresponding to program procedure numbers.= It is + responsible for all the serialization of payloads to/from XDR. +``virNetServerService *`` (virnetserverservice.h) + The virNetServerService APIs are used to connect the server to one or m= ore + network protocols. A single service may involve multiple sockets (ie bo= th + IPv4 and IPv6). A service also has an associated authentication policy = for + incoming clients. + +Client RPC dispatch +~~~~~~~~~~~~~~~~~~~ + +The client RPC code must allow for multiple overlapping RPC method calls t= o be +invoked, transmission and receipt of data for multiple streams and receipt= of +asynchronous events. Understandably this involves coordination of multiple +threads. + +The core requirement in the client dispatch code is that only one thread is +allowed to be performing I/O on the socket at any time. This thread is sai= d to +be "holding the buck". When any other thread comes along and needs to do I= /O it +must place its packets on a queue and delegate processing of them to the t= hread +that has the buck. This thread will send out the method call, and if it se= es a +reply will pass it back to the waiting thread. If the other thread's reply +hasn't arrived, by the time the main thread has got its own reply, then it= will +transfer responsibility for I/O to the thread that has been waiting the lo= ngest. +It is said to be "passing the buck" for I/O. + +When no thread is performing any RPC method call, or sending stream data t= here +is still a need to monitor the socket for incoming I/O related to asynchro= nous +events, or stream data receipt. For this task, a watch is registered with = the +event loop which triggers whenever the socket is readable. This watch is +automatically disabled whenever any other thread grabs the buck, and re-en= abled +when the buck is released. + +Example with buck passing +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the first example, a second thread issues an API call while the first t= hread +holds the buck. The reply to the first call arrives first, so the buck is = passed +to the second thread. + +:: + + Thread-1 + | + V + Call API1() + | + V + Grab Buck + | Thread-2 + V | + Send method1 V + | Call API2() + V | + Wait I/O V + |<--------Queue method2 + V | + Send method2 V + | Wait for buck + V | + Wait I/O | + | | + V | + Recv reply1 | + | | + V | + Pass the buck----->| + | V + V Wait I/O + Return API1() | + V + Recv reply2 + | + V + Release the buck + | + V + Return API2() + +Example without buck passing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this second example, a second thread issues an API call which is sent a= nd +replied to, before the first thread's API call has completed. The first th= read +thus notifies the second that its reply is ready, and there is no need to = pass +the buck + +:: + + Thread-1 + | + V + Call API1() + | + V + Grab Buck + | Thread-2 + V | + Send method1 V + | Call API2() + V | + Wait I/O V + |<--------Queue method2 + V | + Send method2 V + | Wait for buck + V | + Wait I/O | + | | + V | + Recv reply2 | + | | + V | + Notify reply2------>| + | V + V Return API2() + Wait I/O + | + V + Recv reply1 + | + V + Release the buck + | + V + Return API1() + +Example with async events +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this example, only one thread is present and it has to deal with some a= sync +events arriving. The events are actually dispatched to the application fro= m the +event loop thread + +:: + + Thread-1 + | + V + Call API1() + | + V + Grab Buck + | + V + Send method1 + | + V + Wait I/O + | Event thread + V ... + Recv event1 | + | V + V Wait for timer/fd + Queue event1 | + | V + V Timer fires + Wait I/O | + | V + V Emit event1 + Recv reply1 | + | V + V Wait for timer/fd + Return API1() | + ... + +Server RPC dispatch +~~~~~~~~~~~~~~~~~~~ + +The RPC server code must support receipt of incoming RPC requests from mul= tiple +client connections, and parallel processing of all RPC requests, even many= from +a single client. This goal is achieved through a combination of event driv= en +I/O, and multiple processing threads. + +The main libvirt event loop thread is responsible for performing all socke= t I/O. +It will read incoming packets from clients and will transmit outgoing pack= ets to +clients. It will handle the I/O to/from streams associated with client API +calls. When doing client I/O it will also pass the data through any applic= able +encryption layer (through use of the virNetSocket / virNetTLSSession and +virNetSASLSession integration). What is paramount is that the event loop t= hread +never do any task that can take a non-trivial amount of time. + +When reading packets, the event loop will first read the 4 byte length wor= d. +This is validated to make sure it does not exceed the maximum permissible = packet +size, and the client is set to allow receipt of the rest of the packet dat= a. +Once a complete packet has been received, the next step is to decode the R= PC +header. The header is validated to ensure the request is sensible, ie the = server +should not receive a method reply from a client. If the client has not yet +authenticated, an access control list check is also performed to make sure= the +procedure is one of those allowed prior to auth. If the packet is a method= call, +it will be placed on a global processing queue. The event loop thread is n= ow +done with the packet for the time being. + +The server has a pool of worker threads, which wait for method call packet= s to +be queued. One of them will grab the new method call off the queue for +processing. The first step is to decode the payload of the packet to extra= ct the +method call arguments. The worker does not attempt to do any semantic vali= dation +of the arguments, except to make sure the size of any variable length fiel= ds is +below defined limits. + +The worker now invokes the libvirt API call that corresponds to the proced= ure +number in the packet header. The worker is thus kept busy until the API ca= ll +completes. The implementation of the API call is responsible for doing sem= antic +validation of parameters and any MAC security checks on the objects affect= ed. + +Once the API call has completed, the worker thread will take the return va= lue +and output parameters, or error object and encode them into a reply packet. +Again it does not attempt to do any semantic validation of output data, as= ide +from variable length field limit checks. The worker thread puts the reply = packet +on the transmission queue for the client. The worker is now finished and g= oes +back to wait for another incoming method call. + +The main event loop is back in charge and when the client socket becomes +writable, it will start sending the method reply packet back to the client. + +At any time the libvirt connection object can emit asynchronous events. Th= ese +are handled by callbacks in the main event thread. The callback will simply +encode the event parameters into a new data packet and place the packet on= the +client transmission queue. + +Incoming and outgoing stream packets are also directly handled by the main= event +thread. When an incoming stream packet is received, instead of placing it = in the +global dispatch queue for the worker threads, it is sidetracked into a +per-stream processing queue. When the stream becomes writable, queued inco= ming +stream packets will be processed, passing their data payload on the stream. +Conversely when the stream becomes readable, chunks of data will be read f= rom +it, encoded into new outgoing packets, and placed on the client's transmit +queue. + +Example with overlapping methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This example illustrates processing of two incoming methods with overlappi= ng +execution + +:: + + Event thread Worker 1 Worker 2 + | | | + V V V + Wait I/O Wait Job Wait Job + | | | + V | | + Recv method1 | | + | | | + V | | + Queue method1 V | + | Serve method1 | + V | | + Wait I/O V | + | Call API1() | + V | | + Recv method2 | | + | | | + V | | + Queue method2 | V + | | Serve method2 + V V | + Wait I/O Return API1() V + | | Call API2() + | V | + V Queue reply1 | + Send reply1 | | + | V V + V Wait Job Return API2() + Wait I/O | | + | ... V + V Queue reply2 + Send reply2 | + | V + V Wait Job + Wait I/O | + | ... + ... + +Example with stream data +^^^^^^^^^^^^^^^^^^^^^^^^ + +This example illustrates processing of stream data + +:: + + Event thread + | + V + Wait I/O + | + V + Recv stream1 + | + V + Queue stream1 + | + V + Wait I/O + | + V + Recv stream2 + | + V + Queue stream2 + | + V + Wait I/O + | + V + Write stream1 + | + V + Write stream2 + | + V + Wait I/O + | + ... --=20 2.35.1 From nobody Sat May 11 06:37:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340125; cv=none; d=zohomail.com; s=zohoarc; b=MOUZfdaUhvKnpvCNVACioJJ+XtwDD/AKx8P8jJQzUf9LT/p8YHenS5vAMDHzKxqfd/2+Y2RpsWd83FS51kdYUE/ZaSF6n/Ec9FN5BZ7sM8CYCsGm/wRqlL9WgHimmMQPt7Ts4DBD8dKh3TDHwtt7wPDmNtTgUyd1OjJ98zE1ioA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340125; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=vby4HgccoS4Ra0esGnsJMleKbVTanWsdvUR/98UwZP0=; b=B3DaPFiqGQqf+7xQo1NBxHTGiEbgqkbMqEiLsYiWaNxdSLwjyJSoSrglhSir30iB4Up+r39ZQnN5tt2v3FNaMPHDZhmouhu3A3Cwdtm5O3P8zUk7yLVgdK+UPyL25E9TTk8ahiwVLSmymj26iYhwET2AKn4C7Ob82TNpA6dDFOQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1649340125725708.5035267285482; Thu, 7 Apr 2022 07:02:05 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-292-tY4RYHafMuSGUI17sYbYEw-1; Thu, 07 Apr 2022 10:01:03 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A859128EC12C; Thu, 7 Apr 2022 14:00:48 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8EF334118EEB; Thu, 7 Apr 2022 14:00:48 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 1F7C41940355; Thu, 7 Apr 2022 14:00:48 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id B904A1947BBE for ; Thu, 7 Apr 2022 14:00:46 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 8A2D340314D; Thu, 7 Apr 2022 14:00:46 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id CC05F401DB1 for ; Thu, 7 Apr 2022 14:00:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340124; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=vby4HgccoS4Ra0esGnsJMleKbVTanWsdvUR/98UwZP0=; b=OF2SxK3GDuwz7hhida1MnXvvW9q8TBXs/SFP3LLOz8djVFC4VkcygKMlKpvwzxWnMMhzj8 zVwFfmDzmeVP9wT6yGMSK5TdBnPAdxYGu1Vmfq9K0qU73xQZOKgzBryWAdZQ4NnRGB2eyI Bb3Cy16GMVnABp/lvNNZPIputbwxqU8= X-MC-Unique: tY4RYHafMuSGUI17sYbYEw-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 09/11] docs: Remove empty 'internals' subfolder Date: Thu, 7 Apr 2022 16:00:31 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340127785100005 Content-Type: text/plain; charset="utf-8"; x-default="true" All documents were now moved away so we don't need this any more. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/internals/meson.build | 49 -------------------------------------- docs/meson.build | 1 - 2 files changed, 50 deletions(-) delete mode 100644 docs/internals/meson.build diff --git a/docs/internals/meson.build b/docs/internals/meson.build deleted file mode 100644 index cbf0623c08..0000000000 --- a/docs/internals/meson.build +++ /dev/null @@ -1,49 +0,0 @@ -internals_in_files =3D [ -] - -html_xslt_gen_install_dir =3D docs_html_dir / 'internals' -html_xslt_gen =3D [] - -foreach name : internals_in_files - html_xslt_gen +=3D { - 'name': name, - 'source': 'docs' / 'internals' / name + '.html.in', - 'href_base': '../' - } -endforeach - -# keep the XSLT processing code block in sync with docs/meson.build - -# --- begin of XSLT processing --- - -foreach data : html_xslt_gen - html_filename =3D data['name'] + '.html' - - html_file =3D custom_target( - html_filename, - input: data.get('file', data['name'] + '.html.in'), - output: html_filename, - command: [ - xsltproc_prog, - '--stringparam', 'pagesrc', data.get('source', ''), - '--stringparam', 'builddir', meson.build_root(), - '--stringparam', 'timestamp', docs_timestamp, - '--stringparam', 'href_base', data.get('href_base', ''), - '--nonet', - site_xsl, - '@INPUT@', - ], - depends: data.get('depends', []), - depend_files: [ page_xsl ], - capture: true, - install: true, - install_dir: html_xslt_gen_install_dir, - ) - - install_web_deps +=3D html_file - install_web_files +=3D html_file.full_path() + ':' + html_xslt_gen_insta= ll_dir -endforeach - -html_xslt_gen =3D [] - -# --- end of XSLT processing --- diff --git a/docs/meson.build b/docs/meson.build index 9e69a0dc05..4291dea6f5 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -330,7 +330,6 @@ subdir('fonts') subdir('go') subdir('html') subdir('images') -subdir('internals') subdir('js') subdir('kbase') subdir('logos') --=20 2.35.1 From nobody Sat May 11 06:37:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340124; cv=none; d=zohomail.com; s=zohoarc; b=PjTiC9se8N8RLafeu5j6JHZpJMj2aKAGI4IhBL3G6izas9o+MRD06vUovwBcXphdGQrP4o89NsbyUtTVfgnNs0cLg50OZhS3gE1b+LYUBJ4x+qQpqpjNp1G9oRha+gCcMdLH/MwTSWakKi2eQ1YF9HEn3kgsBHBvvo/67tc5UTk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340124; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=3EmKA7r5NclIm+g3HZ84NJ1yUCRISt3VlHRzWAthZl4=; b=DZv+tBKwFUztJdpn8wORYugOb7IgygnAmBg4k3wgLCGxqP3eug3ZD6MY42jseRal0stM2VXb7jGMi5j0RGcy0hVMjmNv9f28GAdbA2C8ZIMEs0Yr/X+594Ll02Rdaa/Oz7BrWWlF/DwIRfAqMXAnBfVzZCDZkZvOPqactH14Ldc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1649340124403771.077280754112; Thu, 7 Apr 2022 07:02:04 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-52-KohhqUzZPIqtMjHj0dWFsA-1; Thu, 07 Apr 2022 10:01:09 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D228418F0241; Thu, 7 Apr 2022 14:00:49 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id BC60440D282F; Thu, 7 Apr 2022 14:00:49 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 6CCA01949761; Thu, 7 Apr 2022 14:00:49 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id BD09F1940347 for ; Thu, 7 Apr 2022 14:00:47 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 9FB2F40314D; Thu, 7 Apr 2022 14:00:47 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id F2C88401DB1 for ; Thu, 7 Apr 2022 14:00:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340123; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=3EmKA7r5NclIm+g3HZ84NJ1yUCRISt3VlHRzWAthZl4=; b=UJ1bukH5p1HggR6WllxkbsNL5/f7Sb7dq26DLz7FuWp2StBMYVQBzNzieWyRM1B4JX0X55 Uu6n/RtcPDpKabkIBViKh0QnsFUDrXTJVGvGEwUwH6EfPWDb5HmcTDSiiqh2LI0XZZiOYM AHO2CRzKyhCvyYhRFSbaccqzMlnXxmU= X-MC-Unique: KohhqUzZPIqtMjHj0dWFsA-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 10/11] docs: Convert 'internals' to RST and move it to 'kbase/internal/overview.rst' Date: Thu, 7 Apr 2022 16:00:32 +0200 Message-Id: <4c87df2b986c254f69f3b9f57165a52ff8d57aab.1649339910.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: application/octet-stream; x-default=true X-Zoho-Virus-Status: 1 X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340126551100003 Note that this document was not referenced from any top level page. This patch does a straight conversion and leaves it unreferenced. Next patch will then modify it to serve as an overview (hence the new name) of how an API call happens. Signed-off-by: Peter Krempa --- docs/internals.html.in | 119 ------------------------------ docs/kbase/internals/meson.build | 1 + docs/kbase/internals/overview.rst | 117 +++++++++++++++++++++++++++++ docs/meson.build | 1 - 4 files changed, 118 insertions(+), 120 deletions(-) delete mode 100644 docs/internals.html.in create mode 100644 docs/kbase/internals/overview.rst diff --git a/docs/internals.html.in b/docs/internals.html.in deleted file mode 100644 index e474f7ddd7..0000000000 --- a/docs/internals.html.in +++ /dev/null @@ -1,119 +0,0 @@ - - - - -

          libvirt internals

          - -

          - This section provides documents useful to those working on the libvirt - internals, adding new public APIs, new hypervisor drivers or extending - the libvirtd daemon code. -

          - - - -

          Before adding new code it will be important to get a basic understanding - of the many elements involved with making any call or change to the libvirt - code. The architecture goals must be adhered to - when submitting new code. Understanding the many places that need to be - touched and the interactions between various subsystems within libvirt - will directly correlate to the ability to be successful in getting new - code accepted.

          -

          The following diagram depicts code flow from a client application, in - this case the libvirt provided virsh command through the - various layers to elicit a response from some chosen hypervisor. -

          - -

          - virConnectOpen calling sequence -

          -
            -
          • "virsh -c qemu:///system list --all" -

            After the virsh code processes the input arguments, it eventually - will make a call to open the connection using a default set of - authentication credentials (virConnectAuthDefault).

          • -
          • virConnectOpenAuth() -

            Each of the virConnectOpen APIs will first call virInitialize() and - then revector through the local "do_open():" call.

            -
              -
            • virInitialize() -

              Calls the registration API for each of the drivers with - client-side only capabilities and then call the remoteRegister() - API last. This ensures the virDriverTab[] tries local drivers - first before using the remote driver.

            • -
            • Loop through virDriverTab[] entries trying to call their - respective "open" entry point (in our case remoteOpen())
            • -
            • After successful return from the virDriverTab[] open() - API, attempt to find and open other drivers (network, interface, - storage, etc.)
            • -
            -
          • -
          • remoteOpen() -

            After a couple of URI checks, a call to doRemoteOpen() is made

            -
              -
            • Determine network transport and host/port to use from URI -

              The transport will be either tls, unix, ssh, libssh2, ext, - or tcp with the default of tls. Decode the host/port if provided - or default to "localhost".

            • -
            • virNetClientRegisterAsyncIO() -

              Register an I/O callback mechanism to get returned data via - virNetClientIncomingEvent()

            • -
            • "call(...REMOTE_PROC_OPEN...)" -

              Eventually routes into virNetClientProgramCall() which will - call virNetClientSendWithReply() and eventually uses - virNetClientIO()to send the message to libvirtd and - then waits for a response using virNetClientIOEventLoop()

            • -
            • virNetClientIncomingEvent() -

              Receives the returned packet and processes through - virNetClientIOUpdateCallback()

            • -
            -
          • -
          • libvirtd Daemon -

            -
              -
            • Daemon Startup -

              The daemon initialization processing will declare itself - as a daemon via a virNetDaemonNew() call, then creates new server - using virNetServerNew() and adds that server to the main daemon - struct with virNetDaemonAddServer() call. It will then use - virDriverLoadModule() to find/load all known drivers, - set up an RPC server program using the remoteProcs[] - table via a virNetServerProgramNew() call. The table is the - corollary to the remote_procedure enum list in - the client. It lists all the functions to be called in - the same order. Once RPC is set up, networking server sockets - are opened, the various driver state initialization routines - are run from the virStateDriverTab[], the network - links are enabled, and the daemon waits for work.

            • -
            • RPC -

              When a message is received, the remoteProcs[] - table is referenced for the 'REMOTE_PROC_OPEN' call entry. - This results in remoteDispatchOpen() being called via the - virNetServerProgramDispatchCall().

            • -
            • remoteDispatchOpen() -

              The API will read the argument passed picking out the - name of the driver to be opened. The code - will then call virConnectOpen() or virConnectOpenReadOnly() - depending on the argument flags.

            • -
            • virConnectOpen() or virConnectOpenReadOnly() -

              Just like the client except that upon entry the URI - is what was passed from the client and will be found - and opened to process the data.

              -

              The returned structure data is returned via the - virNetServer interfaces to the remote driver which then - returns it to the client application.

            • -
            -
          • -
          - - diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.build index 879c4b2de8..8b5daad1f9 100644 --- a/docs/kbase/internals/meson.build +++ b/docs/kbase/internals/meson.build @@ -4,6 +4,7 @@ docs_kbase_internals_files = [ 'incremental-backup', 'locking', 'migration', + 'overview', 'rpc', ] diff --git a/docs/kbase/internals/overview.rst b/docs/kbase/internals/overview.rst new file mode 100644 index 0000000000..84ea7858db --- /dev/null +++ b/docs/kbase/internals/overview.rst @@ -0,0 +1,117 @@ +========================== +libvirt internals overview +========================== + +This section provides documents useful to those working on the libvirt +internals, adding new public APIs, new hypervisor drivers or extending the +libvirtd daemon code. + +- Introduction to basic rules and guidelines for `hacking <../../hacking.html>`__ on + libvirt code +- Guide to adding `public APIs <../../api_extension.html>`__ +- Insight into libvirt `event loop and worker + pool `__ +- Approach for `spawning commands `__ from libvirt + driver code +- The libvirt `RPC infrastructure `__ +- The `Resource Lock Manager `__ + +Before adding new code it will be important to get a basic understanding of the +many elements involved with making any call or change to the libvirt code. The +architecture `goals <../../goals.html>`__ must be adhered to when submitting new code. +Understanding the many places that need to be touched and the interactions +between various subsystems within libvirt will directly correlate to the ability +to be successful in getting new code accepted. + +The following diagram depicts code flow from a client application, in this case +the libvirt provided ``virsh`` command through the various layers to elicit a +response from some chosen hypervisor. + +.. image:: ../../images/libvirt-virConnect-example.png + :alt: virConnectOpen calling sequence + +- "virsh -c qemu:///system list --all" + + After the virsh code processes the input arguments, it eventually will make a + call to open the connection using a default set of authentication credentials + (virConnectAuthDefault). + +- virConnectOpenAuth() + + Each of the virConnectOpen APIs will first call virInitialize() and then + revector through the local "do_open():" call. + + - virInitialize() + + Calls the registration API for each of the drivers with client-side only + capabilities and then call the remoteRegister() API last. This ensures the + virDriverTab[] tries local drivers first before using the remote driver. + + - Loop through virDriverTab[] entries trying to call their respective "open" + entry point (in our case remoteOpen()) + + - After successful return from the virDriverTab[] open() API, attempt to + find and open other drivers (network, interface, storage, etc.) + +- remoteOpen() + + After a couple of URI checks, a call to doRemoteOpen() is made + + - Determine network transport and host/port to use from URI + + The transport will be either tls, unix, ssh, libssh2, ext, or tcp with the + default of tls. Decode the host/port if provided or default to + "localhost". + + - virNetClientRegisterAsyncIO() + + Register an I/O callback mechanism to get returned data via + virNetClientIncomingEvent() + + - "call(...REMOTE_PROC_OPEN...)" + + Eventually routes into virNetClientProgramCall() which will call + virNetClientSendWithReply() and eventually uses virNetClientIO()to send + the message to libvirtd and then waits for a response using + virNetClientIOEventLoop() + + - virNetClientIncomingEvent() + + Receives the returned packet and processes through + virNetClientIOUpdateCallback() + +- libvirtd Daemon + + - Daemon Startup + + The daemon initialization processing will declare itself as a daemon via a + virNetDaemonNew() call, then creates new server using virNetServerNew() + and adds that server to the main daemon struct with + virNetDaemonAddServer() call. It will then use virDriverLoadModule() to + find/load all known drivers, set up an RPC server program using the + ``remoteProcs[]`` table via a virNetServerProgramNew() call. The table is + the corollary to the ``remote_procedure`` enum list in the client. It + lists all the functions to be called in the same order. Once RPC is set + up, networking server sockets are opened, the various driver state + initialization routines are run from the ``virStateDriverTab[]``, the + network links are enabled, and the daemon waits for work. + + - RPC + + When a message is received, the ``remoteProcs[]`` table is referenced for + the 'REMOTE_PROC_OPEN' call entry. This results in remoteDispatchOpen() + being called via the virNetServerProgramDispatchCall(). + + - remoteDispatchOpen() + + The API will read the argument passed picking out the ``name`` of the + driver to be opened. The code will then call virConnectOpen() or + virConnectOpenReadOnly() depending on the argument ``flags``. + + - virConnectOpen() or virConnectOpenReadOnly() + + Just like the client except that upon entry the URI is what was passed + from the client and will be found and opened to process the data. + + The returned structure data is returned via the virNetServer interfaces to + the remote driver which then returns it to the client application. diff --git a/docs/meson.build b/docs/meson.build index 4291dea6f5..9f1f1ed80d 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -25,7 +25,6 @@ docs_html_in_files = [ 'formatnwfilter', 'formatstoragecaps', 'index', - 'internals', 'remote', 'storage', 'uri', -- 2.35.1 From nobody Sat May 11 06:37:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1649340067; cv=none; d=zohomail.com; s=zohoarc; b=VPSH/WmaF5tL9h+31zA54QG/8yPCdFb66S846EA7M/bB66czKL7BNmH41Rjh11z5eksHZpEJbuSFxZGMLLFCVmagOavooDLFynhm2HHw8PemfCn397ALZtNqByKdzdN/NakuFVeyPmPYoFI/8SjR5f4aTy5XXSTngPGULKw8JCU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649340067; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=LVF+fGH/kdEwHblpNXVTCrSFUgr82K/7ikKODb424C0=; b=Gx1djgGNCB8fmau2ja9ucCu28LVbYkpw8fSmHlhLsqTgyL0RRXsjRJ/QmAyi+kDp6cJfRn9buEWlYXZbW1DoEr/AXNCrikHJPetEpEixjkZq1beQb3sQJjRbVK7i224F6x1DkuFomYibgcmjWI+a1gFc4oJoxOczZtapbL/dO24= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1649340067958932.1481453245441; Thu, 7 Apr 2022 07:01:07 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-460-BHzNG69TPVq_bwlove6dqQ-1; Thu, 07 Apr 2022 10:01:03 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2CCC5800882; Thu, 7 Apr 2022 14:00:51 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id D9E8E1415107; Thu, 7 Apr 2022 14:00:50 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 8B9801949761; Thu, 7 Apr 2022 14:00:50 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id CBD331947BBE for ; Thu, 7 Apr 2022 14:00:48 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id B053C403153; Thu, 7 Apr 2022 14:00:48 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 116374AE6E1 for ; Thu, 7 Apr 2022 14:00:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1649340066; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=LVF+fGH/kdEwHblpNXVTCrSFUgr82K/7ikKODb424C0=; b=bOBMnqefsVb1dJeLg4rclRTuT461XCjHXZk3WTKtcGBaeXSXTA3M/F2OwO2LFYu21Eo8bw 9EvE0n1DBmBe1MWOd3S5GBsktvIm4gmFtOytaTRvXGTQRiENhMRltsBLWBzH7/jpxEM1bc P1urb0+6nGeyduCsE98YOwr7nZ6yqi0= X-MC-Unique: BHzNG69TPVq_bwlove6dqQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 11/11] docs: kbase: internals: Make 'overview' page useful and link to it Date: Thu, 7 Apr 2022 16:00:33 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1649340069227100001 Content-Type: text/plain; charset="utf-8"; x-default="true" While the content is slightly outdated it's still a good primer on how an API call traverses through the client library and to the remote driver. To make the page useful, this commit: - removes the paragraphs which were intended to serve as a directory page for the 'internals' subdirectory - adds a note saying that some facts might not be up to date - adds linking to this page from the kbase directory page - adds more monospace formatting around function names Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- docs/kbase/index.rst | 4 + docs/kbase/internals/overview.rst | 121 +++++++++++++----------------- 2 files changed, 57 insertions(+), 68 deletions(-) diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 31711d908b..0848467d51 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -86,6 +86,10 @@ Internals VM migration implementation details, complementing the info in `migration <../migration.html>`__ +`API call flow overview `__ + Overview of how an API call is handled by the ``libvirt`` library and p= assed + over RPC to the daemon. + `Spawning commands `__ Spawning commands from libvirt driver code diff --git a/docs/kbase/internals/overview.rst b/docs/kbase/internals/overv= iew.rst index 84ea7858db..7887e16667 100644 --- a/docs/kbase/internals/overview.rst +++ b/docs/kbase/internals/overview.rst @@ -1,117 +1,102 @@ -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D -libvirt internals overview -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D - -This section provides documents useful to those working on the libvirt -internals, adding new public APIs, new hypervisor drivers or extending the -libvirtd daemon code. - -- Introduction to basic rules and guidelines for `hacking <../../hacking.= html>`__ on - libvirt code -- Guide to adding `public APIs <../../api_extension.html>`__ -- Insight into libvirt `event loop and worker - pool `__ -- Approach for `spawning commands `__ from libvirt - driver code -- The libvirt `RPC infrastructure `__ -- The `Resource Lock Manager `__ - -Before adding new code it will be important to get a basic understanding o= f the -many elements involved with making any call or change to the libvirt code.= The -architecture `goals <../../goals.html>`__ must be adhered to when submitti= ng new code. -Understanding the many places that need to be touched and the interactions -between various subsystems within libvirt will directly correlate to the a= bility -to be successful in getting new code accepted. +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D +libvirt API call overview +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D The following diagram depicts code flow from a client application, in this= case the libvirt provided ``virsh`` command through the various layers to elici= t a response from some chosen hypervisor. +**Note:** Some aspects of this document may be outdated. + .. image:: ../../images/libvirt-virConnect-example.png :alt: virConnectOpen calling sequence -- "virsh -c qemu:///system list --all" +- ``virsh -c qemu:///system list --all`` After the virsh code processes the input arguments, it eventually will = make a call to open the connection using a default set of authentication crede= ntials - (virConnectAuthDefault). + (``virConnectAuthDefault``). -- virConnectOpenAuth() +- ``virConnectOpenAuth()`` - Each of the virConnectOpen APIs will first call virInitialize() and then - revector through the local "do_open():" call. + Each of the ``virConnectOpen`` APIs will first call ``virInitialize()``= and + then revector through the local "``do_open()``" call. - - virInitialize() + - ``virInitialize()`` Calls the registration API for each of the drivers with client-side = only - capabilities and then call the remoteRegister() API last. This ensur= es the - virDriverTab[] tries local drivers first before using the remote dri= ver. + capabilities and then call the ``remoteRegister()`` API last. This + ensures the ``virDriverTab[]`` tries local drivers first before usin= g the + remote driver. - - Loop through virDriverTab[] entries trying to call their respective = "open" - entry point (in our case remoteOpen()) + - Loop through ``virDriverTab[]`` entries trying to call their respect= ive + "open" entry point (in our case ``remoteOpen()``) - - After successful return from the virDriverTab[] open() API, attempt = to - find and open other drivers (network, interface, storage, etc.) + - After successful return from the ``virDriverTab[]`` ``open()`` API, + attempt to find and open other drivers (network, interface, storage,= etc.) -- remoteOpen() +- ``remoteOpen()`` - After a couple of URI checks, a call to doRemoteOpen() is made + After a couple of URI checks, a call to ``doRemoteOpen()`` is made - Determine network transport and host/port to use from URI - The transport will be either tls, unix, ssh, libssh2, ext, or tcp wi= th the - default of tls. Decode the host/port if provided or default to - "localhost". + The transport will be either ``tls``, ``unix``, ``ssh``, ``libssh2``, + ``ext``, or ``tcp`` with the default of ``tls``. Decode the host/por= t if + provided or default to ``localhost``. - - virNetClientRegisterAsyncIO() + - ``virNetClientRegisterAsyncIO()`` Register an I/O callback mechanism to get returned data via - virNetClientIncomingEvent() + ``virNetClientIncomingEvent()`` - - "call(...REMOTE_PROC_OPEN...)" + - ``call(...REMOTE_PROC_OPEN...)`` - Eventually routes into virNetClientProgramCall() which will call - virNetClientSendWithReply() and eventually uses virNetClientIO()to s= end - the message to libvirtd and then waits for a response using - virNetClientIOEventLoop() + Eventually routes into ``virNetClientProgramCall()`` which will call + ``virNetClientSendWithReply()`` and eventually uses ``virNetClientIO= ()`` + to send the message to libvirtd and then waits for a response using + ``virNetClientIOEventLoop()`` - - virNetClientIncomingEvent() + - ``virNetClientIncomingEvent()`` Receives the returned packet and processes through - virNetClientIOUpdateCallback() + ``virNetClientIOUpdateCallback()`` - libvirtd Daemon - Daemon Startup The daemon initialization processing will declare itself as a daemon= via a - virNetDaemonNew() call, then creates new server using virNetServerNe= w() - and adds that server to the main daemon struct with - virNetDaemonAddServer() call. It will then use virDriverLoadModule()= to - find/load all known drivers, set up an RPC server program using the - ``remoteProcs[]`` table via a virNetServerProgramNew() call. The tab= le is - the corollary to the ``remote_procedure`` enum list in the client. It - lists all the functions to be called in the same order. Once RPC is = set - up, networking server sockets are opened, the various driver state - initialization routines are run from the ``virStateDriverTab[]``, the - network links are enabled, and the daemon waits for work. + ``virNetDaemonNew()`` call, then creates new server using + ``virNetServerNew()`` and adds that server to the main daemon struct= with + ``virNetDaemonAddServer()`` call. It will then use + ``virDriverLoadModule()`` to find/load all known drivers, set up an = RPC + server program using the ``remoteProcs[]`` table via a + ``virNetServerProgramNew()`` call. The table is the corollary to the + ``remote_procedure`` enum list in the client. It lists all the funct= ions + to be called in the same order. Once RPC is set up, networking server + sockets are opened, the various driver state initialization routines= are + run from the ``virStateDriverTab[]``, the network links are enabled,= and + the daemon waits for work. - RPC When a message is received, the ``remoteProcs[]`` table is reference= d for - the 'REMOTE_PROC_OPEN' call entry. This results in remoteDispatchOpe= n() - being called via the virNetServerProgramDispatchCall(). + the ``REMOTE_PROC_OPEN`` call entry. This results in + ``remoteDispatchOpen()`` being called via the + ``virNetServerProgramDispatchCall()``. - - remoteDispatchOpen() + - ``remoteDispatchOpen()`` The API will read the argument passed picking out the ``name`` of the - driver to be opened. The code will then call virConnectOpen() or - virConnectOpenReadOnly() depending on the argument ``flags``. + driver to be opened. The code will then call ``virConnectOpen()`` or + ``virConnectOpenReadOnly()`` depending on the argument ``flags``. - - virConnectOpen() or virConnectOpenReadOnly() + - ``virConnectOpen()`` or ``virConnectOpenReadOnly()`` Just like the client except that upon entry the URI is what was pass= ed from the client and will be found and opened to process the data. - The returned structure data is returned via the virNetServer interfa= ces to - the remote driver which then returns it to the client application. + The returned structure data is returned via the ``virNetServer`` + interfaces to the remote driver which then returns it to the client + application. --=20 2.35.1