Skip to content

Model-driven telemetry: streaming operational state

Model-driven telemetry (MDT) is how you get operational data off a network device without polling it to death. Instead of a management station asking every box "what are your counters now?" on a timer, the device pushes YANG-modeled data to a collector on a schedule or when something changes. This article covers the architecture, the choices that actually matter — dial-out vs. dial-in, periodic vs. on-change, and encoding — and a working IOS XE subscription wired to a Telegraf collector.

Why push beats SNMP polling

SNMP is a pull model: a poller reaches out to each device, walks a MIB, and parses the result — repeatedly, forever. That falls apart at scale. Thousands of devices polled every few minutes means thousands of round trips, coarse sampling, and CPU spent answering the same question over and over. MDT flips the direction:

  • Push, not pull — the device sends data on a schedule or on change, so the collector isn't hammering the fleet with poll requests.
  • Granularity — sub-second to per-minute sampling is practical, versus heavy SNMP walks every few minutes.
  • Model-driven — the data is defined by YANG, so you request exactly the leaves you want by a precise path, and what comes back is already structured.
  • Efficiency — compact binary encoding over modern transports scales to large fleets.

The payoff is structured data keyed by its YANG path — no screen-scraping, no fragile regex over show output.

The architecture

An MDT pipeline is a handful of parts, each answering one question. Read them left to right and you have the whole design:

Component Answers Detail
Sensor path what to collect A YANG XPath identifying the data, e.g. interface statistics
Subscription who initiates Binds a sensor path to a destination and cadence; dial-out or dial-in
Cadence how often Periodic (every interval) or on-change (only when a value changes)
Encoding the format Compact GPB, key-value GPB (self-describing), or JSON
Transport the channel gRPC (usual dial-out), gNMI (usual dial-in), or NETCONF
Collector the destination Ingests, stores, and visualizes — e.g. Telegraf → InfluxDB → Grafana

The flow is always the same: a sensor path says what, a subscription binds it to a destination at a cadence, the data is encoded and carried over a transport, and a collector receives it.

Dial-out vs. dial-in: who opens the connection

A subscription is established in one of two directions, and they are easy to mix up:

  • Dial-out — the device initiates the session to the collector and streams to it. The subscription is configured on the device, which connects outward. Good for stable, always-on pipelines.
  • Dial-in — the collector initiates the session to the device and requests a subscription dynamically. Nothing is pre-configured on the box, typically via gNMI. Good for collectors that discover and subscribe on demand.

The mnemonic: dial-out = device dials out; dial-in = collector dials in.

Cadence: match it to how the data behaves

Cadence is when updates are sent, and choosing wrong either floods the collector or misses events:

  • Periodic — send every interval. Right for values that always change, like interface counters, throughput, and CPU. You always want the latest sample.
  • On-change — send only when the value changes. Right for state that rarely changes but matters when it does, like an interface's oper-status or a protocol adjacency. There is no value in resending "up" every second, and on-change reacts the instant it flips to "down."

Pick periodic for counters, on-change for status. Streaming a volatile counter on-change would be a firehose of updates; streaming rare state changes periodically wastes bandwidth reporting "still up."

Encoding and transport

Encoding is how the data is serialized on the wire:

Encoding Trade-off
Compact GPB (Google Protocol Buffers) Smallest and fastest, but the receiver needs the .proto model to decode it
Key-value GPB (self-describing) Carries field names, so it decodes without the model — larger, but the common collector default
JSON Human-readable and largest

Compact GPB maximizes throughput; JSON maximizes readability; key-value GPB sits in the middle and is what most collectors expect. Transport is the channel the encoded stream rides: gRPC (often via gNMI) is the modern high-performance choice, while NETCONF-based yang-push reuses a NETCONF session you may already have. The Telegraf MDT input, for instance, expects key-value (self-describing) GPB — which is why the subscription below sets encode-kvgpb.

Configuring a subscription on IOS XE

On IOS XE, a configured (dial-out) subscription is a single telemetry ietf subscription block. Read it top-down: collect interface statistics, key-value-GPB encoded, and push them by gRPC to a collector every 30 seconds.

telemetry ietf subscription 101
 encoding encode-kvgpb
 filter xpath /ietf-interfaces:interfaces-state/interface/statistics
 stream yang-push
 source-address 10.0.0.1
 update-policy periodic 3000
 receiver ip address 10.0.0.50 57500 protocol grpc-tcp

Two details bite people:

  • The interval is in centiseconds. update-policy periodic 3000 means every 30 seconds, not 3000 seconds and not a sample count. The minimum is 100 — one second. For on-change instead, use update-policy on-change.
  • stream yang-push selects the IETF standard stream (RFC 8641), which supports both periodic and on-change over standard IETF YANG models. Cisco-native sensor paths (for example Cisco-IOS-XE-interfaces-oper) are the alternative, often used for high-rate native counters. The architecture is identical either way; only the model and stream name change.

Verify it on the device before you go looking at the collector:

show telemetry ietf subscription all
show telemetry ietf subscription 101 detail
show telemetry connection all        ! is the receiver actually connected?

Consuming the stream

On the collector side, the classic open-source pipeline is TIG: Telegraf ingests, InfluxDB stores, Grafana visualizes. Telegraf's cisco_telemetry_mdt input receives the gRPC dial-out stream on the port the device targets:

# telegraf.conf — receive gRPC dial-out MDT
[[inputs.cisco_telemetry_mdt]]
  transport = "grpc"
  service_address = ":57500"   # must match the receiver port in the subscription

Because the data arrives already structured and keyed by its YANG path, Telegraf writes clean, labeled series straight into InfluxDB — no parsing step, which is the whole point of the model-driven approach.

gNMI dial-in uses the same ideas in different words

When the transport is gNMI, the collector chooses a subscription mode: ONCE returns a single snapshot and closes, POLL pulls on demand, and STREAM holds a continuous subscription. Within STREAM, each path uses SAMPLE (like periodic), ON_CHANGE, or TARGET_DEFINED. These map directly onto the periodic/on-change concepts — same architecture, gNMI vocabulary.

Key takeaways

  • MDT pushes YANG-modeled operational data from the device to a collector; SNMP pulls by polling. Push is more efficient, more granular, and produces structured data.
  • The architecture is sensor path (what) → subscription (who/how often) → encoding + transport (format/channel) → collector (destination).
  • Dial-out: the device initiates to a configured receiver. Dial-in: the collector connects and subscribes, often via gNMI.
  • Cadence follows the data — periodic for counters and utilization, on-change for status like oper-status.
  • Encoding is GPB / key-value GPB / JSON; transport is gRPC / gNMI / NETCONF. Key-value GPB is the usual collector default.
  • On IOS XE the interval is in centiseconds (periodic 3000 = 30 s), and a common collector is the TIG stack (Telegraf → InfluxDB → Grafana).

Sources: Cisco IOS XE Programmability Configuration Guide — Model-Driven Telemetry, RFC 8641 — Subscription to YANG Notifications for Datastore Updates, Telegraf cisco_telemetry_mdt input plugin, gNMI specification (OpenConfig).