[lighty.io] Open-Source gNMI RESTCONF Application

The lighty.io gNMI RESTCONF plugin allows for easy manipulation of gNMI devices. PANTHEON.tech has open-sourced the gNMI RESTCONF app for lighty.io, to increase the capabilities of lighty.io for different implementations and solutions.

Imagine CRUD operation on multiple gNMI devices, managed by one application – lighty.io. All requests towards the gNMI devices are executed by RESTCONF operations, while the response is formatted in JSON.

The most important lighty.io components used in the lighty.io gNMI RESTCONF application are:

  • lighty.io Controller – provides core OpenDaylight services (MD-SAL, YANG Tools, Global Schema Context & more) that are required for other services or plugins
  • lighty.io RESTCONF Northbound – provides the RESTCONF interface, used for communication with the application, via the RESTCONF protocol over HTTP
  • lighty.io gNMI Southbound – acts as the gNMI client. Manages connections to gNMI devices and gNMI communication. Currently supported gNMI capabilities are Get & Set

Prerequisites

To build and start the lighty.io gNMI RESTCONF application locally, you need:

  •  Java 11 or later
  •  Maven 3.5.4 or later

Custom Configuration

Before the lighty gNMI RESTCONF app creates a mount point for communicating with the gNMI device, it is necessary to create a schema context. This schema context is created, based on the YANG files which the device implements. These models are obtained via the gNMI Capability response, but only model names and versions are actually returned. Thus, we need some way of providing the content of the YANG model.

The way of providing content for the YANG file, so lighty.io gNMI RESTCONF can correctly create schema context, is to:

  • add a parameter to the RCGNMI app .json configuration
  • use upload-yang-model RPC

Both of these options will load the YANG files into the data-store, from which the ligthy.io gNMI RESTCONF reads the model, based on its name and version, obtained in the gNMI Capability response.

YANG Model Configuration as a Parameter

  1. Open the custom configuration example in src/main/resources/example_config.json
  2. Add custom gNMI configuration in root, next to the controller or RESTCONF configuration
 ```
      "gnmi": {
        "initialYangsPaths" : [
          "INITIAL_FOLDER_PATH"
        ]
      }
    ```
    3. Change `INITIAL_FOLDER_PATH`, from JSON block above, to folder path, which contains YANG models you wish to
    load into datastore. These models will be then automatically loaded on startup.

2) Add yang model with RPC request to running app
- 'YANG_MODEL' - Should have included escape characters before each double quotation marks character.
```
curl --request POST 'http://127.0.0.1:8888/restconf/operations/gnmi-yang-storage:upload-yang-model' \
--header 'Content-Type: application/json' \
--data-raw '{
    "input": {
        "name": "openconfig-interfaces",
        "semver": "2.4.3",
        "body": "YANG_MODEL"
    }
}'
```

Start the gNMI RESTCONF Example App

1. Build the project using:

mvn clean install

2. Go to the target directory:

cd lighty-rcgnmi-app/target

3. Unzip example application bundle:

unzip  lighty-rcgnmi-app-14.0.1-SNAPSHOT-bin.zip

4. Go to the unzipped application directory:

cd lighty-rcgnmi-app-14.0.1-SNAPSHOT

5. To start the application with a custom lighty.io configuration, use arg -c. For a custom initial log4j configuration, use the argument -l:

start-controller.sh -c /path/to/config-file -l /path/to/log4j-config-file

Using the gNMI RESTCONF Example App

Register Certificates

Certificates, used for connecting to a device, can be stored inside the lighty-gnmi data store. The certificate key and passphrase are encrypted before they are stored inside the data store.

After registering the certificate key and passphrase, it is not possible to get decrypted data back from the data store.

curl --request POST 'http://127.0.0.1:8888/restconf/operations/gnmi-certificate-storage:add-keystore-certificate' \
--header 'Content-Type: application/json' \
--data-raw '{
    "input": {
        "keystore-id": "keystore-id-1",
        "ca-certificate": "-----BEGIN CERTIFICATE-----
                              CA-CERTIFICATE
                          -----END CERTIFICATE-----",
        "client-key": "-----BEGIN RSA PRIVATE KEY-----
                                CLIENT-KEY
                      -----END RSA PRIVATE KEY-----",
        "passphrase": "key-passphrase",
        "client-cert": "-----BEGIN CERTIFICATE-----
                              CLIENT_CERT
                        -----END CERTIFICATE-----"
    }
}'

Remove Certificates

curl --location --request POST 'http://127.0.0.1:8888/restconf/operations/gnmi-certificate-storage:remove-keystore-certificate' \
--header 'Content-Type: application/json' \
--data-raw '{
    "input": {
        "keystore-id": "keystore-id-1"
    }
}'

Update Certificates

To update the already existing certificates, use the request for registering a new certificate with the keystore-id you wish to update.

Connecting a gNMI Device

To establish a connection and communication with the gNMI device via RESTCONF, one needs to add a new node to gnmi-topology. This is done by sending the appropriate requests (examples below) with a unique node-id.

The connection parameters are used to specify connection parameters and the client’s (lighty gNMI RESTCONF) way of authenticating.

The property connection-type is enum and can be set to two values:

  • INSECURE: Skip TLS validation with certificates
  • PLAINTEXT:  Disable TLS validation

When the device requires the client to authenticate with registered certificates, remove the connection-type property. Then, add the keystore-id property with the ID of the registered certificates.

If the device requires username/password validation, then fill username and password in the credentials container. This container is optional.

In case the device requires additional parameters in the gNMI request/response, there is a container called extensions-parameters, where a defined set of parameters can be optionally included in the gNMI request and response. Those parameters are:

  • overwrite-data-type is used to overwrite the type field of gNMI GetRequest.
  • use-model-name-prefix is used when the device requires a module prefix in the first element name of gNMI request path
  • path-target is used to specify the context of a particular stream of data and is only set in prefix for a path
curl --request PUT 'http://127.0.0.1:8888/restconf/data/network-topology:network-topology/topology=gnmi-topology/node=node-id-1' \
--header 'Content-Type: application/json' \
--data-raw '{
    "node": [
        {
            "node-id": "node-id-1",
            "connection-parameters": {
                "host": "127.0.0.1",
                "port": 9090,
                "connection-type": "INSECURE",
                "credentials": {
                    "username": "admin",
                    "password": "admin"
                }
            }
        }
    ]
}'

Create a Mountpoint with Custom Certificates

curl --request PUT 'http://127.0.0.1:8888/restconf/data/network-topology:network-topology/topology=gnmi-topology/node=node-id-1' \
--header 'Content-Type: application/json' \
--data-raw '{
    "node": [
        {
            "node-id": "node-id-1",
            "connection-parameters": {
                "host": "127.0.0.1",
                "port": 9090,
                "keystore-id": "keystore-id-1",
                "credentials": {
                    "username": "admin",
                    "password": "admin"
                }
            }
        }
    ]
}'

Get State of Registered gNMI Device

curl --request GET 'http://127.0.0.1:8888/restconf/data/network-topology:network-topology/topology=gnmi-topology/node=node-id-1'

[Example] RESTCONF gNMI GetRequest

curl --location --request GET 'http://127.0.0.1:8888/restconf/data/network-topology:network-topology/topology=gnmi-topology/node=node-id-1/yang-ext:mount/openconfig-interfaces:interfaces'

[Example] RESTCONF gNMI SetRequest

curl --request PUT 'http://127.0.0.1:8888/restconf/data/network-topology:network-topology/topology=gnmi-topology/node=node-id-1/yang-ext:mount/interfaces/interface=br0/ethernet/config' \
--header 'Content-Type: application/json' \
--data-raw '{
    "openconfig-if-ethernet:config": {
        "enable-flow-control": false,
        "openconfig-if-aggregate:aggregate-id": "admin",
        "auto-negotiate": true,
        "port-speed": "openconfig-if-ethernet:SPEED_10MB"
    }
}'

Disconnect gNMI Device

curl --request DELETE 'http://127.0.0.1:8888/restconf/data/network-topology:network-topology/topology=gnmi-topology/node=node-id-1'

[RESTCONF] gNMI Operations Mapping

The supported HTTP methods are listed below:

YANG Node TypeHTTP Method
Configuration DataPOST, PUT, PATCH, DELETE, GET
Non-Configuration DataGET
YANG RPCPOST

For each REST request, the lighty.io gNMI  RESTCONF app invokes the appropriate gNMI operation GnmiSet/GnmiGet to process the request.

Below is the mapping of HTTP operations to gNMI operations:

HTTP MethodgNMI OperationRequest DataResponse Data
GETGnmiGetpathstatus, payload
POSTGnmiSetpath, payloadstatus
PATCHGnmiSetpath, payloadstatus
PUTGnmiSetpath, payloadstatus
DELETEGnmiSetpath, payloadstatus

[RESTCONF] GET Method Mapping

In both cases, we will be reading data, but from different data stores.

  • Reading data from the operational datastore invokes readOperationalData() in GnmiGet:
src/main/java/io/lighty/gnmi/southbound/mountpoint/ops/GnmiGet.java
  • Reading data from the configuration datastore invokes readConfigurationData() in GnmiGet:
src/main/java/io/lighty/gnmi/southbound/mountpoint/ops/GnmiGet.java

[RESTCONF] PUT/POST/PATCH/DELETE Method Mapping

  • Sending data to operational/configuration datastore invokes method set() in GnmiSet:
src/main/java/io/lighty/gnmi/southbound/mountpoint/ops/GnmiSet.java

A list of input parameters come from method request in the form of fields of update messages: update, replace, and delete fields.

  • PUT/POST request method sends update messages through two fields: update and replaces fields
  • PATCH request method sends update messages through the update field
  • DELETE request method sends update messages through the delete field

Further Support & Questions

PANTHEON.tech open-sourced lighty.io a while ago, giving the community a unique chance to discover the power of lighty.io in their SDN solution.

If you require enterprise support, integration, or training, make sure to contact us so we can help you catch up with the future of networking.


by Martin Bugáň, Ivan Čaládi, Peter Šuňa & Marek Zaťko