-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Artsiom Koltun <[email protected]>
- Loading branch information
1 parent
2f964b2
commit e01c025
Showing
3 changed files
with
175 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright (C) 2023 Intel Corporation | ||
|
||
// Package middleend implements the MiddleEnd APIs (service) of the storage Server | ||
package middleend | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"log" | ||
"runtime" | ||
"runtime/debug" | ||
|
||
pc "github.com/opiproject/opi-api/common/v1/gen/go" | ||
pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go" | ||
intelmodels "github.com/opiproject/opi-intel-bridge/pkg/models" | ||
"github.com/opiproject/opi-spdk-bridge/pkg/middleend" | ||
spdkmodels "github.com/opiproject/opi-spdk-bridge/pkg/models" | ||
"github.com/opiproject/opi-spdk-bridge/pkg/server" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
var ( | ||
errMissingArgument = status.Error(codes.InvalidArgument, "missing argument") | ||
errNotSupportedCipher = status.Error(codes.Unimplemented, "not supported cipher") | ||
errWrongKeySize = status.Error(codes.InvalidArgument, "invalid key size") | ||
) | ||
|
||
// Server contains middleend related OPI services | ||
type Server struct { | ||
pb.MiddleendServiceServer | ||
rpc server.JSONRPC | ||
} | ||
|
||
// NewServer creates initialized instance of middleend server | ||
func NewServer(jsonRPC server.JSONRPC) *Server { | ||
opiSpdkServer := middleend.NewServer(jsonRPC) | ||
return &Server{ | ||
opiSpdkServer, | ||
jsonRPC, | ||
} | ||
} | ||
|
||
// CreateEncryptedVolume creates an encrypted volume | ||
func (s *Server) CreateEncryptedVolume(_ context.Context, in *pb.CreateEncryptedVolumeRequest) (*pb.EncryptedVolume, error) { | ||
defer func() { | ||
if in != nil && in.EncryptedVolume != nil { | ||
for i := range in.EncryptedVolume.Key { | ||
in.EncryptedVolume.Key[i] = 0 | ||
} | ||
in.EncryptedVolume.Cipher = pb.EncryptionType_ENCRYPTION_TYPE_UNSPECIFIED | ||
} | ||
// Run GC to free all variables which contained encryption keys | ||
runtime.GC() | ||
// Return allocated memory to OS, otherwise the memory which contained | ||
// keys can be kept for some time. | ||
debug.FreeOSMemory() | ||
}() | ||
|
||
err := verifyCreateEncryptedVolumeRequestArgs(in) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
bdevUUID, err := s.getBdevUUIDByName(in.EncryptedVolume.VolumeId.Value) | ||
if err != nil { | ||
log.Println("Failed to find UUID for bdev", in.EncryptedVolume.VolumeId.Value) | ||
return nil, err | ||
} | ||
|
||
half := len(in.EncryptedVolume.Key) / 2 | ||
tweakMode := "A" | ||
params := &intelmodels.NpiBdevSetKeysParams{ | ||
UUID: bdevUUID, | ||
Key: hex.EncodeToString(in.EncryptedVolume.Key[:half]), | ||
Key2: hex.EncodeToString(in.EncryptedVolume.Key[half:]), | ||
Cipher: "AES_XTS", | ||
Tweak: tweakMode, | ||
} | ||
defer func() { | ||
params = nil | ||
}() | ||
|
||
var result intelmodels.NpiBdevSetKeysResult | ||
err = s.rpc.Call("npi_bdev_set_keys", params, &result) | ||
if err != nil { | ||
log.Println("error:", err) | ||
return nil, server.ErrFailedSpdkCall | ||
} | ||
if !result { | ||
log.Println("Failed result on SPDK call:", result) | ||
return nil, server.ErrUnexpectedSpdkCallResult | ||
} | ||
|
||
return &pb.EncryptedVolume{ | ||
EncryptedVolumeId: &pc.ObjectKey{Value: in.EncryptedVolume.EncryptedVolumeId.Value}, | ||
VolumeId: &pc.ObjectKey{Value: in.EncryptedVolume.VolumeId.Value}, | ||
}, nil | ||
} | ||
|
||
func verifyCreateEncryptedVolumeRequestArgs(in *pb.CreateEncryptedVolumeRequest) error { | ||
switch { | ||
case in == nil: | ||
log.Println("request cannot be empty") | ||
return errMissingArgument | ||
case in.EncryptedVolume == nil: | ||
log.Println("encrypted_volume should be specified") | ||
return errMissingArgument | ||
case in.EncryptedVolume.EncryptedVolumeId == nil || in.EncryptedVolume.EncryptedVolumeId.Value == "": | ||
log.Println("encrypted_volume_id should be specified") | ||
return errMissingArgument | ||
case in.EncryptedVolume.VolumeId == nil || in.EncryptedVolume.VolumeId.Value == "": | ||
log.Println("volume_id should be specified") | ||
return errMissingArgument | ||
case len(in.EncryptedVolume.Key) == 0: | ||
log.Println("key cannot be empty") | ||
return errMissingArgument | ||
} | ||
|
||
keyLengthInBits := len(in.EncryptedVolume.Key) * 8 | ||
expectedKeyLengthInBits := 0 | ||
switch { | ||
case in.EncryptedVolume.Cipher == pb.EncryptionType_ENCRYPTION_TYPE_AES_XTS_256: | ||
expectedKeyLengthInBits = 512 | ||
case in.EncryptedVolume.Cipher == pb.EncryptionType_ENCRYPTION_TYPE_AES_XTS_128: | ||
expectedKeyLengthInBits = 256 | ||
default: | ||
log.Println("only AES_XTS_128 and AES_XTS_256 are supported") | ||
return errNotSupportedCipher | ||
} | ||
|
||
if keyLengthInBits != expectedKeyLengthInBits { | ||
log.Printf("expected key size %vb, provided size %vb", | ||
expectedKeyLengthInBits, keyLengthInBits) | ||
return errWrongKeySize | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *Server) getBdevUUIDByName(name string) (string, error) { | ||
params := spdkmodels.BdevGetBdevsParams{Name: name} | ||
var result []spdkmodels.BdevGetBdevsResult | ||
err := s.rpc.Call("bdev_get_bdevs", params, &result) | ||
if err != nil { | ||
log.Println("error:", err) | ||
return "", server.ErrFailedSpdkCall | ||
} | ||
if len(result) != 1 { | ||
log.Println("Found bdevs:", result, "under the name", params.Name) | ||
return "", server.ErrUnexpectedSpdkCallResult | ||
} | ||
return result[0].UUID, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright (C) 2023 Intel Corporation | ||
|
||
// Package models holds definitions for SPDK json RPC structs | ||
package models | ||
|
||
// NpiBdevSetKeysParams holds the parameters required to set crypto keys | ||
type NpiBdevSetKeysParams struct { | ||
UUID string `json:"uuid"` | ||
Key string `json:"key"` | ||
Key2 string `json:"key2"` | ||
Cipher string `json:"cipher"` | ||
Tweak string `json:"tweak"` | ||
} | ||
|
||
// NpiBdevSetKeysResult is the result of setting crypto keys | ||
type NpiBdevSetKeysResult bool |