sma: configure crypto when attaching volumes

Crypto parameters are now checked and crypto is configured when a volume
is attached.  Since configuring crypto can lead to creating new bdevs on
top of the attached volume, each device manager will also need to be
changed to retrieve the bdev through the CryptoEngine.get_crypto_bdev()
interface.  This will be done in subsequent patches.

Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Change-Id: Idb5f804cf88aa5e34bbee6817acdb8f3a42a2320
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13870
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: <sebastian.brzezinka@intel.com>
This commit is contained in:
Konrad Sztyber 2022-08-02 06:46:42 +02:00 committed by Ben Walker
parent cc3f842cd1
commit e1068a862c

View File

@ -5,6 +5,7 @@ import threading
import uuid
from dataclasses import dataclass
from spdk.rpc.client import JSONRPCException
from . import crypto
from ..common import format_volume_id
from ..proto import sma_pb2
@ -157,6 +158,40 @@ class VolumeManager:
raise VolumeException(grpc.StatusCode.INTERNAL,
'Failed to stop discovery')
def _get_crypto_params(self, params):
key, cipher, key2 = None, None, None
try:
if params.HasField('crypto'):
key, cipher = params.crypto.key.decode('ascii'), params.crypto.cipher
if len(params.crypto.key2) > 0:
key2 = params.crypto.key2.decode('ascii')
except UnicodeDecodeError:
raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT,
'Corrupted crypto key')
return key, cipher, key2
def _setup_crypto(self, volume_id, params):
try:
if not params.HasField('crypto'):
return
key, cipher, key2 = self._get_crypto_params(params)
crypto.get_crypto_engine().setup(volume_id, key, cipher, key2)
except crypto.CryptoException as ex:
raise VolumeException(ex.code, ex.message)
def _cleanup_crypto(self, volume_id):
try:
crypto.get_crypto_engine().cleanup(volume_id)
except crypto.CryptoException as ex:
logging.warning(f'Failed to cleanup crypto: {ex.message}')
def _verify_crypto(self, volume_id, params):
try:
key, cipher, key2 = self._get_crypto_params(params)
crypto.get_crypto_engine().verify(volume_id, key, cipher, key2)
except crypto.CryptoException as ex:
raise VolumeException(ex.code, ex.message)
@_locked
def connect_volume(self, params, device_handle=None):
""" Connects a volume through a discovery service. Returns a tuple (volume_id, existing):
@ -172,6 +207,8 @@ class VolumeManager:
if device_handle is not None and volume.device_handle != device_handle:
raise VolumeException(grpc.StatusCode.ALREADY_EXISTS,
'Volume is already attached to a different device')
# Make sure the crypto params are the same
self._verify_crypto(volume_id, params)
return volume_id, True
discovery_services = set()
try:
@ -218,6 +255,7 @@ class VolumeManager:
if subnqn != params.nvmf.subnqn:
raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT,
'Unexpected subsystem NQN')
self._setup_crypto(volume_id, params)
# Finally remember that volume
self._volumes[volume_id] = Volume(volume_id, device_handle, discovery_services)
except Exception as ex:
@ -238,6 +276,7 @@ class VolumeManager:
volume = self._volumes.get(id)
if volume is None:
return
self._cleanup_crypto(id)
# Delete the volume from the map and stop the services it uses
for name in volume.discovery_services:
try: