Spdk/python/spdk/rpc/__init__.py
Changpeng Liu da231290b2 lib/vfu_tgt: add library for PCI device emulation
Previously SPDK use libvfio-user library to provide emulated NVMe
devices to VM, but it's limited to NVMe device type only.  Here we
add SPDK vfu_target library abstraction based on libvfio-user which
supports more PCI device types.

We will add virtio-blk and virtio-scsi devices emulation based on
vfu_tgt library in following patches, actually this library can
support NVMe emulation too, due to the fact that the NVMe emulation
is already exist, so we will keep the NVMe emulation which based on
libvfio-user directly as it is.

Change-Id: Ib0ead6c6118fa62308355fe432003dd928a2fae9
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12597
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
2022-09-29 19:42:56 +00:00

199 lines
5.6 KiB
Python

import json
import os
import sys
from io import IOBase as io
from . import accel
from . import app
from . import bdev
from . import blobfs
from . import env_dpdk
from . import dsa
from . import iaa
from . import ioat
from . import iscsi
from . import log
from . import lvol
from . import nbd
from . import notify
from . import nvme
from . import nvmf
from . import pmem
from . import subsystem
from . import trace
from . import vhost
from . import vmd
from . import sock
from . import vfio_user
from . import client as rpc_client
def framework_start_init(client):
"""Start initialization of subsystems"""
return client.call('framework_start_init')
def framework_wait_init(client):
"""Block until subsystems have been initialized"""
return client.call('framework_wait_init')
def rpc_get_methods(client, current=None, include_aliases=None):
"""Get list of supported RPC methods.
Args:
current: Get list of RPC methods only callable in the current state.
include_aliases: Include aliases in the list with RPC methods.
"""
params = {}
if current:
params['current'] = current
if include_aliases:
params['include_aliases'] = include_aliases
return client.call('rpc_get_methods', params)
def spdk_get_version(client):
"""Get SPDK version"""
return client.call('spdk_get_version')
def _json_dump(config, fd, indent):
if indent is None:
indent = 2
elif indent < 0:
indent = None
json.dump(config, fd, indent=indent)
fd.write('\n')
def _json_load(j):
if j == sys.stdin or isinstance(j, io):
json_conf = json.load(j)
elif os.path.exists(j):
with open(j, "r") as j:
json_conf = json.load(j)
else:
json_conf = json.loads(j)
return json_conf
def save_config(client, fd, indent=2):
"""Write current (live) configuration of SPDK subsystems and targets to stdout.
Args:
fd: opened file descriptor where data will be saved
indent: Indent level. Value less than 0 mean compact mode.
Default indent level is 2.
"""
config = {
'subsystems': []
}
for elem in client.call('framework_get_subsystems'):
cfg = {
'subsystem': elem['subsystem'],
'config': client.call('framework_get_config', {"name": elem['subsystem']})
}
config['subsystems'].append(cfg)
_json_dump(config, fd, indent)
def load_config(client, fd, include_aliases=False):
"""Configure SPDK subsystems and targets using JSON RPC read from stdin.
Args:
fd: opened file descriptor where data will be taken from
"""
json_config = _json_load(fd)
# remove subsystems with no config
subsystems = json_config['subsystems']
for subsystem in list(subsystems):
if not subsystem['config']:
subsystems.remove(subsystem)
# check if methods in the config file are known
allowed_methods = client.call('rpc_get_methods', {'include_aliases': include_aliases})
if not subsystems and 'framework_start_init' in allowed_methods:
framework_start_init(client)
return
for subsystem in list(subsystems):
config = subsystem['config']
for elem in list(config):
if 'method' not in elem or elem['method'] not in allowed_methods:
raise rpc_client.JSONRPCException("Unknown method was included in the config file")
while subsystems:
allowed_methods = client.call('rpc_get_methods', {'current': True,
'include_aliases': include_aliases})
allowed_found = False
for subsystem in list(subsystems):
config = subsystem['config']
for elem in list(config):
if 'method' not in elem or elem['method'] not in allowed_methods:
continue
client.call(**elem)
config.remove(elem)
allowed_found = True
if not config:
subsystems.remove(subsystem)
if 'framework_start_init' in allowed_methods:
framework_start_init(client)
allowed_found = True
if not allowed_found:
break
if subsystems:
print("Some configs were skipped because the RPC state that can call them passed over.")
def save_subsystem_config(client, fd, indent=2, name=None):
"""Write current (live) configuration of SPDK subsystem to stdout.
Args:
fd: opened file descriptor where data will be saved
indent: Indent level. Value less than 0 mean compact mode.
Default is indent level 2.
"""
cfg = {
'subsystem': name,
'config': client.call('framework_get_config', {"name": name})
}
_json_dump(cfg, fd, indent)
def load_subsystem_config(client, fd):
"""Configure SPDK subsystem using JSON RPC read from stdin.
Args:
fd: opened file descriptor where data will be taken from
"""
subsystem = _json_load(fd)
if not subsystem['config']:
return
allowed_methods = client.call('rpc_get_methods')
config = subsystem['config']
for elem in list(config):
if 'method' not in elem or elem['method'] not in allowed_methods:
raise rpc_client.JSONRPCException("Unknown method was included in the config file")
allowed_methods = client.call('rpc_get_methods', {'current': True})
for elem in list(config):
if 'method' not in elem or elem['method'] not in allowed_methods:
continue
client.call(**elem)
config.remove(elem)
if config:
print("Some configs were skipped because they cannot be called in the current RPC state.")