From nobody Tue Feb 10 06:25:03 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 15334565935941018.2493467747913; Sun, 5 Aug 2018 01:09:53 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 689A2307D858; Sun, 5 Aug 2018 08:09:51 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2BF1F77DFB; Sun, 5 Aug 2018 08:09:51 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id D30DB24F60; Sun, 5 Aug 2018 08:09:50 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w6V8jHY7027409 for ; Tue, 31 Jul 2018 04:45:17 -0400 Received: by smtp.corp.redhat.com (Postfix) id DB6085C72A; Tue, 31 Jul 2018 08:45:17 +0000 (UTC) Received: from mx1.redhat.com (ext-mx05.extmail.prod.ext.phx2.redhat.com [10.5.110.29]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7E41B177CE; Tue, 31 Jul 2018 08:45:07 +0000 (UTC) Received: from mail-wm0-f54.google.com (mail-wm0-f54.google.com [74.125.82.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 698A413A90; Tue, 31 Jul 2018 08:45:05 +0000 (UTC) Received: by mail-wm0-f54.google.com with SMTP id o11-v6so2125315wmh.2; Tue, 31 Jul 2018 01:45:05 -0700 (PDT) Received: from clem.localdomain ([2a01:e34:ec25:e330:f2d5:bfff:fe6e:3278]) by smtp.gmail.com with ESMTPSA id s2-v6sm25103775wrn.83.2018.07.31.01.45.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 31 Jul 2018 01:45:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ErRMMYuvgO/5AM67ktljL6l0R/t2a+IXDQCajAS2AIY=; b=AYfI+ml/jaqxfz2um8+GGCM/tefGkJGJJ4RlemSzhCoOpDIsSn7r24uJ9D35yXLnfv LcSXL/QoE0P6JosHimvh49XGWSDbjEsL6zUfEmOE4M0rFlr0yFSqzpjsAWK2w1aqprpA bsP969Uw1yB4FElYEenI4Qn2rKhI77BPMPXFiIo6nhfRTa4fqWBIOKUKQBPxxTivXITX CzCpXL6Mq3aIOMOP6S1slhrwi5hantXZI5CqAm8aKQubXrMmKxBo+NNxliraXxfrw/FO DV2PtDi9wGp7nQn7VhG4QJ5+lCFXAbGBXXNV0gs0B3QRAt+bX2mOBq52/mWp3WKjd1PT VDWQ== X-Gm-Message-State: AOUpUlGTbMzCexVEsWBEIP+E7fs8NLm29UcuXdUkcZ41dVoihiJ/crq0 aik1L+/oTHsMyV/gUcFrfoLYRo21mQ4= X-Google-Smtp-Source: AAOMgpdx3SP+Wfbx0lQ6dJGClyb/aK7kdRbpdeuTXdT8b9nW/BNOL1icBffufiR7MayVCvCY0Xvs9g== X-Received: by 2002:a1c:5e08:: with SMTP id s8-v6mr1712672wmb.88.1533026703636; Tue, 31 Jul 2018 01:45:03 -0700 (PDT) From: clem@lse.epita.fr To: mprivozn@redhat.com, phrdina@redhat.com, libvir-list@redhat.com Date: Tue, 31 Jul 2018 10:44:22 +0200 Message-Id: <20180731084423.8607-4-clem@lse.epita.fr> In-Reply-To: <20180731084423.8607-1-clem@lse.epita.fr> References: <20180731084423.8607-1-clem@lse.epita.fr> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 31 Jul 2018 08:45:05 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 31 Jul 2018 08:45:05 +0000 (UTC) for IP:'74.125.82.54' DOMAIN:'mail-wm0-f54.google.com' HELO:'mail-wm0-f54.google.com' FROM:'clementinehayat@gmail.com' RCPT:'' X-RedHat-Spam-Score: -0.028 (FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS) 74.125.82.54 mail-wm0-f54.google.com 74.125.82.54 mail-wm0-f54.google.com X-Scanned-By: MIMEDefang 2.78 on 10.5.110.29 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-loop: libvir-list@redhat.com Cc: Clementine Hayat Subject: [libvirt] [PATCH v3 3/4] storage: Implement iscsi_direct pool backend X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.48]); Sun, 05 Aug 2018 08:09:52 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Clementine Hayat We need here libiscsi for the storgae pool backend. For the iscsi-direct storage pool, only checkPool and refreshPool should be necessary for basic support. The pool is state-less and just need the informations within the volume to work. Signed-off-by: Clementine Hayat --- m4/virt-storage-iscsi-direct.m4 | 3 + src/storage/Makefile.inc.am | 2 + src/storage/storage_backend_iscsi_direct.c | 400 ++++++++++++++++++++- 3 files changed, 402 insertions(+), 3 deletions(-) diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct= .m4 index cc2d490352..dab4414169 100644 --- a/m4/virt-storage-iscsi-direct.m4 +++ b/m4/virt-storage-iscsi-direct.m4 @@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ with_storage_iscsi_direct=3D$with_libiscsi fi if test "$with_storage_iscsi_direct" =3D "yes"; then + if test "$with_libiscsi" =3D "no"; then + AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver]) + fi AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], [whether iSCSI backend for storage driver is enable= d]) fi diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index b2714fd960..bd5ea06f8b 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -203,6 +203,7 @@ if WITH_STORAGE_ISCSI_DIRECT libvirt_storage_backend_iscsi_direct_la_SOURCES =3D $(STORAGE_DRIVER_ISCSI= _DIRECT_SOURCES) libvirt_storage_backend_iscsi_direct_la_CFLAGS =3D \ -I$(srcdir)/conf \ + -I$(srcdir)/secret \ $(LIBISCSI_CFLAGS) \ $(AM_CFLAGS) \ $(NULL) @@ -211,6 +212,7 @@ storagebackend_LTLIBRARIES +=3D libvirt_storage_backend= _iscsi-direct.la libvirt_storage_backend_iscsi_direct_la_LDFLAGS =3D $(AM_LDFLAGS_MOD) libvirt_storage_backend_iscsi_direct_la_LIBADD =3D \ libvirt.la \ + $(LIBISCSI_LIBS) \ ../gnulib/lib/libgnu.la \ $(NULL) endif WITH_STORAGE_ISCSI_DIRECT diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/stora= ge_backend_iscsi_direct.c index 94c4c989ff..ab192730fb 100644 --- a/src/storage/storage_backend_iscsi_direct.c +++ b/src/storage/storage_backend_iscsi_direct.c @@ -22,28 +22,422 @@ =20 #include =20 +#include +#include + +#include "datatypes.h" +#include "secret_util.h" #include "storage_backend_iscsi_direct.h" #include "storage_util.h" +#include "viralloc.h" +#include "virerror.h" #include "virlog.h" +#include "virobject.h" +#include "virstring.h" +#include "virtime.h" +#include "viruuid.h" =20 #define VIR_FROM_THIS VIR_FROM_STORAGE =20 +#define ISCSI_DEFAULT_TARGET_PORT 3260 +#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000 + VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); =20 +static struct iscsi_context * +virISCSIDirectCreateContext(const char* initiator_iqn) +{ + struct iscsi_context *iscsi =3D NULL; + + iscsi =3D iscsi_create_context(initiator_iqn); + if (!iscsi) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create iscsi context for %s"), + initiator_iqn); + return iscsi; +} + +static char * +virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source) +{ + char *portal =3D NULL; + + if (source->nhost !=3D 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return NULL; + } + if (source->hosts[0].port =3D=3D 0) { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + ISCSI_DEFAULT_TARGET_PORT)); + } else if (strchr(source->hosts[0].name, ':')) { + ignore_value(virAsprintf(&portal, "[%s]:%d", + source->hosts[0].name, + source->hosts[0].port)); + } else { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + source->hosts[0].port)); + } + return portal; +} + +static int +virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi, + virStoragePoolSourcePtr source) +{ + unsigned char *secret_value =3D NULL; + size_t secret_size; + virStorageAuthDefPtr authdef =3D source->auth; + int ret =3D -1; + virConnectPtr conn =3D NULL; + + if (!authdef || authdef->authType =3D=3D VIR_STORAGE_AUTH_TYPE_NONE) + return 0; + + VIR_DEBUG("username=3D'%s' authType=3D%d seclookupdef.type=3D%d", + authdef->username, authdef->authType, authdef->seclookupdef.= type); + + if (authdef->authType !=3D VIR_STORAGE_AUTH_TYPE_CHAP) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("iscsi-direct pool only supports 'chap' auth type= ")); + return ret; + } + + if (!(conn =3D virGetConnectSecret())) + return ret; + + if (virSecretGetSecretString(conn, &authdef->seclookupdef, + VIR_SECRET_USAGE_TYPE_ISCSI, + &secret_value, &secret_size) < 0) + goto cleanup; + + if (iscsi_set_initiator_username_pwd(iscsi, + authdef->username, + (const char *)secret_value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set credential: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret =3D 0; + cleanup: + VIR_DISPOSE_N(secret_value, secret_size); + virObjectUnref(conn); + return ret; +} + +static int +virISCSIDirectSetContext(struct iscsi_context *iscsi, + const char *target_name) +{ + if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to init transport: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_targetname(iscsi, target_name) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set target name: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set session type: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} =20 static int -virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_= UNUSED, - bool *isActive ATTRIBUTE_UNUSED) +virISCSIDirectConnect(struct iscsi_context *iscsi, + const char *portal) { + if (iscsi_connect_sync(iscsi, portal) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to connect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_login_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to login: %s"), + iscsi_get_error(iscsi)); + return -1; + } return 0; } =20 static int -virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUT= E_UNUSED) +virISCSIDirectTestUnitReady(struct iscsi_context *iscsi, + int lun) +{ + struct scsi_task *task =3D NULL; + int ret =3D -1; + virTimeBackOffVar timebackoff; + + if (virTimeBackOffStart(&timebackoff, 1, + VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0) + goto cleanup; + + do { + if (!(task =3D iscsi_testunitready_sync(iscsi, lun))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (task->status !=3D SCSI_STATUS_CHECK_CONDITION || + task->sense.key !=3D SCSI_SENSE_UNIT_ATTENTION || + task->sense.ascq !=3D SCSI_SENSE_ASCQ_BUS_RESET) + break; + + scsi_free_scsi_task(task); + } while (virTimeBackOffWait(&timebackoff)); + + if (task->status !=3D SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret =3D 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + int lun, + char *portal) { + virStoragePoolDefPtr def =3D virStoragePoolObjGetDef(pool); + + if (virAsprintf(&vol->name, "unit:0:0:%u", lun) < 0) + return -1; + if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; + if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; return 0; } =20 +static int +virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi, + virStorageVolDefPtr vol, + int lun) +{ + struct scsi_task *task =3D NULL; + struct scsi_inquiry_standard *inq =3D NULL; + long long size =3D 0; + int ret =3D -1; + + if (!(task =3D iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) || + task->status !=3D SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to send inquiry command: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(inq =3D scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (inq->device_type =3D=3D SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT= _ACCESS) { + struct scsi_readcapacity10 *rc10 =3D NULL; + + scsi_free_scsi_task(task); + task =3D NULL; + + if (!(task =3D iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) || + task->status !=3D SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get capacity of lun: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(rc10 =3D scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + size =3D rc10->block_size; + size *=3D rc10->lba; + vol->target.capacity =3D size; + vol->target.allocation =3D size; + + } + + ret =3D 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectRefreshVol(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + int lun, + char *portal) +{ + virStoragePoolDefPtr def =3D virStoragePoolObjGetDef(pool); + virStorageVolDefPtr vol =3D NULL; + int ret =3D -1; + + virStoragePoolObjClearVols(pool); + if (virISCSIDirectTestUnitReady(iscsi, lun) < 0) + goto cleanup; + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + vol->type =3D VIR_STORAGE_VOL_NETWORK; + + if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0) + goto cleanup; + + def->capacity +=3D vol->target.capacity; + def->allocation +=3D vol->target.allocation; + + if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0) + goto cleanup; + + if (virStoragePoolObjAddVol(pool, vol) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create volume: %d"), + lun); + goto cleanup; + } + vol =3D NULL; + + ret =3D 0; + cleanup: + virStorageVolDefFree(vol); + return ret; +} + +static int +virISCSIDirectReportLuns(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + char *portal) +{ + struct scsi_task *task =3D NULL; + struct scsi_reportluns_list *list =3D NULL; + int full_size; + size_t i; + int ret =3D -1; + + if (!(task =3D iscsi_reportluns_sync(iscsi, 0, 16))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + full_size =3D scsi_datain_getfullsize(task); + + if (full_size > task->datain.size) { + scsi_free_scsi_task(task); + if (!(task =3D iscsi_reportluns_sync(iscsi, 0, full_size))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + } + + if (!(list =3D scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + for (i =3D 0; i < list->num; i++) { + if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) <= 0) + goto cleanup; + } + + ret =3D 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectDisconnect(struct iscsi_context *iscsi) +{ + if (iscsi_logout_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to logout: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_disconnect(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to disconnect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool, + bool *isActive) +{ + *isActive =3D virStoragePoolObjIsActive(pool); + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool) +{ + virStoragePoolDefPtr def =3D virStoragePoolObjGetDef(pool); + struct iscsi_context *iscsi =3D NULL; + char *portal =3D NULL; + int ret =3D -1; + + if (!(iscsi =3D virISCSIDirectCreateContext(def->source.initiator.iqn)= )) + goto cleanup; + if (!(portal =3D virStorageBackendISCSIDirectPortal(&def->source))) + goto cleanup; + if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0) + goto cleanup; + if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0) + goto cleanup; + if (virISCSIDirectConnect(iscsi, portal) < 0) + goto cleanup; + if (virISCSIDirectReportLuns(pool, iscsi, portal) < 0) + goto disconect; + + ret =3D 0; + disconect: + virISCSIDirectDisconnect(iscsi); + cleanup: + VIR_FREE(portal); + iscsi_destroy_context(iscsi); + return ret; +} + virStorageBackend virStorageBackendISCSIDirect =3D { .type =3D VIR_STORAGE_POOL_ISCSI_DIRECT, =20 --=20 2.18.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list