Prior to Junos version 19.3, crucial system information and debug information is included in GNMI protocol as "any_val" . This does not conform to the GNMI protocol specification. Since Junos version 19.3, we introduce our own "GNMI extension" for these values. This KB shows the fields available in Juniper's "GNMI extensions".
GNMI proto definition does not contain fields for specifying crucial system information and debug information. Prior to 19.3, this information was part of the payload and was stuffed as “ any_val ” . However, this did not conform with the GNMI protocol mandate of supplying of this information as part of GNMI extensions. Hence Juniper has introduced its own Extension for exporting the values. Below sections will discuss on various fields of the extension proto, release information and a sample illustration.
Prior to 19.3 release, the data was packed with the below header:
https://github.com/Juniper/telemetry/blob/master/20.3/20.3R1/protos/GnmiJuniperTelemetryHeader.proto
syntax = "proto3"; // Present as first gNMI update in all packets message GnmiJuniperTelemetryHeader { // router name:export IP address string system_id = 1; // line card / RE (slot number) uint32 component_id = 2; // PFE (if applicable) uint32 sub_component_id = 3; // Path contains useful information on identifying which sensor, // resoruce string and producer the data corresponds to. // "internal_sensor_name:internal_path:external_path:component" // e.g.: // "sensor_1006:/junos/system/linecard/cpu/memory/:/junos/system/linecard/cpu/memory/:PFE" string path = 4; // Sequence number, monotonically increasing for each // system_id, component_id, sub_component_id + path. uint64 sequence_number = 5; }
Post 19.3 release, data is packed with the below header: Please note the change in the names of the message in the below and above headers. https://raw.githubusercontent.com/Juniper/telemetry/master/20.3/20.3R1/protos/GnmiJuniperTelemetryHeaderExtension.proto
syntax = "proto3"; // Present as first gNMI update in all packets message GnmiJuniperTelemetryHeaderExtension { // router name:export IP address string system_id = 1; // line card / RE (slot number) uint32 component_id = 2; // PFE (if applicable) uint32 sub_component_id = 3; // Internal sensor name string sensor_name = 4; // Sensor path in the subscribe request string subscribed_path = 5; // Internal sensor path in junos string streamed_path = 6; string component = 7; // Sequence number, monotonically increasing for each uint64 sequence_number = 8; // Payload get timestamp in milliseconds int64 payload_get_timestamp = 9; // Stream creation timestamp in milliseconds int64 stream_creation_timestamp = 10; // Event timestamp in milliseconds int64 event_timestamp = 11; // Export timestamp in milliseconds int64 export_timestamp = 12; // Subsequence number uint64 sub_sequence_number = 13; // End of marker. Not supported bool eom = 14; }
The field “eom” is not supported yet (20.4). Since both message names are different, hence a single collector can be used to parse the values from pre and post 19.3 releases. Also, the use of extensions require registration of Extension ID in the gnmi_ext.proto. Juniper has already created the following pull request to allocate and extension id for the telemetry header:
https://github.com/openconfig/gnmi/pull/76
Until the changes are merged, customers are requested to use the gnmi_ext.proto from Juniper Github page:
https://github.com/Juniper/telemetry/blob/master/20.3/20.3R1/protos/gnmi_ext.proto
Sample Code to parse any value: For releases prior to 19.3 you can use the following steps (sample illustration is in python):
for result in response.update.update: #Unpacking GnmiJuniperTelemetryHeader Data if "__juniper_telemetry_header__" in str(result.path): x = GnmiJuniperTelemetryHeader_pb2.GnmiJuniperTelemetryHeader() result.val.any_val.Unpack(x) print str(x)
system_id: "foo.juniper.net" component_id: 65535 sensor_name: "sensor_1004:/components/:/components/:chassisd"
update { path { elem { name: __juniper_telemetry_header__ } } val { any_val { type_url: GnmiJuniperTelemetryHeader value: 65535;2097152;sensor_1000:/junos/task-memory-information/ task-memory-overall-report/:/junos/task-memory-information/task-memory-overall-report/ :xmlproxyd;0;foo } } }
For this illustration the snippet is written in python.
for response in responses: # check if the response contains an extension field if (response.extension): # extract the extension ID id = response.extension[0].registered_ext.id # check if the extension matches Juniper registered extension if (id == gnmi_ext_pb2.EID_JUNIPER_TELEMETRY_HEADER): # parse the extension fields. x = GnmiJuniperTelemetryHeaderExtension_pb2.\ GnmiJuniperTelemetryHeaderExtension() x.ParseFromString(response.extension[0].registered_ext.msg) print x
system_id: "foo.juniper.net" component_id: 65535 sensor_name: "sensor_1004" subscribed_path: "/junos/task-memory-information/" streamed_path: "/junos/task-memory-information/" component: "xmlproxyd" sequence_number: 246 payload_get_timestamp: 1602181495043 stream_creation_timestamp: 1602181494541 export_timestamp: 1602181495063 Raw GNMI response: update { path { elem { name: "junos" } elem { name: "task-memory-information" } elem { name: "task-memory-total-bytes-percent" } } val { uint_val: 0 } } } extension { registered_ext { id: EID_JUNIPER_TELEMETRY_HEADER msg: "\n\005fishy\020\377\377\003\"\013sensor_1004*\037/junos/task-memory-information/2\037/ junos/task-memory-information/:\txmlproxyd@\200\002H\361\362\325\313\320 .P\215\356\325\313\320.`\365\362\325\313\320." } }
2020-02-03 First Publication