179a3ac88SKonrad Sztyber# Storage Management Agent {#sma} 279a3ac88SKonrad Sztyber 379a3ac88SKonrad SztyberStorage Management Agent (SMA) is a service providing a gRPC interface for 479a3ac88SKonrad Sztyberorchestrating SPDK applications. It's a standalone application that allows 579a3ac88SKonrad Sztyberusers to create and manage various types of devices (e.g. NVMe, virtio-blk, 679a3ac88SKonrad Sztyberetc.). The major difference between SMA's API and the existing SPDK-RPC 779a3ac88SKonrad Sztyberinterface is that it's designed to abstract the low level details exposed by 879a3ac88SKonrad SztyberSPDK-RPCs, which enables it to be more easily consumed by orchestration 979a3ac88SKonrad Sztyberframeworks, such as k8s or OpenStack. This is especially important for 1079a3ac88SKonrad Sztyberdeployments on IPUs (Infrastructure Processing Unit), which usually require a 1179a3ac88SKonrad Sztyberlot of hardware-specific options. 1279a3ac88SKonrad Sztyber 1379a3ac88SKonrad Sztyber## Interface 1479a3ac88SKonrad Sztyber 1557cf8961SJohn KariukiThe interface is defined in a protobuf files located in `proto` 1679a3ac88SKonrad Sztyberdirectory. The generic interface common to all types of devices is defined in 1779a3ac88SKonrad Sztyber`sma.proto` file, while device-specific options are defined in their separate 1879a3ac88SKonrad Sztyberfiles (e.g. `nvme.proto` for NVMe). 1979a3ac88SKonrad Sztyber 2079a3ac88SKonrad SztyberCurrently, the interface consists of four methods. Additionally, it defines two 2179a3ac88SKonrad Sztybermain types of objects: volumes and devices. A volume is a representation of 2279a3ac88SKonrad Sztybersome storage media. It is equivalent to a SPDK bdev and/or an NVMe namespace 2379a3ac88SKonrad Sztyberand can exist even if it's not presented to the host system. A device is 2479a3ac88SKonrad Sztyberusually a virtual/physical PCIe function that is exposed to a host. It is 2579a3ac88SKonrad Sztybercapable of presenting one or more volumes (depending on the type of the device) 2679a3ac88SKonrad Sztyberto a host. 2779a3ac88SKonrad Sztyber 2879a3ac88SKonrad SztyberThe following sections provide a high-level description of each method. For 2979a3ac88SKonrad Sztybermore details, consult the protobuf definitions. 3079a3ac88SKonrad Sztyber 3179a3ac88SKonrad Sztyber### CreateDevice 3279a3ac88SKonrad Sztyber 3379a3ac88SKonrad SztyberThis method creates a device. If a device with given parameters already exists, 3479a3ac88SKonrad Sztyberit becomes a no-op and returns a handle to that device. 3579a3ac88SKonrad Sztyber 3679a3ac88SKonrad SztyberInput: 3779a3ac88SKonrad Sztyber 3879a3ac88SKonrad Sztyber- `volume`: Volume parameters describing a volume to immediately attach to the 3979a3ac88SKonrad Sztyber created device. This field may be optional for some device types (e.g. NVMe), 40*8de3c57fSMichal Rozegnal while it may be required for others (e.g. virtio-blk). Extending parameters with 41*8de3c57fSMichal Rozegnal crypto attributes like encryption type, keys, tweak mode allows the user to configure 42*8de3c57fSMichal Rozegnal crypto when attaching a volume to a device. Users must specify the crypto engine 43*8de3c57fSMichal Rozegnal to use under `crypto` section in config. It is also possible to register out-of-tree 44*8de3c57fSMichal Rozegnal crypto engines by inheriting from the `CryptoEngine` class. 4579a3ac88SKonrad Sztyber- `params`: Device-specific parameters. The type of this structure determines 4679a3ac88SKonrad Sztyber the type of device to create. 4779a3ac88SKonrad Sztyber 4879a3ac88SKonrad SztyberOutput: 4979a3ac88SKonrad Sztyber 5079a3ac88SKonrad Sztyber- `handle`: Opaque handle identifying the device. 5179a3ac88SKonrad Sztyber 5279a3ac88SKonrad Sztyber### DeleteDevice 5379a3ac88SKonrad Sztyber 5479a3ac88SKonrad SztyberThis method deletes a device. Volumes that are still attached to a device being 5579a3ac88SKonrad Sztyberdeleted will be automatically detached. 5679a3ac88SKonrad Sztyber 5779a3ac88SKonrad SztyberInput: 5879a3ac88SKonrad Sztyber 5979a3ac88SKonrad Sztyber- `handle`: Device handle obtained from `CreateDevice`. 6079a3ac88SKonrad Sztyber 6179a3ac88SKonrad Sztyber### AttachVolume 6279a3ac88SKonrad Sztyber 6379a3ac88SKonrad SztyberThis method creates a volume and attaches it to a device exposing it to the 6479a3ac88SKonrad Sztyberhost. It might lead to establishing a connection to remote storage target. 6579a3ac88SKonrad SztyberHowever, this is not always the case, even if the volume is remote. For 6679a3ac88SKonrad Sztyberinstance, if a volume describes an NVMe namespace, it might already be connected 6779a3ac88SKonrad Sztyberif another volume on the same subsystem was created previously. It may be 6879a3ac88SKonrad Sztyberunsupported by some types of devices (e.g. virtio-blk). 6979a3ac88SKonrad Sztyber 7079a3ac88SKonrad SztyberInput: 7179a3ac88SKonrad Sztyber 7279a3ac88SKonrad Sztyber- `volume`: Parameters describing the volume to attach. The type of this 7379a3ac88SKonrad Sztyber structure determines the method to create it (e.g. direct NVMe-oF connection, 74*8de3c57fSMichal Rozegnal NVMe-oF through discovery service, iSCSI, etc.). Extending parameters with 75*8de3c57fSMichal Rozegnal crypto attributes like type, keys, tweak mode allowing the user to configure crypto 76*8de3c57fSMichal Rozegnal when attaching a volume to a device. Users must specify the crypto engine to use under 77*8de3c57fSMichal Rozegnal `crypto` section in config. It is also possible to register out-of-tree crypto engines 78*8de3c57fSMichal Rozegnal by inheriting from the `CryptoEngine` class. 7979a3ac88SKonrad Sztyber- `device_handle`: Device handle obtained from `CreateDevice`. 8079a3ac88SKonrad Sztyber 8179a3ac88SKonrad Sztyber### DetachVolume 8279a3ac88SKonrad Sztyber 8379a3ac88SKonrad SztyberThis method detaches a volume from a device making it unavailable to the host. 8479a3ac88SKonrad SztyberIt may be unsupported by some types of devices (e.g. virtio-blk). 8579a3ac88SKonrad Sztyber 8679a3ac88SKonrad SztyberInput: 8779a3ac88SKonrad Sztyber 8879a3ac88SKonrad Sztyber- `volume_id`: Volume UUID/GUID. 8979a3ac88SKonrad Sztyber- `device_handle`: Device handle obtained from `CreateDevice`. 9079a3ac88SKonrad Sztyber 91*8de3c57fSMichal Rozegnal### SetQos 92*8de3c57fSMichal Rozegnal 93*8de3c57fSMichal RozegnalThis method configures QoS on a per-device or per-volume level. 94*8de3c57fSMichal RozegnalNot all QoS settings have to be supported by each device, so users 95*8de3c57fSMichal Rozegnalcan use `GetQosCapabilities` to get capabilities. 96*8de3c57fSMichal Rozegnal 97*8de3c57fSMichal RozegnalInput: 98*8de3c57fSMichal Rozegnal 99*8de3c57fSMichal Rozegnal- `handle`: Device handle obtained from `CreateDevice`. 100*8de3c57fSMichal Rozegnal- `volume_id`: Volume UUID/GUID. If this parameter is omitted, the QoS will be set up 101*8de3c57fSMichal Rozegnal on the whole device (all volumes attached to that device will share QoS settings). 102*8de3c57fSMichal Rozegnal Some device types might only support configuring QoS on per-device 103*8de3c57fSMichal Rozegnal (volume_id must be empty) or per-volume level (volume_id cannot be empty). 104*8de3c57fSMichal Rozegnal This information can be obtained by sending a GetQosCapabilities request. 105*8de3c57fSMichal Rozegnal- `maximum`: Maximum allowed IOPS/bandwidth values. 106*8de3c57fSMichal Rozegnal 107*8de3c57fSMichal Rozegnal### GetQosCapabilities 108*8de3c57fSMichal Rozegnal 109*8de3c57fSMichal RozegnalThis method queries supported QoS settings. 110*8de3c57fSMichal Rozegnal 111*8de3c57fSMichal RozegnalInput: 112*8de3c57fSMichal Rozegnal 113*8de3c57fSMichal Rozegnal- `device_type`: Type of a device to query for QoS capabilities. 114*8de3c57fSMichal Rozegnal 115*8de3c57fSMichal RozegnalOutput: 116*8de3c57fSMichal Rozegnal 117*8de3c57fSMichal Rozegnal- `capabilities`: QoS capabilities response including device/volume 118*8de3c57fSMichal Rozegnal QoS limits like read IOPS, write IOPS, read/write IOPS, read bandwidth, 119*8de3c57fSMichal Rozegnal write bandwidth, read/write bandwidth. 120*8de3c57fSMichal Rozegnal 12179a3ac88SKonrad Sztyber## Running and Configuration 12279a3ac88SKonrad Sztyber 12379a3ac88SKonrad SztyberIn order to run SMA, SPDK needs to be configured with the `--with-sma` flag. 12479a3ac88SKonrad SztyberThen, SMA can be started using a script located in `scripts/sma.py`. It 12579a3ac88SKonrad Sztyberrequires a YAML configuration file that specifies which types of devices to 12679a3ac88SKonrad Sztyberservice, as well as several other options (e.g. listen address, SPDK-RPC socket, 12779a3ac88SKonrad Sztyberetc.). Device types not listed in the configuration will be disabled and it 12879a3ac88SKonrad Sztyberwon't be possible to manage them. Below is an example configuration enabling 12979a3ac88SKonrad Sztybertwo device types (NVMe/vfiouser and vhost-blk): 13079a3ac88SKonrad Sztyber 13179a3ac88SKonrad Sztyber```yaml 13279a3ac88SKonrad Sztyberaddress: 'localhost' 13379a3ac88SKonrad Sztybersocket: '/var/tmp/spdk.sock' 13479a3ac88SKonrad Sztyberport: 8080 13579a3ac88SKonrad Sztyberdevices: 13679a3ac88SKonrad Sztyber - name: 'vfiouser' 13779a3ac88SKonrad Sztyber params: 13879a3ac88SKonrad Sztyber root_path: '/var/tmp/vfiouser' 13979a3ac88SKonrad Sztyber bus: 'bus0' 14079a3ac88SKonrad Sztyber address: '127.0.0.1' 14179a3ac88SKonrad Sztyber port: 4444 14279a3ac88SKonrad Sztyber - name: 'vhost-blk' 14379a3ac88SKonrad Sztyber``` 14479a3ac88SKonrad Sztyber 14579a3ac88SKonrad Sztyber## Plugins 14679a3ac88SKonrad Sztyber 14779a3ac88SKonrad SztyberSMA provides a way to load external plugins implementing support for specific 14879a3ac88SKonrad Sztyberdevice types. A plugin will be loaded if it's specified in the `SMA_PLUGINS` 14979a3ac88SKonrad Sztyberenvironment variable (multiple plugins are separated with a colon) or if it's 15079a3ac88SKonrad Sztyberspecified in the `plugins` section of the config file. For example, the 15179a3ac88SKonrad Sztyberfollowing two methods are equivalent: 15279a3ac88SKonrad Sztyber 15379a3ac88SKonrad Sztyber```sh 15479a3ac88SKonrad Sztyber$ SMA_PLUGINS=plugin1:plugin2 scripts/sma.py 15579a3ac88SKonrad Sztyber 15679a3ac88SKonrad Sztyber$ cat sma.yaml 15779a3ac88SKonrad Sztyberaddress: 'localhost' 15879a3ac88SKonrad Sztyberport: 8080 15979a3ac88SKonrad Sztyberplugins: 16079a3ac88SKonrad Sztyber - 'plugin1' 16179a3ac88SKonrad Sztyber - 'plugin2' 16279a3ac88SKonrad Sztyberdevices: 16379a3ac88SKonrad Sztyber - name: 'device-from-plugin1' 16479a3ac88SKonrad Sztyber - name: 'device-from-plugin2' 16579a3ac88SKonrad Sztyber$ scripts/sma.py -c sma.yaml 16679a3ac88SKonrad Sztyber``` 16779a3ac88SKonrad Sztyber 16879a3ac88SKonrad SztyberEach plugin needs to be in the python search path (either in one of the default 16979a3ac88SKonrad Sztyberdirectories or added to `PYTHONPATH`). 17079a3ac88SKonrad Sztyber 17179a3ac88SKonrad SztyberA plugin is required to define a global variable called `devices` storing a list 17279a3ac88SKonrad Sztyberof classes deriving from `spdk.sma.DeviceManager`. This base class define the 17379a3ac88SKonrad Sztyberinterface each device needs to implement. Additionally, each DeviceManager 17479a3ac88SKonrad Sztyberneeds to define a unique name that will be used to identify it in config file as 17579a3ac88SKonrad Sztyberwell as the name of the protocol it supports. There can be many DeviceManagers 17679a3ac88SKonrad Sztybersupporting the same protocol, but only one can be active at a time. The name of 17779a3ac88SKonrad Sztyberthe protocol shall match the type specified in `CreateDeviceRequest.params` 17879a3ac88SKonrad Sztyber(e.g. "nvme", "virtio_blk", etc.), as it'll be used to select the DeviceManager 17979a3ac88SKonrad Sztyberto handle a gRPC request. Finally, a DeviceManager needs to implement the 18079a3ac88SKonrad Sztyber`own_device()` method returning a boolean value indicating whether a given 18179a3ac88SKonrad Sztyberdevice handle is owned by that DeviceManager. 182