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:

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:

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:

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:

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:

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:

  1. Setup your Collection Agent plugin.
  2. Configure your mappings.
  3. 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:

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.

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:

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:

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:

Dataview of simple telemetry data with one key

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:

Dataview of simple telemetry data with multiple keys

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:

Dataview of nested telemetry data

Monitoring and troubleshooting Copied

Device cannot connect Copied

If no telemetry is arriving from the network device, work through the following checks:

  1. Check if the firewall rules allow incoming connections on the configured port.
  2. Verify that the collector is actively listening. For example, run netstat -an | grep 57500.
  3. Check the device configuration has the correct collector IP and port.
["Geneos"] ["User Guide"]

Was this topic helpful?