Cisco MDT
Synopsis
The Cisco MDT device (type: cisco_mdt) takes the model-driven telemetry that Cisco IOS XR, IOS XE and NX-OS routers stream when they dial out: the router connects to Director and sends a telemetry message every time a subscription's interval comes, or when something changes for an event-driven one. Every row of a message is written as a record. Interface counters, CPU, memory, BGP, QoS, optics and the rest of a platform's operational state arrive this way. It is Telegraf's cisco_telemetry_mdt input.
The router pushes, and nothing is polled. Director needs no credentials of the router. For the other direction, where Director subscribes to a router's gNMI server, use the gNMI device.
The device reads three transports:
transport | Platforms | Encryption |
|---|---|---|
grpc (default) | IOS XR 6.1 and later (64-bit), IOS XE 16.10 and later, NX-OS 7.x and later | TLS, with the routers' own certificates when the device asks for them |
tcp | IOS XR 6.1 and later (32- and 64-bit) | None |
udp | IOS XR (protocol udp), NX-OS (protocol UDP) | None |
The encodings the device reads are self-describing GPB (GPB-KV) and IOS XR's JSON (encoding json). The compact GPB encoding needs the model's own .proto file to decode, and a row sent in it is left out with a warning — see Records; so are NX-OS's JSON and XML over UDP.
The Cisco MDT device needs Director 2.3.1 or later. With no Director or cluster at that version selected, the wizard shows Cisco MDT devices are unavailable on directors or clusters below version 2.3.1 and the device cannot be created.
Schema
- id: <numeric>
name: <string>
description: <string>
type: cisco_mdt
tags: <string[]>
pipelines: <pipeline[]>
status: <boolean>
properties:
address: <string>
port: <numeric>
transport: <string>
tls:
status: <boolean>
cert_name: <string>
key_name: <string>
passphrase: <string>
client_ca_name: <string>
client_auth_required: <boolean>
min_tls_version: <string>
max_tls_version: <string>
max_message_size: <numeric>
aliases: <object>
reuse: <boolean>
Configuration
The following fields are used to define the device:
Device
| Field | Required | Default | Description |
|---|---|---|---|
id | Y | - | Unique numeric identifier |
name | Y | - | Device name |
description | N | - | Optional description |
type | Y | - | Must be cisco_mdt |
tags | N | - | Optional tags |
pipelines | N | - | Optional pre-processor pipelines |
status | N | true | Enable/disable the device |
Listener
| Field | Required | Default | Description |
|---|---|---|---|
address | N | 0.0.0.0 | The address to listen on |
port | N | 57000 | The port the routers' destination group names, from 1 to 65535: a TCP port, or a UDP port for udp. The device binds it, so no other device on the Director can take it |
transport | N | grpc | How the routers dial out: grpc, tcp, or udp. See How a Router Dials Out |
max_message_size | N | 4194304 | The largest telemetry message taken, in bytes, from 65536 (64 KiB) to 67108864 (64 MiB). The default is 4 MiB. A message NX-OS sends in parts is measured whole. It bounds nothing over udp |
aliases | N | - | An object of table names and the encoding paths they stand for. See Tables |
TLS
TLS goes with the gRPC transport alone. TCP and UDP dial-out are not encrypted, and a device with transport: tcp or udp and tls.status: true is refused.
| Field | Required | Default | Description |
|---|---|---|---|
tls.status | N | false | Take the routers' gRPC dial-out over TLS. Requires tls.cert_name and tls.key_name |
tls.cert_name | Y* | - | The certificate the listener presents. A router's destination names its host (tls-hostname on IOS XR) and trusts its CA |
tls.key_name | Y* | - | The certificate's private key |
tls.passphrase | N | - | Passphrase for an encrypted private key |
tls.client_ca_name | N | - | The CA that signed the routers' own certificates |
tls.client_auth_required | N** | false | Require every router to present a certificate of its own, signed by tls.client_ca_name |
tls.min_tls_version | N | - | Minimum accepted TLS version (tls1.0, tls1.1, tls1.2, tls1.3) |
tls.max_tls_version | N | - | Maximum accepted TLS version |
* = Required when tls.status is true.
** = Requires tls.client_ca_name.
TLS material fields (cert_name, key_name, ca_name, client_ca_name) accept any of the following:
- File name — resolved relative to the service root directory. Nested paths such as
certs/prod/server.pemare supported. - Absolute path — honored only if it resolves inside the service root. Any path that escapes the root is refused.
- Inline PEM content — used verbatim when the value contains
-----BEGIN. - Environment variable —
${ENV_VAR}. - Vault reference —
$secret{id=...}or$secret{store=...,ref=...}.
Advanced Configuration
| Field | Required | Default | Description |
|---|---|---|---|
reuse | N | true | Share the port with a listener that is still closing when the device starts again, so a restart is not refused |
A configuration that cannot run stops the device with Configuration error and says why: a transport that is none of grpc, tcp and udp, TLS with the TCP or UDP transport or without its certificate or key, a message size out of its bounds, an address that is not valid, or an alias that names no valid table or no encoding path.
How a Router Dials Out
A router is configured with three things:
- a destination group: this Director's address and port, the transport, and
encoding self-describing-gpb; - a sensor group: the paths;
- a subscription that ties them together with an interval.
A minimal IOS XR one, over gRPC with TLS:
telemetry model-driven
destination-group VM
address-family ipv4 192.0.2.10 port 57000
encoding self-describing-gpb
protocol grpc tls-hostname mdt.example.com
sensor-group interfaces
sensor-path Cisco-IOS-XR-infra-statsd-oper:infra-statistics/interfaces/interface/latest/generic-counters
subscription interfaces
sensor-group-id interfaces sample-interval 30000
destination-id VM
protocol grpc no-tls dials out without TLS, protocol tcp uses the TCP transport, and protocol udp the UDP one (its packetsize, 1,472 bytes by default, bounds a datagram). encoding json sends IOS XR's JSON.
IOS XE and NX-OS take the same three things in their own syntax. A minimal IOS XE subscription, which dials out over gRPC without TLS (grpc-tcp), so the device it sends to has tls.status off. protocol grpc-tls profile <name> dials out over TLS instead:
telemetry ietf subscription 101
encoding encode-kvgpb
filter xpath /process-cpu-ios-xe-oper:cpu-usage/cpu-utilization
source-address 192.0.2.21
stream yang-push
update-policy periodic 3000
receiver ip address 192.0.2.10 57000 protocol grpc-tcp
A minimal NX-OS one:
feature telemetry
telemetry
destination-group 1
ip address 192.0.2.10 port 57000 protocol gRPC encoding GPB
sensor-group 1
path sys/intf depth unbounded
subscription 1
dst-grp 1
snsr-grp 1 sample-interval 30000
On IOS XE, encode-kvgpb is the self-describing encoding. On NX-OS, encoding GPB is self-describing; GPB-compact is not read. Over UDP, configure NX-OS with encoding GPB.
gRPC
The router calls MdtDialout of Cisco's gRPCMdtDialout service and keeps the stream open: every message on it is a telemetry message. The listener answers nothing, which is what a router expects.
- NX-OS sends a large message in parts. The parts are joined, and a message larger than
max_message_sizeis left out with a warning. - A message larger than the device takes, sent whole, closes the stream with
RESOURCE_EXHAUSTED, and the router dials out again. - A router that ends its stream with an error text, such as a subscription removed, has it logged.
- Keepalives need no setting. The listener takes a ping as often as every five seconds, with or without a call in flight. gRPC's own rule would cut off a client that pings more often than every five minutes, which IOS XE does.
- A message compressed with gzip, zstd, snappy or lz4 is decompressed.
TCP
Every message comes behind a twelve-byte header that says what the frame holds, how the message is encoded, and its length.
- A heartbeat is read and skipped.
- A message the header says is JSON is read as IOS XR's JSON — see JSON.
- A compressed frame, which neither Cisco's own collector nor Telegraf reads, closes the connection with a warning. So does a header that claims a message larger than
max_message_size.
A problem with what a router sends — a message that cannot be read, a row nested past the limits, compact rows, a datagram that cannot be read — is logged once for as long as its connection lasts, since a router sends the same thing at every interval. Over UDP, which has no connection, it is logged once per router.
UDP
Every message comes whole in a datagram of its own, behind a header: IOS XR's is the twelve-byte header of the TCP transport, NX-OS's a six-byte header of its own. A datagram is one message, and nothing joins a message sent in parts.
- IOS XR: a heartbeat is skipped, and JSON is read as over TCP.
- NX-OS: a message of GPB is read. NX-OS's JSON and XML are left out with a warning that says to configure
encoding GPB. - A compressed datagram, one shorter than the message its header claims, and one that begins with neither header — NX-OS's secure UDP among them — are left out with a warning, once per router, and the next datagram is read.
JSON
IOS XR's JSON (encoding json) is one JSON object per message, its rows under data_json, each an object of its timestamp, its keys and its content. A row of it is the same record the same row of GPB-KV makes — see Records. No deletion is read from it.
Records
A telemetry message says which encoding path its rows are of, which router sent them, the subscription, and the collection's id, start and end. Each row has a time, its keys (the list entry it is, such as an interface's name) and its content (the values). Every row is one ECS record:
{
"@timestamp": "2026-09-21T14:13:20.123Z",
"ecs": { "version": "8.11.0" },
"event": { "module": "cisco_mdt", "dataset": "cisco_mdt.telemetry", "kind": "metric", "category": ["host"], "type": ["info"] },
"observer": { "vendor": "VirtualMetric", "product": "Cisco MDT", "name": "cisco-mdt", "hostname": "director-01" },
"network": { "protocol": "grpc", "transport": "tcp" },
"client": { "ip": "192.0.2.21", "port": 40112 },
"host": { "name": "pe-ams-01" },
"cisco_mdt": {
"telemetry": {
"table": "ifstats",
"path": "Cisco-IOS-XR-infra-statsd-oper:infra-statistics/interfaces/interface/latest/generic-counters",
"subscription": "interfaces",
"collection": { "id": 77, "start": "2026-09-21T14:13:20.1Z", "end": "2026-09-21T14:13:20.3Z" },
"keys": { "interface_name": "HundredGigE0/0/0/0" }
},
"ifstats": { "packets_received": 5, "bytes_received": 5000, "input_errors": 2, "last_data_time": 17 }
}
}
- The content is under
cisco_mdt.<table>— see Tables. - What the row is — its table, encoding path, subscription, collection and keys — is under
cisco_mdt.telemetry. The keys keep the types the router sent, a number as a number. - The router is
host.name, by the name it gives itself. Where its connection came from isclient.ipandclient.port. The listener is theobserver. - The transport is
network.transport:tcpover gRPC and TCP,udpover UDP.network.protocolisgrpcover gRPC only. - Field names are the model's, with an underscore for every hyphen and dot:
packets-receivedispackets_received. Case is the model's, so NX-OS'soperStstaysoperSt. - The tree is kept. A field that holds fields is an object of them, and fields that share a name, or that have no name, as a router writes the entries of a list, are a list. A field that holds nothing is left out.
- Values are written as the router types them: text, bytes in base64, a switch, a whole number (signed or not, 64 bits), or a number. A NaN or an infinity, which JSON cannot hold, is left out.
- Time. A record is dated by its row's time, else its message's, else when it arrived.
- A deletion. A row the router says was deleted is a deletion event (
event.type: deletion,event.action: delete) with its keys,cisco_mdt.telemetry.deleted: true, and no content. - Compact GPB rows are counted and left out, with a warning that names the path. The self-describing rows of the same message are written.
- Limits. A row nests at most 128 levels, and the rows of one message hold at most 1,048,576 fields in all. A row past either is left out with a warning; past the second, so is the rest of its message.
Records are written under definition ID 859, as network log records.
Tables
A table named in aliases holds the rows of its encoding path:
aliases:
ifstats: "Cisco-IOS-XR-infra-statsd-oper:infra-statistics/interfaces/interface/latest/generic-counters"
An encoding path with no table gets one made of the path, in lower case, with an underscore for every run of characters a field name cannot hold. Cisco-IOS-XR-infra-statsd-oper:infra-statistics/interfaces/interface/latest/generic-counters is cisco_ios_xr_infra_statsd_oper_infra_statistics_interfaces_interface_latest_generic_counters, and show interface is show_interface. A path that would make telemetry makes telemetry_.
A table name in aliases:
- begins with a letter or an underscore, and holds letters, digits and underscores;
- is at most 64 characters;
- is not
telemetry, which every record already has.
An encoding path is at most 1024 characters and has one table, and a device names at most 256.
Connection States
- Connected: the configuration is read and the port can be bound. Over UDP, Connected says only that the port is bound.
- Connection error: the port cannot be bound.
- Configuration error: a configuration that cannot run — see Advanced Configuration.
When the device stops, every router's stream or connection is closed. What is being written of a message at that moment is cut off; the router sends the next one when it dials out again. A message waits for room in the device's buffer, and the router's stream waits with it. Over UDP the router does not wait: datagrams wait in the socket's buffer, and are lost once it is full.
Every node of a cluster runs the device. A router sends to the node its destination group names, or to a load balancer in front of the nodes.
Migrating from Telegraf
Where the device departs from Telegraf's cisco_telemetry_mdt input:
| Telegraf | This device |
|---|---|
transport, tcp or grpc | transport, grpc, tcp, or udp |
| Self-describing GPB alone: a message of JSON cannot be read | IOS XR's JSON too, over every transport |
A metric per row, its fields flattened into /-joined names | A record per row, its content kept as a tree under cisco_mdt.<table> |
aliases, a measurement name per encoding path | aliases, a table name per encoding path. Without one, the table is made of the path |
embedded_tags, to tell list entries apart | No counterpart: a list is a list in the record |
dmes, to convert the types of NX-OS values | No counterpart: a record keeps the type the router sent, and the pipeline converts types |
include_delete_field | No counterpart: a deleted row is always written, as a deletion event |
source_field_name, to rename a key called source | No counterpart: the router is host.name and the keys are under keys, so nothing clashes |
grpc_enforcement_policy | No counterpart: keepalive needs no setting |
max_msg_size on gRPC; 1 MiB on TCP unless set | max_message_size on gRPC and TCP, 4 MiB by default |
service_address, tls_cert, tls_key, tls_allowed_cacerts | address and port, and tls |
Console
In the console, go to
Protocol settings :Listen address (Optional) ,Port , andTransport —gRPC ,TCP , orUDP . For gRPC,TLS settings follow: theTLS encryption switch, and enabled, the certificate and its private key, the passphrase, the routers' own certificates and their CA, and the minimum and maximum TLS version. The step's description names what a router needs: a destination group with this Director's address and port, the transport, and the self-describing-gpb encoding, and a subscription that sends its sensor paths there.Advanced settings :Tables : a list ofTable name andEncoding path rows, withAdd table . With none, every encoding path's rows are written under a table made of the path.Maximum message size (Optional) , not shown withUDP .Socket address reuse : lets the listener bind its port while the one it replaces is still closing, so a restart is not refused.- The
Simulation section.
Simulation
The device can be simulated as the other listeners are — see Device Simulation. The cisco_mdt_telemetry sample generates rows of IOS XR interface counters and memory, and IOS XE CPU utilization, in the shape Records shows.
Examples
gRPC with Router Certificates
Taking IOS XR, IOS XE and NX-OS telemetry over gRPC, with TLS and a certificate required of every router, and two tables named... | |
IOS XR over TCP
Taking the telemetry of IOS XR edge routers over the TCP transport, which has no TLS... | |
IOS XR and NX-OS over UDP
Taking the telemetry of IOS XR and NX-OS edge routers over UDP, a datagram per message, which has no TLS... | |