Skip to content

Commit

Permalink
Add CreateEncryptedVolume OPI call.
Browse files Browse the repository at this point in the history
Signed-off-by: Artsiom Koltun <[email protected]>
  • Loading branch information
artek-koltun authored and intelfisz committed Apr 11, 2023
1 parent 2f964b2 commit e01c025
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 3 deletions.
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
}
17 changes: 17 additions & 0 deletions pkg/models/spdk.go
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

0 comments on commit e01c025

Please sign in to comment.