Blame plugin/README.md

Packit 534379
# Plugin Architecture #
Packit 534379
The OPAE Plugin Architecture describes the interfaces and data structures
Packit 534379
involved in designing and building the core plugin framework, OPAE compatible
Packit 534379
plugins, and an OPAE application that uses the OPAE API. An OPAE plugin is a
Packit 534379
software library that can be loaded dynamically at runtime and is either
Packit 534379
specific to a given platform or is a proxy for one or more remote endpoints.
Packit 534379
OPAE plugins use the OPAE API for their prototype definitions but are free to
Packit 534379
use any internal data structures and functions in their implementations.
Packit 534379
While it is not required that a plugin implements the complete OPAE API, it
Packit 534379
is required, however, to adhere to the plugin interface. Futhermore, any OPAE
Packit 534379
API functions implemented by a plugin must follow their corresponding
Packit 534379
function interfaces as defined in the OPAE API specification.
Packit 534379
Packit 534379
## Objective ##
Packit 534379
The objective of this document is to provide architectural details about the
Packit 534379
plugin interface as well as the Plugin Manager, the Plugin Loader, and an OPAE
Packit 534379
plugin.
Packit 534379
Packit 534379
The requirements for the Plugin Architecture are as follows:
Packit 534379
* Describe plugin types.
Packit 534379
* Define the plugin interface.
Packit 534379
  This is how plugins register with the OPAE Plugin Manager and includes
Packit 534379
  defining API functions as well as plugin configuration functions.
Packit 534379
* Describe how OPAE API calls are forwarded to an appropriate implementation.
Packit 534379
* Define the C API that applications link to. This API will:
Packit 534379
  * Be a superset of the APIs defined in the existing OPAE C API and any other
Packit 534379
  extension APIs.
Packit 534379
  * Define functions that control how the system is configured and initialized.
Packit 534379
* Use as much of the existing OPAE APIs as possible with few modifications to the API.
Packit 534379
* Define a configuration schema that can be used to configure:
Packit 534379
  * What plugins to load.
Packit 534379
  * Plugin-specific parameters.
Packit 534379
  * Policies for how OPAE APIs are enabled and connected at runtime.
Packit 534379
  * Policies for error handling.
Packit 534379
Packit 534379
While it is possible to use the Plugin Manager to design a framework
Packit 534379
for pooling of OPAE resources, that is outside of the scope of this document.
Packit 534379
While this document and any samples in this document may refer to using remote
Packit 534379
resources, details of how to manage and connect to remote endpoints are also
Packit 534379
out of scope for the plugin architecture, although proxy or remote resources may
Packit 534379
be mentioned.
Packit 534379
Packit 534379
Packit 534379
## High Level Design ##
Packit 534379
In order for a plugin design to be scalable and extensible, some data
Packit 534379
structures and operations should be decoupled and abstracted with well-defined
Packit 534379
interfaces that are used to connect the different components. For OPAE, the
Packit 534379
components that make up the plugin design are the Plugin Manager, Plugin
Packit 534379
Loader, and the Plugin libraries. The following provide brief descriptions of
Packit 534379
these components. More detailed descriptions of these components and their
Packit 534379
interfaces are provided later in this document.
Packit 534379
Packit 534379
### The Plugin Manger ###
Packit 534379
  The Plugin Manager implements the OPAE C API and is responsible for delegating
Packit 534379
  its calls to the appropriate plugin.
Packit 534379
Packit 534379
### The Plugin Loader ###
Packit 534379
  The plugin loader can be considered a component of the Plugin Manager.
Packit 534379
  Its job is to load plugins and initialize them.
Packit 534379
Packit 534379
### Plugin Types ###
Packit 534379
The OPAE codebase and library will include a set of default or native plugins
Packit 534379
that require little to no configuration. The goal of these plugins is to:
Packit 534379
* Be backwards compatible with the devices/drivers currently supported by OPAE.
Packit 534379
* Support remote resources via RDMA transport.
Packit 534379
Packit 534379
### Plugin ###
Packit 534379
  A plugin is a library that implements functions defined in the OPAE API
Packit 534379
  specification. It is called by the Plugin Manager to discover or operate
Packit 534379
  on OPAE resources.
Packit 534379
Packit 534379
Packit 534379
## Interface Design ##
Packit 534379
Packit 534379
Packit 534379
### Plugin Interface ###
Packit 534379
The following list describes features that are compatible with the Plugin Manager and Plugin Loader:
Packit 534379
Packit 534379
Packit 534379
* It must implement a configuration routine in a function called
Packit 534379
  `opae_plugin_configure` to provide a mechanism for any necessary
Packit 534379
  configuration of the plugin. It must follow the following function
Packit 534379
  signature:
Packit 534379
  * The function takes two arguments of type `opae_api_adapter_table *` and  `const char *`.
Packit 534379
    * The first argument is a pointer to an adapter table structure that the
Packit 534379
      Plugin Manager has allocated and pre-initialized. The plugin will set
Packit 534379
      both the API function pointers here as well as the function pointers used
Packit 534379
      by the plugin framework.
Packit 534379
    
Packit 534379
    * The second is a pointer to the configuration data which will be encoded
Packit 534379
      in a JSON structure. In order to avoid introducing dependencies on
Packit 534379
      other libraries, it will be expected that the JSON structure be
Packit 534379
      serialized before passing it to the plugin. It is up to the plugin to
Packit 534379
      determine how it will deserialize the configuration data.
Packit 534379
  * The function must return zero (0) upon successful configuration and a
Packit 534379
  non-zero value otherwise. It is up to the plugin developer to define and
Packit 534379
  document return codes.
Packit 534379
Packit 534379
  The following is an example of the configuration function declaration:
Packit 534379
  ```C
Packit 534379
  int opae_plugin_configure(opae_api_adapter_table *table, const char *jsonConfig);
Packit 534379
  ```
Packit 534379
Packit 534379
* It may define an optional initialization routine in a function called `opae_plugin_initialize` to provide a mechanism for initialization of the plugin. It must follow the function signature:
Packit 534379
  * The function takes no arguments.
Packit 534379
  * The function must return zero (0) upon successful initialization and a non-zero value otherwise. It is up to the plugin developer to define and document return codes.
Packit 534379
Packit 534379
  The following is an example of the initialization function declaration:
Packit 534379
  ```C
Packit 534379
  int opae_plugin_initialize(void);
Packit 534379
  ```
Packit 534379
Packit 534379
* It may define an optional finalization routine in a function called `opae_plugin_finalize` to provide a mechanism for plugin finalization (or any cleanup routines). It must follow the function signature:
Packit 534379
  * The function takes no arguments.
Packit 534379
  * The function must return zero (0) upon successful initialization and a non-zero value otherwise. It is up to the plugin developer to define and document return codes.
Packit 534379
Packit 534379
  The following is an example of the finalization function declaration:
Packit 534379
  ```C
Packit 534379
  int opae_plugin_finalize(void);
Packit 534379
  ```
Packit 534379
Packit 534379
* It may define two optional functions used to indicate if the plugin supports
Packit 534379
  devices based on the device type or the device host. Both functions return
Packit 534379
  bool and both functions take one argument of type `const char*`. The plugin will
Packit 534379
  use the argument to determine if a device is supported, returning true
Packit 534379
  if the device is supported and false otherwise.
Packit 534379
  If either of these functions is set in the adapter table, the function will
Packit 534379
  be called by the OPAE library during enumeration to determine if
Packit 534379
  `fpgaEnumerate` should be called in the plugin.
Packit 534379
Packit 534379
* The `opae_api_adapter_table` is used to fill out a plugin's API and
Packit 534379
  initialization/finalization functions. This structure looks something like:
Packit 534379
Packit 534379
  ```C
Packit 534379
  struct opae_api_adapter_table {
Packit 534379
    ...
Packit 534379
Packit 534379
    fpga_result (*fpgaEnumerate)(const fpga_properties *, uint32_t, fpga_token *, uint32_t, uint32_t *);
Packit 534379
    fpga_result (*fpgaOpen)(fpga_token, fpga_handle *, int);
Packit 534379
    fpga_result (*fpgaClose)(fpga_handle);
Packit 534379
    // ... Other API functions
Packit 534379
Packit 534379
    // configuration functions
Packit 534379
    int (*initialize)(void);
Packit 534379
    int (*finalize)(void);
Packit 534379
Packit 534379
    // first-level query
Packit 534379
    bool (*supports_device)(const char *device_type);
Packit 534379
    bool (*supports_host)(const char *hostname);
Packit 534379
Packit 534379
  }
Packit 534379
  ```
Packit 534379
Packit 534379
* Any OPAE API functions it implements must use the same function signature as
Packit 534379
defined by the OPAE API specification.
Packit 534379
Packit 534379
* The configuration interfaces implemented must have the ABI visibility set to
Packit 534379
  default. This allows the Plugin Manager to lookup this symbol and call it.
Packit 534379
  It is implicitly set by not setting the visibility attribute or by
Packit 534379
  explicitly setting it to default as listed in the example below:
Packit 534379
  ```C
Packit 534379
  #define DLL_PUBLIC __attribute__((visibility ("default")))
Packit 534379
Packit 534379
  int DLL_PUBLIC opae_plugin_configure(opae_api_adapter_table *a, const char *c);
Packit 534379
  ```
Packit 534379
Packit 534379
#### Required Changes to OPAE API ####
Packit 534379
Two new properties will be introduced to the `fpga_properties` structure to
Packit 534379
aid in filtering and identifying resources by device type or by host. These
Packit 534379
two properties are:
Packit 534379
* `host`
Packit 534379
Packit 534379
  This can be a host name or an IP address used to indicate a remote host.
Packit 534379
  For backwards compatibility, the absence of this property in an
Packit 534379
  `fpga_properties` structure will indicate resources on the local host. A
Packit 534379
  proxy plugin for remote endpoints should set the host name of the
Packit 534379
  corresponding endpoints here. To aid in filtering for resources generically
Packit 534379
  by host, the following three keywords will be reserved:
Packit 534379
    * `localhost`
Packit 534379
      This is equivalent to not including a host property and refers to
Packit 534379
      resources on the local host.
Packit 534379
     * `^localhost`
Packit 534379
       This will be used to indicate that the matching criteria exclude local
Packit 534379
       resources (only include resources from remote hosts).
Packit 534379
     * `*`
Packit 534379
       This is a wildcard used to indicate resources on any host (which can
Packit 534379
       be local or remote).
Packit 534379
Packit 534379
* `device type`
Packit 534379
Packit 534379
  This is an enumeration and is used to indicate the device type (or device
Packit 534379
  family) similar to `device id`. However, the difference with `device id` is
Packit 534379
  that a `device id` refers to the ID registered with the PCI ID repository and
Packit 534379
  is unique to one product releaes. A `device type` is broader and refers to a
Packit 534379
  family of devices that include one or more `device ids`. The enumerated
Packit 534379
  values are TBD.
Packit 534379
Packit 534379
The accessor methods that will be added to the OPAE API are:
Packit 534379
* `fpgaPropertiesSetHost(const fpga_properties, fpga_token *, char *)`
Packit 534379
* `fpgaPropertiesGetHost(const fpga_properties, fpga_token *, char *)`
Packit 534379
* `fpgaPropertiesSetDeviceType(const fpga_properties, fpga_device_type)`
Packit 534379
* `fpgaPropertiesGetDeviceType(const fpga_properties, fpga_device_type *)`
Packit 534379
Packit 534379
## Component Designs ##
Packit 534379
Packit 534379
Because the data structures defined in the OPAE API are opaque types, any
Packit 534379
implementation of the API (including the Plugin Manager) is free to define its
Packit 534379
own versions of the concrete types to fit its own implementation.
Packit 534379
Packit 534379
The Plugin Manager defines its internal versions of these concrete types as
Packit 534379
data structures that are composed of both the adapter table and the plugin's instance
Packit 534379
of an opaque type. The Plugin Manager will then use this association to forward
Packit 534379
calls to appropriate function pointers in the adapter table.
Packit 534379
Packit 534379
### Plugin Manager ###
Packit 534379
Packit 534379
The Plugin Manager is the software component that is linked as a shared library
Packit 534379
and implements the OPAE C API. Because it implements the OPAE C API, it can be
Packit 534379
linked at runtime by any application that links against the API. It will then
Packit 534379
forward API calls to the appropriate plugins that have been loaded.
Packit 534379
Packit 534379
The Plugin Manager parses the plugins section of the configuration file to
Packit 534379
determine the list of plugins to load.
Packit 534379
The manager then invokes the Plugin Loader to load each plugin. The result of
Packit 534379
loading a plugin is the adapter table for the plugin. The Plugin Manager
Packit 534379
maintains the following mappings:
Packit 534379
Packit 534379
* Each API adapter table is mapped to its plugin.
Packit 534379
* Each enumerated `fpga_token` is mapped to its plugin.
Packit 534379
* Each opened `fpga_handle` is mapped to its plugin.
Packit 534379
Packit 534379
#### Enumeration ####
Packit 534379
Packit 534379
When the API's main `fpgaEnumerate` is called, the Plugin Manager iterates
Packit 534379
over each loaded plugin, using its adapter table to call the plugin's
Packit 534379
`fpgaEnumerate` entry point. The tokens resulting from an individual
Packit 534379
plugin enumeration are each mapped to the originating plugin. Finally,
Packit 534379
the tokens are collected into the token array for returning to the caller.
Packit 534379
Packit 534379
#### Opening a device ####
Packit 534379
Packit 534379
When the API's main `fpgaOpen` is called, the Plugin Manager resolves
Packit 534379
the given token to its plugin. The adapter table's `fpgaOpen` is then
Packit 534379
invoked. Finally, the resulting `fpga_handle` is mapped to its
Packit 534379
originating plugin, and the handle is returned to the caller.
Packit 534379
Packit 534379
### Plugin Loader ###
Packit 534379
Packit 534379
The plugin loader is responsible for opening each plugin and constructing a
Packit 534379
plugin adapter table based on the contained API entry points. The loader
Packit 534379
calls opae_plugin_configure(), passing a pre-initialized adapter table object
Packit 534379
and any relevant configuration data. It is expected that the plugin set
Packit 534379
function pointer fields in the adapter table that point to API functions
Packit 534379
implemented by the plugin. The adapter table also has fields for setting
Packit 534379
functions defined in the plugin that can be called by the Plugin Manager for
Packit 534379
non API related functionality. These include initialization, finalization, and
Packit 534379
pre-filtering functions that can be used for plugin selection during
Packit 534379
enumeration.
Packit 534379
Packit 534379
### Configuration Schema ###
Packit 534379
The OPAE Plugin system will use JSON for defining any runtime configuration
Packit 534379
parameters. This includes the list of plugins to load, their instance names,
Packit 534379
and their individual configuration data.
Packit 534379
Packit 534379
```JSON
Packit 534379
{
Packit 534379
        "plugins":
Packit 534379
        [
Packit 534379
                {
Packit 534379
                        "module": "libopae-net-proxy",
Packit 534379
                        "name": "tcp-proxy1",
Packit 534379
                        "config": {
Packit 534379
                                "transport": "tcp",
Packit 534379
                                "discovery": "none",
Packit 534379
                                "hosts": ["host1", "host2", "host3"]
Packit 534379
                        },
Packit 534379
                        "load_policy" : {}
Packit 534379
                },
Packit 534379
                {
Packit 534379
                        "module": "libopae-net-proxy",
Packit 534379
                        "name": "rdma-proxy1",
Packit 534379
                        "config": {
Packit 534379
                                "transport": "rdma",
Packit 534379
                                "discovery": "none",
Packit 534379
                                "hosts": ["host1", "host2", "host3"]
Packit 534379
                        },
Packit 534379
                        "load_policy": {}
Packit 534379
                }
Packit 534379
        ]
Packit 534379
}
Packit 534379
```
Packit 534379
Packit 534379
## Example Use Case ##
Packit 534379
Packit 534379
The diagrams below illustrate a case of a client application linking to the
Packit 534379
plugin-enabled OPAE library. The Plugin Manager in OPAE is responsible for
Packit 534379
managing plugins and forwarding API function calls to any plugins that have
Packit 534379
been registered. The Plugin Manager wraps any API data structures
Packit 534379
(`fpga_token`, `fpga_handle`) created by API functions in any of its
Packit 534379
registered plugins in its own version of the data structures before returning
Packit 534379
them to the client application. When operating on its own API data
Packit 534379
structures, it will unwrap them to get a plugin's API data structure along
Packit 534379
with its adapter table.
Packit 534379
Packit 534379
### Initialization ###
Packit 534379
This first diagram below shows the initialization sequence when the OPAE
Packit 534379
library is first loaded. The initialization routine in the OPAE library can
Packit 534379
either be called explicitly from the client application or implicitly by the
Packit 534379
library's constructor. In either case, when the initialization routine is
Packit 534379
called, it parses the configuration file to get configuration parameters for
Packit 534379
any of its plugins (including native plugins). As mentioned in [Plugin
Packit 534379
Types](#plugin-types) section, native plugins should require little or no
Packit 534379
configuration. However, any configuration parameters that can be overridden
Packit 534379
can be included in the configuration file. See the psuedo-code for the
Packit 534379
[Plugin Manager](cpseudo.md#plugin-manager) and [Plugin
Packit 534379
Loader](cpseudo.md#plugin-loader) for skeleton implementations.
Packit 534379
![plugin initialization](plugin_init.svg)
Packit 534379
Packit 534379
### OPAE Stack ###
Packit 534379
Calling OPAE API functions requires going up and down the OPAE SW stack.
Packit 534379
These examples refer to the SW stack with respect to the OPAE usermode APIs.
Packit 534379
Refer to the pseudocode for skeleton implementations of routines for API
Packit 534379
functions in the [OPAE Stack](cpseudo.md#opae-stack).
Packit 534379
Packit 534379
#### Enumeration ####
Packit 534379
This next diagram below shows the enumeration flow from a client application
Packit 534379
to an arbitrary plugin, A. The filter, a set of `fpga_properties` objects, is
Packit 534379
passed to the plugin. Upon successful enumeration by the plugin, it returns a
Packit 534379
set of `fpga_token` structures (A_tokens) to the caller (the
Packit 534379
OPAE.PluginManager). For each token in the returned tokens, the Plugin
Packit 534379
Manager wraps these tokens into its own internal token data structure which
Packit 534379
is composed of the token from the plugin and the adapter table that contains
Packit 534379
the plugin's API functions.
Packit 534379
Packit 534379
![enumeration](plugin_enum.svg)
Packit 534379
Packit 534379
#### Opening a Resource ####
Packit 534379
Opening a resource requires unwrapping an `fpga_token` object by the Plugin
Packit 534379
Manager to get both the plugin's adapter table and the plugin's version of
Packit 534379
the `fpga_token` object. It then calls the `open` function in the adapter
Packit 534379
table with the plugin's token (or the wrapped token). The diagram below shows
Packit 534379
this sequence of events.
Packit 534379
Packit 534379
![opening a resource](plugin_open.svg)
Packit 534379
Packit 534379
#### Remote Enumeration ####
Packit 534379
The pseudo-code for [Proxy Plugins](cpseudo.md#proxy-plugins) outlines notional
Packit 534379
implementations for the two kinds of proxy plugins. The diagram below
Packit 534379
illustrates the general sequence.
Packit 534379
![remote enumeration](plugin_remote.svg)