Guidelines for Telemetry Data Subscriptions over gNMI
This section describes the subscription modes supported by gNMI connections.
The gNMI protocol defines the Subscribe RPC for subscribing to telemetry
data. The telemetry collector uses this RPC to request updates from the network device for
state and configuration data.
Requests for new subscriptions are encapsulated within
a SubscribeRequest message containing one or more resource paths. The
subscribed paths relate to specific data instances on the target network device. The request
can contain paths based on the OpenConfig or native Junos® OS schemas.
The subscription request must also include one of the following modes:
-
ONCE- a one-time request for data. -
POLL- for periodic, on-demand retrieval of data. -
STREAM- a long-lived subscription that streams data according to specified triggers.
Subscriptions in STREAM mode must specify one of the following
sub-modes:
-
ON_CHANGE- data updates are only sent when the value of the data item changes. -
SAMPLE- data updates are sent once per sample interval based on an interval period specified in the subscription request. The default sample interval is 30 seconds. -
TARGET_DEFINED- the network device receiving the subscription request determines the best type of delivery for the data on a per-leaf basis. If the path specified within the message refers to event-driven data, then anON_CHANGEsubscription might be created. For data that represents counter values, aSAMPLEsubscription might be created.Note:The
TARGET_DEFINEDsubscription requests for configuration paths are treated asON_CHANGErequests only.
For ONCE, ON_CHANGE and SAMPLE
subscriptions, the collector can request an initial update containing the current state of the
paths in the subscription. An initial sync update is valuable because:
-
The collector has a complete view of the current state of every field on the device for that sensor path.
-
Event-driven data (
ON_CHANGE) is received by the collector at least once before the next occurs, ensuring that the collector remains aware of the data state beforehand. -
Packet Forwarding Engine sensors that contain zero counter values that normally do not show up in streamed data due to zero-suppression feature are also sent. This ensures that all fields from each line card are known to the collector.
The target device responds to the subscription request with a
SubscribeResponse message. If the subscription request calls for an initial
sync, the target sends the data followed by the response message with the
sync_response flag set to true. After the initial sync,
the target device proceeds with updates for the paths according to the subscription mode.
The SubscribeRequest message includes a flag called
updates_only. When this flag is set to true, the target
device does not send an initial sync, only subsequent updates as follows:
-
For
STREAMsubscriptions inSAMPLEmode, the update is sent at the next sample interval. -
For
STREAMsubscriptions inON_CHANGEmode, the update is sent upon the next value change. -
For
ONCEsubscriptions, only theSubscribeResponseis sent withsync_responseset tofalse, and the subscription closes. -
TARGET_DEFINEDsubscriptions are treated asON_CHANGEfor configuration paths and the update is sent upon the next value change.
The contents of the SubscribeRequest and SubscribeResponse
messages are defined in gnmi.proto file. For more information on the Subscribe RPC and
subscription modes, see the gNMI specification at: gNMI Specification: Subscribing to Telemetry
Updates.
Configuration paths have these limitations:
-
POLLsubscriptions are not supported. -
Prefix paths are not included in the update messages.
-
The gNMI response is not supported for Juniper-specific metadata operations, such as
active/inactive,insert before/after,comment/annotate, andprotect/unprotect. These might appear in the message but are not valid. -
Unsupported parameters in the
SubscribeRequestincludesuppress_redundant,heartbeat_level,allow_aggregation, andqos. -
PROTO encoding is the only supported encoding.
-
Extensions in
SubscribeRequestmessages are not supported -
Subscription path filtering is supported only at a key level.
The following commit variants are not supported for
ON_CHANGEandTARGET_DEFINEDsubscriptions:commit at,commit prepare/activate, and batch commits.Commits are not supported from the
edit dynamicandedit privateedit or configure modes.-
Update messages are not sent for presence containers.
-
Subscription lists that have only one configured leaf for the identifier or key might not generate an update message.
Enabling “ON CHANGE” Sensor Support Through gNMI
Periodical streaming of OpenConfig operational states and counters is available since Junos OS Release 16.1, exporting telemetry data from Juniper equipment to an external collector. Although it is useful in collecting all the needed information and creating a baseline “snapshot,” periodical streaming is less useful for time-critical missions. Configure ON_CHANGE streaming for an external collector to receive information only when operational states change.
To support ON_CHANGE streaming, a new specification called gRPC Network Management Interface (gNMI) is implemented for the modification and retrieval of configurations from a network element. Additionally, the gNMI specification can be used to generate and control telemetry streams from a network element to a data collection system. The new gNMI specification allows one gRPC service definition to provide a single implementation on a network element for configuration and telemetry. It also allows a Network Management System (NMS) to interact with the device through unified telemetry and configuration RPCs.
The Junos file package (junos-telemetry-interface) includes the gnmi.proto file and GnmiJuniperTelemetryHeader.proto Juniper extension for gNMI support.
Information about the RPCs supporting this feature is in the gNMI Proto file version 0.4.0 (the supported version) and the specification released
The telemetry RPC subscribe under gNMI service supports ON_CHANGE
streaming. RPC subscribe allows clients to request the target to send
values for particular paths within the data tree. Values may be streamed (STREAM), sent
one-off on a long-lived channel (POLL), or sent one-off as a retrieval (ONCE).
If you subscribe to a top-level container with a sample frequency of 0, leaves with ON_CHANGE support are streamed based on events. Other leaves are not streamed.
To let a device determine which nodes are streamed as ON_CHANGE or which are SAMPLE, the collector must subscribe for TARGET_DEFINED with sample_interval.
Enabling “TARGET_DEFINED” Subscription Mode Through gNMI
Junos OS Release 20.2R1 adds support for TARGET_DEFINED subscription mode with gRPC Network Management Interface (gNMI) services on MX5, MX10, MX40, MX80, MX104, MX150, MX204, MX240, MX480, MX960, MX2008, MX2010, MX2020, MX10003, MX10008, and MX10016 routers.
An external collector that uses a gNMI subscription determines how sensor data is delivered:
-
STREAMING mode periodically streams sensor data from the DUT at a specified interval.
-
ON_CHANGE mode sends updates for sensor data from the DUT only when data values change.
-
Newly supported TARGET_DEFINED mode (submode 0) instructs the DUT to select the relevant mode (STREAMING or ON_CHANGE) to deliver each element (leaf) of sensor data to the external collector. When the external collector sends a subscription for a sensor with submode 0 to the DUT, the DUT responds, activating the sensor subscription so that periodic streaming does not include any of the ON_CHANGE updates. The DUT notifies the collector whenever qualifying ON_CHANGE events occur.
Subscriptions default to a periodic streaming frequency of 30 seconds unless the collector specifies otherwise in the subscription request.
The JavaScript Object Notation (JSON) file below shows a sample gNMI subscription.
TARGET_DEFINED mode is set using submode=0 for the resource (sensor) path
/interfaces/interface[name='lo0']/state.
$ cat gnmi.json
{
"dut_list":[
{
"port":32767,
"rpc":["sub_request"],
"sub_request":{
"subscription":[
{
"path":"/interfaces/interface[name='lo0']/state",
"submode":0,
"sample_interval":30
}
],
"mode":0,
"encoding":2
}
}
]
$ python ./gnmi_subscribe_client_sample.py -c ./gnmi.json -d 10.53.32.102 -l client.log
The Junos file package (junos-telemetry-interface) includes the gnmi.proto file and GnmiJuniperTelemetryHeader.proto Juniper extension for gNMI support.
For more information, see the gNMI specifications and gNMI protocol file here:
Enabling “INITIAL_SYNC” Subscription Mode Through gNMI
Starting in Junos OS Release 20.2R1, support for INITIAL_SYNC statistics from Packet Forwarding Engine sensors using gNMI services is available. This feature applies to the MX960, MX2008, MX2010, MX2020, PTX1000, and the PTX5000 Router. The Juniper Networks® PTX10000 line of Routers, Juniper Networks® QFX5100 Switch, and Juniper Networks® QFX5200 Switch also provide this support.
Starting in Junos OS Evolved Release 20.4R1, support for INITIAL_SYNC statistics from Packet Forwarding Engine sensors using gNMI services is available. Juniper Networks® QFX5130-32CD Switch includes this support.
When an external collector sends a subscription request for a sensor with INITIAL_SYNC (gnmi-submode 2), the host sends all supported target leaves (fields) under that resource path at least once to the collector with the current value. Collecting these statistics is beneficial because:
-
The collector has a complete view of the current state of every field on the device for that sensor path.
-
Event-driven data (ON_CHANGE) arrives at the collector at least once before the next event occurs. This approach ensures collector awareness of the data state before the next event occurs.
-
Packet Forwarding Engine sensors with zero counter values (zero-suppressed) that normally do not appear in the streamed data are sent atleast once. This approach ensures the collector has visibility into all fields from each line card, often called a source.
INITIAL_SYNC submode requires the device to send at least one copy to the collector, though sending more than one is acceptable.
Subscriptions will default to a periodic streaming frequency of 30 seconds unless otherwise specified by the collector in the subscription request.
The JavaScript Object Notation (JSON) file below shows a sample gNMI subscription.
INITIAL_SYNC mode is set using gnmi_submode 2 for the resource (sensor)
path /interfaces/. The gnmi_mode is set to
0. The protocol encoding is set to 2 for GBP.
{
"influx": {
"server": "server1",
"port": 8086,
"dbname": "gD40",
"measurement": "OC",
"user": "influx",
"password": "influxdb",
"recreate": true
},
"gnmi": {
"mode": 0, <---- STREAM
"encoding": 2, <--- PROTO encoding
"prefix": "/x/y/z"
},
"host": "10.10.130.73",
"port": 10162,
"user": "user1",
"password": "password1",
"cid": "cid-1jk",
"paths":[
{
"path": "/interfaces/",
"Freq": 10000000000,
"gnmi_submode": 2 <---- SAMPLE
}
]
}
The Junos file package (junos-telemetry-interface) includes the gnmi.proto file and GnmiJuniperTelemetryHeader.proto Juniper extension for gNMI support.
For more information, see the gNMI specifications and gNMI protocol file here:
gNMI telemetry specification gNMI protocol definition
Examples
The following examples show subscription requests and responses made by a gNMI client and target device in protobuf format.
Example: ONCE mode
The following example shows a subscription request sent from a gNMI client in protobuf
format. The subscription mode is ONCE and the OpenConfig resource path is
/system/aaa/authentication/users:
root@controller:~# /usr/local/bin/gnmic sub -a 10.225.0.0:32767 --mode once --path /system/aaa/authentication/users -u <username> -p <password> --format prototext
The target responds with a one-time update:
update: {
timestamp: 1676294840
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test2"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}Example: ON_CHANGE
The following example shows a subscription request in STREAM mode with
ON_CHANGE sub-mode. The OpenConfig resource path is
/system/aaa/authentication/users/user[username="test1"]:
root@controller:~# /usr/local/bin/gnmic sub -a 10.225.0.0:32767 --mode stream --stream-mode on-change --path /system/aaa/authentication/users -u <username> -p <password> --format prototext
The OpenConfig configuration at the time of the subscription request:
user@root> show configuration openconfig-system:system aaa authentication | display set set openconfig-system:system aaa authentication users user test1 config password $ABC123 set openconfig-system:system aaa authentication users user test1 config role superuser
The example response message shows the values for the configuration paths and the
sync_response flag set to true:
update: {
timestamp: 1676311979
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
sync_response: true The following configuration changes are made to the subscribed paths:
-
Add username for
test1. -
Delete password for
test1.
The target device sends the following update in response:
update: {
timestamp: 1676312428
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
delete: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
}Example: SAMPLE
The following example shows a subscription request in STREAM mode and
SAMPLE sub-mode. The OpenConfig resource path is
/system/aaa/authentication/users/user[username="test1"]:
root@controller:~# /usr/local/bin/gnmic sub -a 10.225.0.0:32767 --mode stream --stream-mode sample --sample-interval 5s --path /system/aaa/authentication/users -u <username> -p <password> --format prototext
The OpenConfig configuration at the time of the subscription request:
user@root> show configuration openconfig-system:system aaa authentication | display set set openconfig-system:system aaa authentication users user test1 config username test1 set openconfig-system:system aaa authentication users user test1 config password "$ABC123" set openconfig-system:system aaa authentication users user test1 config role superuser
The example response messages show an initial update sent with the
sync_response flag set to true and subsequent updates
sent at 5 second intervals:
update: {
timestamp: 1676295454
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
sync_response: true
update: {
timestamp: 1676295459
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
update: {
timestamp: 1676295464
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}