Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CreateEncryptedVolume OPI call #79

Merged
merged 2 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (
"net"

fe "github.com/opiproject/opi-intel-bridge/pkg/frontend"
me "github.com/opiproject/opi-intel-bridge/pkg/middleend"
"github.com/opiproject/opi-smbios-bridge/pkg/inventory"
"github.com/opiproject/opi-spdk-bridge/pkg/backend"
"github.com/opiproject/opi-spdk-bridge/pkg/frontend"
"github.com/opiproject/opi-spdk-bridge/pkg/middleend"
"github.com/opiproject/opi-spdk-bridge/pkg/server"
"github.com/opiproject/opi-strongswan-bridge/pkg/ipsec"

Expand Down Expand Up @@ -45,15 +45,15 @@ func main() {
frontendOpiIntelServer := fe.NewServer(jsonRPC)
frontendOpiSpdkServer := frontend.NewServer(jsonRPC)
backendOpiSpdkServer := backend.NewServer(jsonRPC)
middleendOpiSpdkServer := middleend.NewServer(jsonRPC)
middleendOpiIntelServer := me.NewServer(jsonRPC)

pb.RegisterFrontendNvmeServiceServer(s, frontendOpiIntelServer)
pb.RegisterFrontendVirtioBlkServiceServer(s, frontendOpiSpdkServer)
pb.RegisterFrontendVirtioScsiServiceServer(s, frontendOpiSpdkServer)
pb.RegisterNVMfRemoteControllerServiceServer(s, backendOpiSpdkServer)
pb.RegisterNullDebugServiceServer(s, backendOpiSpdkServer)
pb.RegisterAioControllerServiceServer(s, backendOpiSpdkServer)
pb.RegisterMiddleendServiceServer(s, middleendOpiSpdkServer)
pb.RegisterMiddleendServiceServer(s, middleendOpiIntelServer)
pc.RegisterInventorySvcServer(s, &inventory.Server{})
ps.RegisterIPsecServer(s, &ipsec.Server{})

Expand Down
155 changes: 155 additions & 0 deletions pkg/middleend/middleend.go
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
}
Loading