Skip to content
Renato Westphal edited this page Aug 22, 2024 · 6 revisions

The Holo daemon includes a gRPC module that can be used to configure and monitor the daemon programatically. The module is enabled by default and listens on the 50051 TCP port.

The interface's definition is specified in the holo.proto file, available at https://github.com/rwestphal/holo/blob/master/proto/holo.proto.

Compared to the gNMI interface, the gRPC interface is simpler and supports the following additional features:

  • Confirmed commits: Commits are rolled back if they are not confirmed within a specified time frame.
  • Configuration validation: Allows validation of configurations without committing them.
  • Configuration rollbacks: Provides support for reverting to previous configurations stored in non-volatile memory.
  • Network-wide transactions: The ability to update the entire network in a pseudo-atomic fashion. This means that either all devices are updated, or none of them are.
  • Use of YANG Patch to update the running configuration.
  • YANG RPC/Action support: Enables the invocation of YANG-modeled RPCs, such as clearing protocol statistics or resetting neighborships. (Note: In the OpenConfig space, the gNOI interface is used for that purpose)
  • Support for the XML and LYB data encodings.

While the gRPC interface provides these benefits, the gNMI interface is an industry standard and may be the preferred choice for those working with a heterogeneous network where a single management interface for all devices is desired.

RPCs

The following RPCs are supported:

Capabilities

The Capabilities RPC is used to retrieve the device capabilities, including the Holo version, supported modules, and supported data encodings.

Ruby example:

require 'holo_services_pb'

# Connect to holod
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Invoke RPC
request = Holo::CapabilitiesRequest.new
response = stub.capabilities(request)

# Print the response
pp response.version
pp response.supported_modules
pp response.supported_encodings
$ ruby -I. ./caps.rb | head -n 10
"0.1.0"
[<Holo::ModuleData: name: "iana-if-type", organization: "IANA", revision: "2017-01-19">,
 <Holo::ModuleData: name: "ietf-interfaces", organization: "IETF NETMOD (Network Modeling) Working Group", revision: "2018-01-09">,
 <Holo::ModuleData: name: "ietf-routing-types", organization: "IETF RTGWG - Routing Area Working Group", revision: "2017-10-13">,
 <Holo::ModuleData: name: "ietf-bfd-types", organization: "IETF BFD Working Group", revision: "2022-09-22">,
 <Holo::ModuleData: name: "ietf-routing", organization: "IETF NETMOD (Network Modeling) Working Group", revision: "2018-03-13">,
 <Holo::ModuleData: name: "ietf-key-chain", organization: "IETF RTGWG - Routing Area Working Group", revision: "2017-06-15">,
 <Holo::ModuleData: name: "ietf-ip", organization: "IETF NETMOD (Network Modeling) Working Group", revision: "2018-01-09">,
 <Holo::ModuleData: name: "ietf-segment-routing", organization: "IETF SPRING - SPRING Working Group", revision: "2021-05-26">,
 <Holo::ModuleData: name: "ietf-segment-routing-common", organization: "IETF SPRING - SPRING Working Group", revision: "2021-05-26">,

Get

The Get RPC retrieves configuration data, state data, or both. Optionally, the request can be restricted to a single YANG path. If no data encoding is specified, the default encoding used is JSON.

Ruby example:

require 'holo_services_pb'

# Connect to holod
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Invoke RPC
request = Holo::GetRequest.new
request.type = :STATE
request.path = '/ietf-routing:routing/control-plane-protocols'
response = stub.get(request)

# Print the response
pp response
$ ruby -I. ./get.rb | head -n 20
<Holo::GetResponse: timestamp: 1680547280, data: <Holo::DataTree: encoding: :JSON, data: "{
  "ietf-routing:routing": {
    "control-plane-protocols": {
      "control-plane-protocol": [
        {
          "type": "ietf-bfd-types:bfdv1",
          "name": "main",
          "ietf-bfd:bfd": {
            "summary": {
              "number-of-sessions": 2,
              "number-of-sessions-up": 2,
              "number-of-sessions-down": 0,
              "number-of-sessions-admin-down": 0
            },
            "ietf-bfd-ip-mh:ip-mh": {
              "summary": {
                "number-of-sessions": 0,
                "number-of-sessions-up": 0,
                "number-of-sessions-down": 0,
                "number-of-sessions-admin-down": 0

Validate

The Validate RPC performs validation on configuration data without committing it, including both YANG and internal validation checks.

Ruby example:

require 'holo_services_pb'

# Connect to holod
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Invoke RPC
request = Holo::ValidateRequest.new
request.config = Holo::DataTree.new
request.config.encoding = :JSON
request.config.data = '
{
  "ietf-routing:routing": {
    "control-plane-protocols": {
      "control-plane-protocol": [
        {
          "type": "ietf-ospf:ospfv2",
          "name": "main",
          "ietf-ospf:ospf": {
            "explicit-router-id": "1.1.1.3"
          }
        }
      ]
    }
  }
}
'
response = stub.validate(request)

# Print the response
pp response

Commit

The Commit RPC creates a new configuration transaction using a two-phase commit protocol, with three available commit operations: merge, replace, and change (YANG Patch). The provided data tree can be specified using any of the supported data encodings.

For confirmed commits, the confirmed_timeout parameter must be specified with a non-zero value, representing the commit timeout in minutes. Within the given timeout, a new Commit RPC is expected to confirm the previous commit.

Additionally, the comment parameter can be used to describe the configuration changes being pushed to the device, making the rollback log more informative.

Ruby example:

require 'holo_services_pb'

# Connect to holod
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Invoke RPC
request = Holo::CommitRequest.new
request.operation = :MERGE
request.config = Holo::DataTree.new
request.config.encoding = :JSON
request.config.data = '
{
  "ietf-routing:routing": {
    "control-plane-protocols": {
      "control-plane-protocol": [
        {
          "type": "ietf-ospf:ospfv2",
          "name": "main",
          "ietf-ospf:ospf": {
            "explicit-router-id": "1.1.1.3"
          }
        }
      ]
    }
  }
}
'
request.confirmed_timeout = 1
response = stub.commit(request)

# Print the response
pp response

Execute

The Execute RPC enables the execution of a YANG RPC/Action. The Execute request carries the YANG RPC/Action input parameters, while the response contains the corresponding output parameters.

Ruby example:

require 'holo_services_pb'

# Connect to holod
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Invoke RPC
request = Holo::ExecuteRequest.new
request.data = Holo::DataTree.new
request.data.encoding = :JSON
request.data.data = '
{
  "ietf-ospf:clear-neighbor": {
    "routing-protocol-name":"main"
  }
}
'
response = stub.execute(request)

# Print the response
pp response

Please note that the Ruby examples presented use manually written JSON for the sake of simplicity. Ideally, the management script should use YANG language bindings to achieve type safety and other benefits.

ListTransactions

The ListTransactions RPC provides a list of all recorded transactions within the rollback log. This log is stored in non-volatile memory, ensuring the preservation of transaction records even in the event of power loss or system restarts.

Ruby example:

require 'holo_services_pb'

# Create the connection with holod:
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Create a new state request to get interface state:
request = Holo::ListTransactionsRequest.new

# Invoke RPC.
response = stub.list_transactions(request)

# Print the response.
response.each do |t|
  pp t
end

GetTransaction

The GetTransaction RPC allows querying data from the rollback log for a given configuration transaction ID.

Ruby example:

require 'holo_services_pb'
  
# Create the connection with holod:
stub = Holo::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)

# Create a new state request to get interface state:
request = Holo::GetTransactionRequest.new
request.transaction_id = 1
request.encoding = :XML

# Invoke RPC.
response = stub.get_transaction(request)

# Print the response.
pp response

Limitations

As of now, the gRPC module has the following limitations:

  • No support for streaming telemetry
  • No support for YANG notifications

Configuration

The gRPC module has the following configuration options:

  # gRPC northbound plugin configuration
  [plugins.grpc]
    # Enable or disable the plugin
    enabled = true
    # gRPC server listening address
    address = "[::1]:50051"
    # Optional gRPC TLS configuration
    [plugins.grpc.tls]
      # Enable or disable TLS authentication
      enabled = false
      # TLS certificate
      certificate = "/etc/ssl/private/holo.pem"
      # TLS key
      key = "/etc/ssl/certs/holo.key"