Model-Driven Telemetry (MDT)
Overview Copied
The Model-Driven Telemetry (MDT) Collection Agent plugin receives streaming telemetry from network devices over gRPC dial-out connections. It uses a push model, where devices send data to the collector at configured intervals. This differs from SNMP polling, where a collector repeatedly polls devices.
The MDT Collection Agent plugin:
- Accepts gRPC dial-out connections from Cisco devices (primarily IOS-XR, IOS-XE, and NX-OS).
- Supports self-describing GPB (KV-GPB) telemetry encoding.
- Converts Cisco Protocol Buffer telemetry into Collection Agent datapoints.
- Supports optional TLS, including mutual TLS (mTLS) when configured.
- Handles concurrent connections from multiple devices.
The MDT data format uses Yet Another Next Generation (YANG) data model. Refer to Telemetry data format for more information.
Prerequisites Copied
Geneos environment Copied
The latest version of the MDT plugin requires:
-
Gateway and Netprobe 7.9.x or higher.
-
Collection Agent 6.5.x or higher.
Note
Starting from Collection Agent 5.x, Java 21 is the minimum required version.
The MDT plugin binaries are packaged with Netprobe, and are stored in the collection_agent > plugins folder. Alternatively, you can download separate binaries for the MDT plugin from ITRS Downloads.
Network device configuration Copied
To send telemetry data to the plugin, the Cisco network devices need to be configured with the appropriate telemetry destination and subscription settings. Cisco configuration commands vary by OS, but the key configurations are:
- Use gRPC protocol with the correct collector IP and port, matching the IP of the machine running the MDT Plugin, and the port the MDT plugin is configured to listen on.
- Use self-describing GPB (KV-GPB) encoding format.
- Configure the YANG path for the telemetry data to be sent. This should match the
mapping.pathin the plugin configuration if specified. - Set an appropriate sample interval for the telemetry data to avoid overwhelming the collector.
Telemetry data format Copied
The plugin expects Cisco telemetry data as Google Protocol Buffer messages that follow the MDT dial-out schema.
The Cisco telemetry data structure understood by the plugin uses self-describing GPB format (KV-GPB). This is an example of a basic telemetry payload:
node_id_str: "router1"
subscription_id_str: "100"
encoding_path: "Cisco-IOS-XE-interfaces-oper:interfaces/interface/statistics"
collection_id: 1
collection_start_time: 1762148227871
msg_timestamp: 1762148227953
data_gpbkv {
timestamp: 1762148227953
fields {
name: "keys"
fields {
name: "name"
string_value: "Vlan1"
}
}
fields {
name: "content"
fields {
name: "discontinuity-time"
string_value: "2025-08-27T14:13:49+00:00"
}
fields {
name: "in-octets"
uint64_value: 519
}
}
}
In the example, each telemetry message includes:
- Node ID — the device that sent the message.
- Subscription ID — the subscription ID configured on the device.
- Encoding Path — the YANG path related to this data.
- Timestamps
- The actual data (
data_gpbkv):- The telemetry data is divided into two sections:
keysandcontent. - In general,
keysfields contain identifiers for the resource described by the values incontent.
- The telemetry data is divided into two sections:
The actual data fields and structure can vary widely depending on the YANG model used by the device and the specific telemetry configuration. Any data from a YANG data model that follows the structure above can be processed by the plugin.
The plugin processes the telemetry data and converts it into Collection Agent datapoints:
keysto dimensionscontentto metric values or attributes
Configure Gateway to deploy the MDT plugin Copied
The MDT plugin supports Collection Agent publication into Geneos using dynamic managed entities. To set up the MDT plugin in Geneos, follow these steps:
- Setup your Collection Agent plugin.
- Configure your mappings.
- Configure your other Dynamic Entities in the Gateway, see Create Dynamic Entities in Collection Agent setup for a more detailed procedure.
Setup your Collection Agent plugin Copied
Use one of the following options listed below to configure the plugin:
- Setting up your collector in the Gateway Setup Editor by adding the following configuration in Dynamic Entities > Collectors. For more information, see Collectors in Dynamic Entities.
- Adding the following configuration in
collection-agent.ymlfile on your local machine:
collectors:
- type: plugin
className: MDTCollector
# Port for gRPC server (default: 57500)
port: 57500
# Optional. Enables TLS when present.
tls:
# Required when tls is specified.
certFile: /path/to/cert.pem
# Required when tls is specified.
keyFile: /path/to/key.pem
# Optional. Use for mTLS client authentication.
trustChainFile: /path/to/trust-chain.pem
# Optional. Defaults to TLSv1.3 and TLSv1.2.
protocols: [ TLSv1.3, TLSv1.2 ]
# Optional mapping rules.
# If omitted, keys -> dimensions and content -> datapoints.
mapping:
- path: "Cisco-IOS-XE-process-cpu-oper:cpu-usage/cpu-utilization"
dimensionMapping:
keyFields:
- name
- id
contentFieldPaths:
- cpu-usage-processes/cpu-usage-process/pid
datapointMapping:
- field: "five-seconds"
type: Gauge
- field: "five-seconds-intr"
type: Gauge
- field: "one-minute"
type: Gauge
- field: "five-minutes"
type: Gauge
- field: "cpu-usage-processes/cpu-usage-process/name"
type: EntityAttribute
Configure your mappings Copied
To be able to show metrics and events in Geneos, dynamic mappings must be configured and attached to the Netprobe receiving the data from the Collection Agent. Use one of the following options listed below to configure your dynamic mappings.
- Adding
templates/mdt_mapping.xmlas an include file in your Gateway. - Choosing a built-in mapping in > Mapping. For more information, see Mapping and mapping group in Dynamic Entities.
- Setting up a custom mapping in Dynamic Entities Health > Mapping. For more information, see Mapping and mapping group in Dynamic Entities.
Datapoint structure Copied
Telemetry data is converted to Collection Agent datapoints with the following structure:
Entity dimensions Copied
| Dimension | Description | Example |
|---|---|---|
node_id |
Device identifier (node-id). | router1 |
encoding_path |
YANG path received in the header of the telemetry data. | interfaces/interface/statistics |
keys fields in the telemetry data are also converted to dimensions.
You can also set the mapping.dimensionMapping config to identify keys and content paths to use as dimensions.
Metric names Copied
Metric names are the field name, with path (if not root), after the encoding_path. In the example path, the metric name is in-octets.
Value types Copied
You can specify the type of datapoint to be used for each data in the mapping.datapointMapping config.
If this is not specified, the plugin defaults to the following conversion:
- Numeric values (uint32, uint64, sint32, sint64, double, float) to
Gauge. - Boolean values (converted to 1.0/0.0) to
StatusMetric. - String values (stored as attributes) to
StatusMetricif the name ends with “status” or “state”, otherwise,EntityAttribute.
Telemetry data examples Copied
Simple telemetry data with one key only Copied
node_id_str: "router1"
subscription_id_str: "100"
encoding_path: "Cisco-IOS-XE-interfaces-oper:interfaces/interface/statistics"
collection_id: 1
collection_start_time: 1762148227871
msg_timestamp: 1762148227953
data_gpbkv {
timestamp: 1762148227953
fields {
name: "keys"
fields {
name: "name"
string_value: "Vlan1"
}
}
fields {
name: "content"
fields {
name: "discontinuity-time"
string_value: "2025-08-27T14:13:49+00:00"
}
fields {
name: "in-octets"
uint64_value: 519
}
fields {
name: "in-unicast-pkts"
uint64_value: 7
}
fields {
name: "in-broadcast-pkts"
uint64_value: 0
}
fields {
name: "in-multicast-pkts"
uint64_value: 0
}
fields {
name: "in-discards"
uint32_value: 0
}
fields {
name: "in-errors"
uint32_value: 0
}
fields {
name: "in-unknown-protos"
uint32_value: 0
}
fields {
name: "out-octets"
uint32_value: 0
}
fields {
name: "out-unicast-pkts"
uint64_value: 0
}
fields {
name: "out-broadcast-pkts"
uint64_value: 0
}
fields {
name: "out-multicast-pkts"
uint64_value: 0
}
fields {
name: "out-discards"
uint64_value: 0
}
fields {
name: "out-errors"
uint64_value: 0
}
fields {
name: "rx-pps"
uint64_value: 0
}
fields {
name: "rx-kbps"
uint64_value: 0
}
fields {
name: "tx-pps"
uint64_value: 0
}
fields {
name: "tx-kbps"
uint64_value: 0
}
fields {
name: "num-flaps"
uint64_value: 0
}
fields {
name: "in-crc-errors"
uint64_value: 0
}
fields {
name: "in-discards-64"
uint64_value: 0
}
fields {
name: "in-errors-64"
uint64_value: 0
}
fields {
name: "in-unknown-protos-64"
uint64_value: 0
}
fields {
name: "out-octets-64"
uint64_value: 0
}
}
By default, the plugin converts fields in keys into datapoint dimensions and fields in content into datapoints.
In this example, with no mapping configuration defined, the plugin creates an EntityAttribute datapoint for discontinuity-time because the value is a string:
- name:
discontinuity-time - value: “2025-08-27T14:13:49+00:00”
- dimensions: {node_id=“router1”, encoding_path=“interfaces/interface/statistics”, name=“Vlan1”}
- properties (
entityAttributeInfo): {yang_model=“Cisco-IOS-XE-interfaces-oper”}
Since there is only one key in the keys field, this is automatically normalized.
This is an example of a simple telemetry data with only one key displayed in a dataview in Geneos:
Simple telemetry data with multiple keys Copied
node_id_str: "router1"
subscription_id_str: "103"
encoding_path: "Cisco-IOS-XE-environment-oper:environment-sensors/environment-sensor"
collection_id: 1
collection_start_time: 1773281606571
msg_timestamp: 1773281606572
data_gpbkv {
timestamp: 1773281606572
fields {
name: "keys"
fields {
name: "name"
string_value: "HotSpot Temp Sensor"
}
fields {
name: "location"
string_value: "Switch 1"
}
}
fields {
name: "content"
fields {
name: "state"
string_value: "Norm"
}
fields {
name: "current-reading"
uint32_value: 54
}
fields {
name: "sensor-units"
string_value: "celsius"
}
fields {
name: "low-critical-threshold"
sint32_value: 0
}
fields {
name: "low-normal-threshold"
sint32_value: 0
}
fields {
name: "high-normal-threshold"
sint32_value: 125
}
fields {
name: "high-critical-threshold"
sint32_value: 0
}
fields {
name: "sensor-name"
string_value: "temperature"
}
}
To convert all the keys into dimensions, define mapping.dimensionMapping.keyFields with the fields in the keys section to be converted in the order you want them applied.
If mapping.dimensionMapping.keyFields is not set, the plugin still converts all fields in keys into dimensions, but it will not be normalized.
This is an example of a simple telemetry data with multiple keys displayed in a dataview in Geneos:
Nested telemetry data Copied
Telemetry data can contain nested structures. The keys field only appears at the root of the path of the telemetry data. There are instances wherein keys (as defined in the YANG model) are not in the root path.
Nested keys do not appear in the keys fields. Instead, they appear as normal fields inside content.
For example, see the cpu-usage-processes/cpu-usage-process fields below, where the key is pid. Refer to this YANG catalog for a sample YANG model of the telemetry data below:
node_id_str: "router1"
subscription_id_str: "101"
encoding_path: "Cisco-IOS-XE-process-cpu-oper:cpu-usage/cpu-utilization"
collection_id: 1
collection_start_time: 1762148228082
msg_timestamp: 1762148228082
data_gpbkv {
timestamp: 1762148228082
fields {
name: "keys"
}
fields {
name: "content"
fields {
name: "five-seconds"
uint32_value: 0
}
fields {
name: "five-seconds-intr"
uint32_value: 0
}
fields {
name: "one-minute"
uint32_value: 0
}
fields {
name: "five-minutes"
uint32_value: 0
}
fields {
name: "cpu-usage-processes"
fields {
name: "cpu-usage-process"
fields {
name: "pid"
uint32_value: 1
}
fields {
name: "name"
string_value: "Chunk Manager"
}
fields {
name: "tty"
uint32_value: 0
}
fields {
name: "total-run-time"
uint64_value: 1
}
fields {
name: "invocation-count"
uint32_value: 14
}
fields {
name: "avg-run-time"
uint64_value: 71
}
fields {
name: "five-seconds"
double_value: 0.0
}
fields {
name: "one-minute"
double_value: 0.0
}
fields {
name: "five-minutes"
double_value: 0.0
}
}
fields {
name: "cpu-usage-process"
fields {
name: "pid"
uint32_value: 2
}
fields {
name: "name"
string_value: "Load Meter"
}
fields {
name: "tty"
uint32_value: 0
}
fields {
name: "total-run-time"
uint64_value: 322886
}
fields {
name: "invocation-count"
uint32_value: 1168834
}
fields {
name: "avg-run-time"
uint64_value: 276
}
fields {
name: "five-seconds"
double_value: 0.0
}
fields {
name: "one-minute"
double_value: 0.0
}
fields {
name: "five-minutes"
double_value: 0.0
}
}
}
}
To handle this, the mapping config in the plugin should be specified to instruct the plugin which content data should be converted into keys.
This is a sample configuration for the telemetry data below:
mapping:
- path: "Cisco-IOS-XE-process-cpu-oper:cpu-usage/cpu-utilization"
dimensionMapping:
contentFieldPaths:
- cpu-usage-processes/cpu-usage-process/pid
- cpu-usage-processes/cpu-usage-process/name
This is an example of a nested telemetry data displayed in a dataview in Geneos:
Monitoring and troubleshooting Copied
Device cannot connect Copied
If no telemetry is arriving from the network device, work through the following checks:
- Check if the firewall rules allow incoming connections on the configured port.
- Verify that the collector is actively listening. For example, run
netstat -an | grep 57500. - Check the device configuration has the correct collector IP and port.