Adding Optional Extensions to gNMI
Contributors: Rob Shakir ([email protected]), Carl Lebsack ([email protected]), Nick Ethier ([email protected]), Anees Shaikh ([email protected])
Date: November 2017
Status: New Proposal
Summary
This contribution proposes to modify the gNMI protocol to allow extensions to be added without requiring the core specification to be modified. The intention of this is to allow implementors to add additional functionality to existing gNMI RPCs.
Problem Statement/Motivation
In particular use cases, there are requirements for data that is not currently specified within the existing RPC payloads to be carried. Some examples of this include:
- Implementations of gNMI which act as a proxy to set of downstream devices. In this case, there is a requirement to convey, along with each RPC, the target to which the request is being transmitted.
- Scenarios where the network element participates in arbitration between multiple writers. In this case, the payload of a
Set
RPC carries additional data that allows the target to determine whether the client is the most up-to-date writer, and hence determine whether to accept a Set
request.
- Implementations of gNMI wherein the target wishes to supply additional (non-fatal) errors or warnings to the client in
Get
or Subscribe
RPCs. For example, conveying that a warning condition occurred when retrieving the configuration (e.g., the device was not able to map a part of a native schema back to the requested schema).
The common requirement of these cases is that they require additional data to be supplied in addition to the existing payload without changing the RPC's semantics. If the semantics of an RPC are to be changed, defining an additional service (e.g., FooGNMIExtService
with a new MagicSubscription
RPC) provides a clean way to extend the service definition. However, for the cases above, where the semantics stay fundamentally the same, bifurcating RPC paths does not seem an optimal solution.
One proposed solution to this problem is to add additional fields in the gRPC metadata. There are a number of downsides to this approach:
- Logging, tracing or debugging frameworks must be extended to support logging gRPC metadata to allow the whole context of a request to be understood. Where logging frameworks simply take the serialised protobuf input as the logging payload, metadata is omitted.
- Semantically, since in some cases (e.g., that of the proxy) the information is really a first class requirement of the RPC payload, it seems fragile to rely on metadata for such information.
This proposal seeks to define a means by which existing gNMI RPC payloads can be extended using a non-metadata approach.
Proposal
We propose to introduce an additional repeated field to all top-level gNMI RPC messages (i.e., Capability(Request|Response)
, Get(Request|Response)
, Set(Request|Response)
and and Subscribe(Request|Response)
) named extension
. This field is defined to a carry an gnmiext.Extension
message.
We propose that the Extension
message is defined as follows:
message Extension {
oneof ext {
ProxyDetails proxy = 1;
...
RegisteredExtension ext = NN;
}
}
message RegisteredExtension {
enum ExtensionID {
UNSET = 0;
EXPERIMENTAL = 999;
}
ExtensionID id = 1;
bytes msg = 2;
}
This splits gNMI extensions into two sets:
- Well-known extensions: These are defined to the set of extensions that are expected to be required by multiple implemenations. For example, numerous use cases have been described for carrying information that is useful to a target which acts as a proxy for other gNMI targets. For such common use cases, we propose to define messages directly within the gNMI extensions module.
The following example for a ProxyDetails
extension is below.
// Credentials stores the authentication information for a proxy.
message Credentials {
string username = 1; // The login username.
string password = 2; // The authentication password.
// TODO: Extend to other auth, e.g., SSL certificates.
}
message ProxyDetails {
string address = 1; // Address of the proxy.
Credentials credentials = 2; // Authentication credentials.
proto.Any extra = 3; // Additional (arbitrary) details.
}
- Registered Extensions: In other cases, extensions may be more esoteric, or required only in a subset of cases. In this case, we propose to register such extensions (particularly, to ensure that extensions do not make undefined modifications to the base behaviour expected of an RPC), but leave their payload defined by
contrib
definitions. We propose that an extension ID is allocated from the ExtensionID
simply by requesting such an extension, and providing a link to a reference to the specification for the extension. The payload of the RegisteredExtension
msg
field is the marshalled contents of the message. The ExtensionID
acts in the same manner as the type
field of google.protobuf.Any
, albeit with more restrictions as to the allowed set of types.
If a registered extension becomes popular, it may be promoted to a well-known extension. Initially, we propose that RegisteredExtension
IDs are assigned simply through an email request. We do not propose to assign an extension ID to a well known extension. When extensions are promoted to well known, their extension ID will be deprecated over time.
Open Questions
- Currently, this proposal does not allow supported extensions to be discovered. The
Capability
RPC could be extended to add such discovery.