From nobody Thu Sep 19 16:10:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=linux.microsoft.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1722869094898526.6508917405052; Mon, 5 Aug 2024 07:44:54 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id DAF00D0E; Mon, 5 Aug 2024 10:44:53 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id C7B3D1279; Mon, 5 Aug 2024 10:41:26 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 13262B37; Mon, 5 Aug 2024 10:41:07 -0400 (EDT) Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lists.libvirt.org (Postfix) with ESMTP id 335E5B51 for ; Mon, 5 Aug 2024 10:41:06 -0400 (EDT) Received: from paekkaladevi-dev-u22.gi4irqh5pfqublruu4yyku2wof.phxx.internal.cloudapp.net (unknown [20.125.125.171]) by linux.microsoft.com (Postfix) with ESMTPSA id 69C2320B712E; Mon, 5 Aug 2024 07:41:05 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 69C2320B712E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1722868865; bh=/zMvoXUYqsomvYaWaiidWm3y5R2ORsrFokRIGIb3Ymw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=soe1cgKGZEjGHRdYmiCbQj5HXfx++1jyvhogc4s1bWwPy3UzWwXDCijxLEke4fHM3 h3NmErhpQ2wYdO1qGSC17Gp0i4NWssKeEIOT3HZ3O12lIPoB35qn1H4dPc92resIGg /RF0fV4uUj2x5uWt/TBJWvtUod8U6VynI3DxdIqI= From: Purna Pavan Chandra To: devel@lists.libvirt.org Subject: [PATCH v3 7/9] ch: support restore with net devices Date: Mon, 5 Aug 2024 14:40:59 +0000 Message-Id: <20240805144101.4864-8-paekkaladevi@linux.microsoft.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240805144101.4864-1-paekkaladevi@linux.microsoft.com> References: <20240805144101.4864-1-paekkaladevi@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: OB7D2BVQMJSX2YQLUENUYYYYWTZKOR7I X-Message-ID-Hash: OB7D2BVQMJSX2YQLUENUYYYYWTZKOR7I X-MailFrom: paekkaladevi@linux.microsoft.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: paekkaladevi@microsoft.com, kumarpraveen@linux.microsoft.com, liuwe@microsoft.com, prapal@linux.microsoft.com, Purna Pavan Chandra X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Computed bodyhash is different from the expected one) X-ZM-MESSAGEID: 1722869096304116600 Content-Type: text/plain; charset="utf-8" Cloud-hypervisor now supports restoring with new net fds. Ref: https://github.com/cloud-hypervisor/cloud-hypervisor/pull/6402 So, pass new tap fds via SCM_RIGHTS to CH's restore api. Signed-off-by: Purna Pavan Chandra --- src/ch/ch_capabilities.c | 6 +++ src/ch/ch_capabilities.h | 1 + src/ch/ch_driver.c | 29 +++++++----- src/ch/ch_monitor.c | 21 ++++++++- src/ch/ch_monitor.h | 2 +- src/ch/ch_process.c | 98 +++++++++++++++++++++++++++++++++------- 6 files changed, 126 insertions(+), 31 deletions(-) diff --git a/src/ch/ch_capabilities.c b/src/ch/ch_capabilities.c index 5941851500..f3765a8095 100644 --- a/src/ch/ch_capabilities.c +++ b/src/ch/ch_capabilities.c @@ -65,6 +65,12 @@ virCHCapsInitCHVersionCaps(int version) if (version >=3D 36000000) virCHCapsSet(chCaps, CH_SOCKET_BACKEND_SERIAL_PORT); =20 + /* Starting v40, Cloud-Hypervisor supports restore with new net fds. + * This is required to be able to restore a guest with network config = define. + * https://github.com/cloud-hypervisor/cloud-hypervisor/releases/tag/v= 40.0 */ + if (version >=3D 40000000) + virCHCapsSet(chCaps, CH_RESTORE_WITH_NEW_TAPFDS); + return g_steal_pointer(&chCaps); =20 } diff --git a/src/ch/ch_capabilities.h b/src/ch/ch_capabilities.h index 03932511f6..e5efb14b68 100644 --- a/src/ch/ch_capabilities.h +++ b/src/ch/ch_capabilities.h @@ -28,6 +28,7 @@ typedef enum { CH_SERIAL_CONSOLE_IN_PARALLEL, /* Serial and Console ports can work in= parallel */ CH_MULTIFD_IN_ADDNET, /* Cloud-hypervisor can accept multiple FDs in a= dd-net api */ CH_SOCKET_BACKEND_SERIAL_PORT, /* Support Unix socket as a backend for= a serial port */ + CH_RESTORE_WITH_NEW_TAPFDS, /* Cloud-hypervisor support for restore wi= th new net fds */ =20 CH_CAPS_LAST /* this must always be the last item */ } virCHCapsFlags; diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index fbeac60825..24aed471c5 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -680,22 +680,24 @@ chDomainDestroy(virDomainPtr dom) } =20 static int -chDomainSaveAdditionalValidation(virDomainDef *vmdef) +chDomainSaveRestoreAdditionalValidation(virCHDriver *driver, virDomainDef = *vmdef) { - /* - SAVE and RESTORE are functional only without any networking and - device passthrough configuration - */ - if (vmdef->nnets > 0) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("cannot save domain with network interfaces")); - return -1; - } + /* SAVE and RESTORE are functional only without any host device + * passthrough configuration */ if (vmdef->nhostdevs > 0) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("cannot save domain with host devices")); + _("cannot save/restore domain with host devices")); return -1; } + + if (vmdef->nnets > 0) { + if (!virBitmapIsBitSet(driver->chCaps, CH_RESTORE_WITH_NEW_TAPFDS)= ) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot save/restore domain with network devi= ces")); + return -1; + } + } + return 0; } =20 @@ -728,7 +730,7 @@ chDoDomainSave(virCHDriver *driver, VIR_AUTOCLOSE fd =3D -1; int ret =3D -1; =20 - if (chDomainSaveAdditionalValidation(vm->def) < 0) + if (chDomainSaveRestoreAdditionalValidation(driver, vm->def) < 0) goto end; =20 domainState =3D virDomainObjGetState(vm, NULL); @@ -1087,6 +1089,9 @@ chDomainRestoreFlags(virConnectPtr conn, if (virDomainRestoreFlagsEnsureACL(conn, def) < 0) goto cleanup; =20 + if (chDomainSaveRestoreAdditionalValidation(driver, def) < 0) + goto cleanup; + if (!(vm =3D virDomainObjListAdd(driver->domains, &def, driver->xmlopt, VIR_DOMAIN_OBJ_LIST_ADD_LIVE | diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 8d8be1f46e..3af5e7f2d1 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -978,14 +978,31 @@ virCHMonitorSaveVM(virCHMonitor *mon, const char *to) } =20 int -virCHMonitorBuildRestoreJson(const char *from, char **jsonstr) +virCHMonitorBuildRestoreJson(virDomainDef *vmdef, const char *from, char *= *jsonstr) { + size_t i; g_autoptr(virJSONValue) restore_json =3D virJSONValueNewObject(); - g_autofree char *path_url =3D g_strdup_printf("file://%s", from); + if (virJSONValueObjectAppendString(restore_json, "source_url", path_ur= l)) return -1; =20 + /* Pass the netconfig needed to restore with new netfds */ + if (vmdef->nnets) { + g_autoptr(virJSONValue) nets =3D virJSONValueNewArray(); + for (i =3D 0; i < vmdef->nnets; i++) { + g_autoptr(virJSONValue) net_json =3D virJSONValueNewObject(); + g_autofree char *id =3D g_strdup_printf("%s_%ld", CH_NET_ID_PR= EFIX, i); + if (virJSONValueObjectAppendString(net_json, "id", id) < 0) + return -1; + if (virJSONValueObjectAppendNumberInt(net_json, "num_fds", vmd= ef->nets[i]->driver.virtio.queues)) + return -1; + virJSONValueArrayAppend(nets, &net_json); + } + if (virJSONValueObjectAppend(restore_json, "net_fds", &nets)) + return -1; + } + if (!(*jsonstr =3D virJSONValueToString(restore_json, false))) return -1; =20 diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index 375b7a49a4..02a6685d58 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -127,4 +127,4 @@ int virCHMonitorGetIOThreads(virCHMonitor *mon, virDomainIOThreadInfo ***iothreads); int virCHMonitorBuildNetJson(virDomainNetDef *netdef, int netindex, char **jso= nstr); -int virCHMonitorBuildRestoreJson(const char *from, char **jsonstr); +int virCHMonitorBuildRestoreJson(virDomainDef *vmdef, const char *from, ch= ar **jsonstr); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index 09c8be6c56..ff0fc5ca63 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -29,6 +29,7 @@ #include "ch_process.h" #include "domain_cgroup.h" #include "domain_interface.h" +#include "viralloc.h" #include "virerror.h" #include "virfile.h" #include "virjson.h" @@ -716,6 +717,56 @@ chProcessAddNetworkDevices(virCHDriver *driver, return 0; } =20 +/** + * virCHRestoreCreateNetworkDevices: + * @driver: pointer to driver structure + * @vmdef: pointer to domain definition + * @vmtapfds: returned array of FDs of guest interfaces + * @nvmtapfds: returned number of network indexes + * @nicindexes: returned array of network indexes + * @nnicindexes: returned number of network indexes + * + * Create network devices for the domain. This function is called during + * domain restore. + * + * Returns 0 on success or -1 in case of error +*/ +static int +virCHRestoreCreateNetworkDevices(virCHDriver *driver, + virDomainDef *vmdef, + int **vmtapfds, + size_t *nvmtapfds, + int **nicindexes, + size_t *nnicindexes) +{ + size_t i, j; + size_t tapfd_len; + size_t index_vmtapfds; + for (i =3D 0; i < vmdef->nnets; i++) { + g_autofree int *tapfds =3D NULL; + tapfd_len =3D vmdef->nets[i]->driver.virtio.queues; + if (virCHDomainValidateActualNetDef(vmdef->nets[i]) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("net definition failed validation")); + return -1; + } + tapfds =3D g_new0(int, tapfd_len); + memset(tapfds, -1, (tapfd_len) * sizeof(int)); + + /* Connect Guest interfaces */ + if (virCHConnetNetworkInterfaces(driver, vmdef, vmdef->nets[i], ta= pfds, + nicindexes, nnicindexes) < 0) + return -1; + + index_vmtapfds =3D *nvmtapfds; + VIR_EXPAND_N(*vmtapfds, *nvmtapfds, tapfd_len); + for (j =3D 0; j < tapfd_len; j++) { + VIR_APPEND_ELEMENT_INPLACE(*vmtapfds, index_vmtapfds, tapfds[j= ]); + } + } + return 0; +} + /** * virCHProcessStartValidate: * @driver: pointer to driver structure @@ -917,7 +968,12 @@ virCHProcessStartRestore(virCHDriver *driver, virDomai= nObj *vm, const char *from g_autofree char *payload =3D NULL; g_autofree char *response =3D NULL; VIR_AUTOCLOSE mon_sockfd =3D -1; + g_autofree int *tapfds =3D NULL; + g_autofree int *nicindexes =3D NULL; size_t payload_len; + size_t ntapfds =3D 0; + size_t nnicindexes =3D 0; + int ret =3D -1; =20 if (!priv->monitor) { /* Get the first monitor connection if not already */ @@ -932,17 +988,7 @@ virCHProcessStartRestore(virCHDriver *driver, virDomai= nObj *vm, const char *from vm->def->id =3D vm->pid; priv->machineName =3D virCHDomainGetMachineName(vm); =20 - /* Pass 0, NULL as restore only works without networking support */ - if (virDomainCgroupSetupCgroup("ch", vm, - 0, NULL, /* nnicindexes, nicindexes */ - &priv->cgroup, - cfg->cgroupControllers, - 0, /*maxThreadsPerProc*/ - priv->driver->privileged, - priv->machineName) < 0) - return -1; - - if (virCHMonitorBuildRestoreJson(from, &payload) < 0) { + if (virCHMonitorBuildRestoreJson(vm->def, from, &payload) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to restore domain")); return -1; @@ -960,20 +1006,40 @@ virCHProcessStartRestore(virCHDriver *driver, virDom= ainObj *vm, const char *from if ((mon_sockfd =3D chMonitorSocketConnect(priv->monitor)) < 0) return -1; =20 - if (virSocketSendMsgWithFDs(mon_sockfd, payload, payload_len, NULL, 0)= < 0) { + if (virCHRestoreCreateNetworkDevices(driver, vm->def, &tapfds, &ntapfd= s, &nicindexes, &nnicindexes) < 0) + goto cleanup; + + if (virDomainCgroupSetupCgroup("ch", vm, + nnicindexes, nicindexes, + &priv->cgroup, + cfg->cgroupControllers, + 0, /*maxThreadsPerProc*/ + priv->driver->privileged, + priv->machineName) < 0) + goto cleanup; + + /* Bring up netdevs before restoring vm */ + if (virDomainInterfaceStartDevices(vm->def) < 0) + goto cleanup; + + if (virSocketSendMsgWithFDs(mon_sockfd, payload, payload_len, tapfds, = ntapfds) < 0) { virReportSystemError(errno, "%s", _("Failed to send restore request to CH")); - return -1; + goto cleanup; } =20 /* Restore is a synchronous operation in CH. so, pass false to wait un= til there's a response */ if (chSocketProcessHttpResponse(mon_sockfd, false) < 0) - return -1; + goto cleanup; =20 if (virCHProcessSetup(vm) < 0) - return -1; + goto cleanup; =20 virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_FROM_SNA= PSHOT); + ret =3D 0; =20 - return 0; + cleanup: + if (tapfds) + chCloseFDs(tapfds, ntapfds); + return ret; } --=20 2.34.1