Skip to content

Commit 301a2b3

Browse files
committed
feat(pool/encryption): handle new create and import API
Signed-off-by: Diwakar Sharma <diwakar.sharma@datacore.com>
1 parent a2758a1 commit 301a2b3

File tree

14 files changed

+248
-12
lines changed

14 files changed

+248
-12
lines changed

io-engine-tests/src/pool.rs

+2
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ impl PoolBuilderLocal {
272272
cluster_size: None,
273273
md_args: None,
274274
backend: Default::default(),
275+
enc_key: None,
276+
crypto_vbdev_name: None,
275277
})
276278
.await?;
277279
Ok(lvs)

io-engine/examples/lvs-eval/main.rs

+2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ async fn create_lvs(args: &CliArgs) -> Lvs {
136136
md_resv_ratio: args.md_resv_ratio,
137137
}),
138138
backend: Default::default(),
139+
enc_key: None,
140+
crypto_vbdev_name: None,
139141
};
140142

141143
Lvs::create_or_import(lvs_args.clone()).await.unwrap()

io-engine/src/bdev/lvs.rs

+8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ use crate::{
3434
pool_backend::{PoolArgs, PoolBackend},
3535
};
3636

37+
use super::crypto::EncryptionKey;
38+
3739
/// An lvol specified via URI.
3840
pub(super) struct Lvol {
3941
/// Name of the lvol.
@@ -50,6 +52,8 @@ struct Lvs {
5052
disk: String,
5153
/// The lvs creation mode.
5254
mode: LvsMode,
55+
// Encryption key - if the lvs is encrypted.
56+
key: Option<EncryptionKey>,
5357
}
5458

5559
impl Debug for Lvol {
@@ -144,6 +148,7 @@ impl TryFrom<String> for Lvs {
144148
name: uri.path()[1..].into(),
145149
disk,
146150
mode,
151+
key: None,
147152
})
148153
}
149154
}
@@ -209,6 +214,9 @@ impl Lvs {
209214
cluster_size: None,
210215
md_args: None,
211216
backend: PoolBackend::Lvs,
217+
enc_key: self.key.clone(),
218+
// XXX: Is this path ever exercised apart from test, or casperf perhaps?
219+
crypto_vbdev_name: self.key.as_ref().map(|_| format!("crypto_{}", self.name)),
212220
};
213221
match &self.mode {
214222
LvsMode::Create => match crate::lvs::Lvs::import_from_args(args.clone()).await {

io-engine/src/bin/io-engine-client/v1/pool_cli.rs

+123-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@ pub fn subcommands() -> Command {
5454
.required(false)
5555
.value_parser(PoolType::types().to_vec())
5656
.default_value(PoolType::Lvs.as_ref()),
57+
)
58+
.arg(
59+
Arg::new("cipher")
60+
.short('c')
61+
.long("cipher")
62+
.help("The cipher to use for encryption")
63+
.required(false)
64+
.requires("encryption-key"),
65+
)
66+
.arg(
67+
Arg::new("encryption-key")
68+
.short('k')
69+
.long("encryption-key")
70+
.help("The encryption key of the pool in hexlified format")
71+
.required(false),
72+
)
73+
.arg(
74+
Arg::new("xts-key")
75+
.short('e')
76+
.long("xts-key")
77+
.help("encryption key2 required for AES_XTS")
78+
.required(false)
79+
.required_if_eq("cipher", "AES_XTS"),
5780
);
5881

5982
let import = Command::new("import")
@@ -86,6 +109,28 @@ pub fn subcommands() -> Command {
86109
.required(false)
87110
.value_parser(PoolType::types().to_vec())
88111
.default_value(PoolType::Lvs.as_ref()),
112+
)
113+
.arg(
114+
Arg::new("cipher")
115+
.short('c')
116+
.long("cipher")
117+
.help("The cipher to use for encryption")
118+
.required(false)
119+
.requires("encryption-key"),
120+
)
121+
.arg(
122+
Arg::new("encryption-key")
123+
.short('k')
124+
.long("encryption-key")
125+
.help("The encryption key of the pool in hexlified format")
126+
.required(false),
127+
)
128+
.arg(
129+
Arg::new("xts-key")
130+
.short('e')
131+
.long("xts-key")
132+
.help("encryption key2 required for AES_XTS")
133+
.required_if_eq("cipher", "AES_XTS"),
89134
);
90135

91136
let destroy = Command::new("destroy")
@@ -211,6 +256,19 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
211256
.to_owned();
212257

213258
let uuid = matches.get_one::<String>("uuid");
259+
let cipher = matches.get_one::<String>("cipher");
260+
261+
if let Some(c) = cipher {
262+
if !c.eq_ignore_ascii_case("AES_XTS") && !c.eq_ignore_ascii_case("AES_CBC") {
263+
return Err(Status::invalid_argument(
264+
"Need valid cipher(AES_XTS or AES_CBC)",
265+
))
266+
.context(GrpcStatus);
267+
}
268+
}
269+
270+
let enc_key = matches.get_one::<String>("encryption-key");
271+
let xts_key = matches.get_one::<String>("xts-key");
214272

215273
let disks_list = matches
216274
.get_many::<String>("disk")
@@ -251,6 +309,23 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
251309
None => None,
252310
};
253311

312+
let enc_key_msg = enc_key.map(|k| v1rpc::common::EncryptionKey {
313+
key_name: "key_".to_owned() + k.as_str(),
314+
key: k.clone().into(),
315+
key_length: (k.len() * 4) as u32,
316+
key2: xts_key.map(|k2| k2.clone().into()),
317+
key2_length: xts_key.map(|x| { x.len() * 4 } as u32),
318+
});
319+
320+
let enc_msg = enc_key_msg.map(|e| {
321+
v1rpc::common::create_pool_request::Encryption::Data(v1rpc::common::EncryptionData {
322+
cipher: v1rpc::common::Cipher::from_str_name(cipher.unwrap())
323+
.unwrap()
324+
.into(),
325+
key: Some(e),
326+
})
327+
});
328+
254329
let response = ctx
255330
.v1
256331
.pool
@@ -261,7 +336,7 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
261336
pooltype: v1rpc::pool::PoolType::from(pooltype) as i32,
262337
cluster_size,
263338
md_args: Some(v1rpc::pool::PoolMetadataArgs { md_resv_ratio }),
264-
encryption: None,
339+
encryption: enc_msg,
265340
})
266341
.await
267342
.context(GrpcStatus)?;
@@ -284,6 +359,21 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
284359
Ok(())
285360
}
286361

362+
#[derive(EnumString, VariantNames, AsRefStr)]
363+
#[strum(serialize_all = "UPPERCASE")]
364+
pub(super) enum Cipher {
365+
AesCbc,
366+
AesXts,
367+
}
368+
impl From<Cipher> for v1rpc::common::Cipher {
369+
fn from(value: Cipher) -> Self {
370+
match value {
371+
Cipher::AesCbc => Self::AesCbc,
372+
Cipher::AesXts => Self::AesXts,
373+
}
374+
}
375+
}
376+
287377
#[derive(EnumString, VariantNames, AsRefStr)]
288378
#[strum(serialize_all = "camelCase")]
289379
pub(super) enum PoolType {
@@ -312,6 +402,20 @@ async fn import(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
312402
})?
313403
.to_owned();
314404
let uuid = matches.get_one::<String>("uuid");
405+
let cipher = matches.get_one::<String>("cipher");
406+
407+
if let Some(c) = cipher {
408+
if !c.eq_ignore_ascii_case("AES_XTS") && !c.eq_ignore_ascii_case("AES_CBC") {
409+
return Err(Status::invalid_argument(
410+
"Need valid cipher(AES_XTS or AES_CBC)",
411+
))
412+
.context(GrpcStatus);
413+
}
414+
}
415+
416+
let enc_key = matches.get_one::<String>("encryption-key");
417+
let xts_key = matches.get_one::<String>("xts-key");
418+
315419
let disks_list = matches
316420
.get_many::<String>("disk")
317421
.ok_or_else(|| ClientError::MissingValue {
@@ -326,6 +430,23 @@ async fn import(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
326430
.map_err(|e| Status::invalid_argument(e.to_string()))
327431
.context(GrpcStatus)?;
328432

433+
let enc_key_msg = enc_key.map(|k| v1rpc::common::EncryptionKey {
434+
key_name: "key_".to_owned() + k,
435+
key: k.clone().into(),
436+
key_length: k.len() as u32,
437+
key2: xts_key.map(|k2| k2.clone().into()),
438+
key2_length: xts_key.map(|x| x.len() as u32),
439+
});
440+
441+
let enc_msg = enc_key_msg.map(|e| {
442+
v1rpc::common::import_pool_request::Encryption::Data(v1rpc::common::EncryptionData {
443+
cipher: v1rpc::common::Cipher::from_str_name(cipher.unwrap())
444+
.unwrap()
445+
.into(),
446+
key: Some(e),
447+
})
448+
});
449+
329450
let response = ctx
330451
.v1
331452
.pool
@@ -334,7 +455,7 @@ async fn import(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
334455
uuid: uuid.map(ToString::to_string),
335456
disks: disks_list,
336457
pooltype: v1rpc::pool::PoolType::from(pooltype) as i32,
337-
encryption: None,
458+
encryption: enc_msg,
338459
})
339460
.await
340461
.context(GrpcStatus)?;

io-engine/src/grpc/v1/pool.rs

+70-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub use crate::pool_backend::FindPoolArgs as PoolIdProbe;
22
use crate::{
3+
bdev::crypto::{Cipher, EncryptionKey as PoolEncKey},
34
core::{NvmfShareProps, ProtectedSubsystems, Protocol, ResourceLockGuard, ResourceLockManager},
45
grpc::{acquire_subsystem_lock, GrpcClientContext, GrpcResult, RWLock, RWSerializer},
56
lvs::{BsError, LvsError},
@@ -11,9 +12,17 @@ use crate::{
1112
use ::function_name::named;
1213
use futures::FutureExt;
1314
use io_engine_api::v1::{
14-
pool::*, replica::destroy_replica_request, snapshot::destroy_snapshot_request,
15+
common::{create_pool_request, import_pool_request, Cipher as GrpcCipher, EncryptionData},
16+
pool::*,
17+
replica::destroy_replica_request,
18+
snapshot::destroy_snapshot_request,
19+
};
20+
use std::{
21+
convert::{TryFrom, TryInto},
22+
fmt::Debug,
23+
ops::Deref,
24+
panic::AssertUnwindSafe,
1525
};
16-
use std::{convert::TryFrom, fmt::Debug, ops::Deref, panic::AssertUnwindSafe};
1726
use tonic::{Request, Status};
1827

1928
impl From<DestroyPoolRequest> for FindPoolArgs {
@@ -126,6 +135,37 @@ impl RWLock for PoolService {
126135
}
127136
}
128137

138+
impl TryFrom<EncryptionData> for PoolEncKey {
139+
type Error = LvsError;
140+
fn try_from(msg: EncryptionData) -> Result<Self, Self::Error> {
141+
let key = if let Some(k) = msg.key {
142+
k
143+
} else {
144+
return Err(LvsError::Invalid {
145+
source: BsError::InvalidArgument {},
146+
msg: "invalid argument, missing key".to_string(),
147+
});
148+
};
149+
150+
let arg_cipher = msg.cipher;
151+
let ctype: Cipher = GrpcCipher::try_from(arg_cipher)
152+
.map_err(|_| LvsError::Invalid {
153+
source: BsError::InvalidArgument {},
154+
msg: format!("invalid cipher provided: {}", arg_cipher),
155+
})?
156+
.into();
157+
158+
Ok(Self {
159+
cipher: ctype,
160+
key_name: key.key_name,
161+
key: String::from_utf8_lossy(&key.key).to_string(),
162+
key_len: key.key_length,
163+
key2: key.key2.map(|k2| String::from_utf8_lossy(&k2).to_string()),
164+
key2_len: key.key2_length,
165+
})
166+
}
167+
}
168+
129169
impl TryFrom<CreatePoolRequest> for PoolArgs {
130170
type Error = LvsError;
131171
fn try_from(args: CreatePoolRequest) -> Result<Self, Self::Error> {
@@ -149,13 +189,24 @@ impl TryFrom<CreatePoolRequest> for PoolArgs {
149189
}
150190
}
151191

192+
let enc_key = match args.encryption.clone() {
193+
Some(create_pool_request::Encryption::Data(kd)) => kd.try_into().ok(),
194+
Some(create_pool_request::Encryption::Secret(_ks)) => None,
195+
_ => None,
196+
};
197+
152198
Ok(Self {
153-
name: args.name,
154-
disks: args.disks,
155-
uuid: args.uuid,
199+
name: args.name.clone(),
200+
disks: args.disks.clone(),
201+
uuid: args.uuid.clone(),
156202
cluster_size: args.cluster_size,
157203
md_args: args.md_args.map(|md| md.into()),
158204
backend: backend.into(),
205+
enc_key,
206+
crypto_vbdev_name: args
207+
.encryption
208+
.as_ref()
209+
.map(|_| format!("crypto_{}", args.name)),
159210
})
160211
}
161212
}
@@ -226,13 +277,24 @@ impl TryFrom<ImportPoolRequest> for PoolArgs {
226277
}
227278
}
228279

280+
let enc_key = match args.encryption.clone() {
281+
Some(import_pool_request::Encryption::Data(kd)) => PoolEncKey::try_from(kd).ok(),
282+
Some(import_pool_request::Encryption::Secret(_ks)) => None,
283+
_ => None,
284+
};
285+
229286
Ok(Self {
230-
name: args.name,
231-
disks: args.disks,
232-
uuid: args.uuid,
287+
name: args.name.clone(),
288+
disks: args.disks.clone(),
289+
uuid: args.uuid.clone(),
233290
cluster_size: None,
234291
md_args: None,
235292
backend: backend.into(),
293+
enc_key,
294+
crypto_vbdev_name: args
295+
.encryption
296+
.as_ref()
297+
.map(|_| format!("crypto_{}", args.name)),
236298
})
237299
}
238300
}

io-engine/src/pool_backend.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{
2+
bdev::crypto::EncryptionKey,
23
core::{BdevStater, BdevStats, ToErrno},
34
replica_backend::ReplicaOps,
45
};
@@ -16,6 +17,8 @@ pub struct PoolArgs {
1617
pub cluster_size: Option<u32>,
1718
pub md_args: Option<PoolMetadataArgs>,
1819
pub backend: PoolBackend,
20+
pub enc_key: Option<EncryptionKey>,
21+
pub crypto_vbdev_name: Option<String>,
1922
}
2023

2124
/// Pool metadata args.

0 commit comments

Comments
 (0)