Skip to content
Log in Sign up My account

YANG, NETCONF, RESTCONF and gNMI Walkthrough

Model-driven programmability replaces screen scraping with structured APIs. YANG defines what the data looks like, and NETCONF, RESTCONF and gNMI are three ways to read and change it. This walkthrough shows how to find a model, pull and change configuration with ncclient and with curl, and subscribe to telemetry with gNMI using gnmic, including the difference between periodic and on-change subscriptions.

The examples use a Cisco IOS XE device, but the ideas carry to any platform that supports these interfaces.

How the pieces fit

graph TB
    Y["YANG models<br/>define the data (RFC 7950)"] --> N["NETCONF<br/>XML over SSH, port 830"]
    Y --> R["RESTCONF<br/>HTTPS, JSON or XML, port 443"]
    Y --> G["gNMI<br/>gRPC, Protobuf or JSON"]
    N --> D["Device datastores<br/>running config and state"]
    R --> D
    G --> D
  • YANG (RFC 7950) is a modelling language. A YANG module describes containers, lists and leaves, their types, and whether they are configuration or operational state.
  • NETCONF (RFC 6241) is an RPC protocol. It runs over SSH (default port 830), exchanges XML, and has operations such as get, get-config, edit-config, commit and lock.
  • RESTCONF (RFC 8040) maps the same models onto HTTP methods (GET, PUT, POST, PATCH, DELETE) with JSON or XML bodies.
  • gNMI is the gRPC Network Management Interface from the OpenConfig project. It has Get, Set, Capabilities and Subscribe RPCs and is the main choice for streaming telemetry.

NETCONF and RESTCONF are good for configuration. gNMI is the leading choice for telemetry at scale because the device pushes data and the collector does not have to poll.

Enable the interfaces on IOS XE

netconf-yang
restconf
ip http secure-server

netconf-yang starts the NETCONF server on port 830. RESTCONF needs the HTTPS server, and the account you use must have privilege 15 or an appropriate AAA authorisation. Check the programmability configuration guide for your release for gNMI, since the enable commands and the port (commonly 9339 for secure gNMI) depend on the software version. Verify what is running with:

show netconf-yang status
show platform software yang-management process

Warning

Do not leave these interfaces open to your whole network. Restrict the management plane with ACLs or a management VRF, and use certificates instead of disabling verification once you are past the lab stage.

Finding the right model

You need three things: which models the device supports, what they look like, and the path to the data you want.

  1. Ask the device. NETCONF advertises its capabilities in the hello message, and gNMI returns them from Capabilities. Both list the supported modules and versions.
  2. Browse the source. The community YangModels/yang repository holds the vendor and standards modules. Cisco's IOS XE models live under vendor/cisco/xe/<release>/.
  3. Render a tree. Install pyang and print the structure:
pip install pyang
pyang -f tree -p . ietf-interfaces.yang
pyang -f tree --tree-path /interfaces/interface Cisco-IOS-XE-native.yang | head -50

The tree shows each node, with rw for configuration and ro for operational state. Three families of models matter:

Family Example module Notes
IETF ietf-interfaces, ietf-ip Standard but limited coverage
OpenConfig openconfig-interfaces, openconfig-bgp Vendor-neutral; support level varies
Native Cisco-IOS-XE-native, Cisco-IOS-XE-interfaces-oper Full coverage of the platform, vendor-specific

If you only need to manage Cisco gear, native models cover the most. If you manage several vendors, prefer OpenConfig or IETF where the device implements what you need.

NETCONF with ncclient

pip install ncclient

Pull configuration

from ncclient import manager

with manager.connect(
    host="192.0.2.10",
    port=830,
    username="automation",
    password="change-me",
    hostkey_verify=False,        # lab only
    device_params={"name": "iosxe"},
) as m:
    flt = """
    <filter>
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>GigabitEthernet1</name>
        </interface>
      </interfaces>
    </filter>
    """
    reply = m.get_config(source="running", filter=flt)
    print(reply.xml)

The filter is a subtree filter. You name the nodes you want, using the module's XML namespace, and the device returns only those. A request without a filter returns the entire config, which can be large.

To see what the device supports:

for cap in m.server_capabilities:
    print(cap)

Change configuration

config = """
<config>
  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
    <interface>
      <name>GigabitEthernet2</name>
      <description>uplink to dist-1</description>
      <enabled>true</enabled>
    </interface>
  </interfaces>
</config>
"""
reply = m.edit_config(target="running", config=config)
print(reply.ok)

edit_config merges by default, so only the leaves you send change. Per-element operation attributes (replace, delete, remove, create) override that. IOS XE writes to the running datastore directly, and a candidate datastore is only available when enabled separately. Changes made this way live in the running config, so save them as you would after any other change (copy running-config startup-config, or the Cisco save-config RPC).

A good habit is to read back the same filter after edit_config and confirm the new value.

RESTCONF with curl

The same data is available over HTTPS. The root is /restconf/data/, the module name prefixes the top container, and list keys follow an equals sign.

curl -k -u automation:change-me \
  -H "Accept: application/yang-data+json" \
  https://192.0.2.10/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet1

-k skips certificate verification and is for the lab only. The Accept header selects JSON; use application/yang-data+xml for XML. Interface names with slashes must be URL-encoded, so GigabitEthernet1/0/1 becomes GigabitEthernet1%2F0%2F1.

Change a description with PATCH, which merges:

curl -k -u automation:change-me -X PATCH \
  -H "Content-Type: application/yang-data+json" \
  -H "Accept: application/yang-data+json" \
  -d '{"ietf-interfaces:interface": {"name": "GigabitEthernet2", "description": "uplink to dist-1"}}' \
  https://192.0.2.10/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2

A successful PATCH returns 204 No Content. The methods behave differently:

Method Effect
GET Read a resource
POST Create a child resource (fails if it exists)
PUT Create or replace the target resource entirely
PATCH Merge the supplied data into the target
DELETE Remove the target

PUT replaces everything at that path, so PUT on a whole interface removes attributes you did not include. Use PATCH unless you mean to replace. Error responses are JSON documents with an errors list, and the HTTP status (400, 401, 404, 409) tells you the category.

RESTCONF is easy to use from anywhere HTTP works, including Python requests, Postman and shell scripts, which makes it a good first model-driven interface to try.

gNMI and telemetry with gnmic

gnmic is an open-source gNMI client (see its documentation for installation options). Start by confirming the connection and listing supported models:

gnmic -a 192.0.2.10:9339 -u automation -p change-me --skip-verify capabilities

--skip-verify ignores certificate validation and is for the lab. Use --tls-ca with your CA file in production.

Read a value once with get:

gnmic -a 192.0.2.10:9339 -u automation -p change-me --skip-verify \
  get --path "/interfaces/interface[name=GigabitEthernet1]/state/oper-status"

gNMI paths use the schema's path format with list keys in square brackets. The paths you can use depend on which models the device supports, so take them from capabilities and from the YANG tree.

Change a value with set:

gnmic -a 192.0.2.10:9339 -u automation -p change-me --skip-verify \
  set --update-path "/interfaces/interface[name=GigabitEthernet2]/config/description" \
      --update-value "uplink to dist-1"

Subscribing

A subscription asks the device to send data on its own. The key choice is the mode.

Periodic (sample). The device sends the current value at a fixed interval, whether or not it changed.

gnmic -a 192.0.2.10:9339 -u automation -p change-me --skip-verify \
  subscribe --path "/interfaces/interface/state/counters" \
            --mode stream --stream-mode sample --sample-interval 10s

On-change. The device sends an update only when the value changes, plus an initial snapshot.

gnmic -a 192.0.2.10:9339 -u automation -p change-me --skip-verify \
  subscribe --path "/interfaces/interface/state/oper-status" \
            --mode stream --stream-mode on-change
graph LR
    subgraph Periodic
    A1["t=0 value 100"] --> A2["t=10 value 140"] --> A3["t=20 value 140"] --> A4["t=30 value 190"]
    end
    subgraph OnChange
    B1["initial value up"] --> B2["change: down"] --> B3["change: up"]
    end

Use periodic for counters and gauges such as byte counts, CPU and memory, because they change constantly and you want a regular time series for graphs. Use on-change for state and events: interface status, BGP neighbour state, configuration changes. On-change gives faster detection and far less traffic, but not every path supports it. A device may reject the subscription or fall back to sampling for paths that cannot be tracked as events, so test each path.

Other modes exist: --mode once sends one snapshot and closes, and --mode poll lets the client trigger each update. A third stream mode, target-defined, lets the device pick per path.

To store the data, gnmic can write to Prometheus, InfluxDB, Kafka and other outputs from a config file, which turns a one-off command into a collector. Check its documentation for the output options.

Choosing between them

Task Good choice
One-off config read or write from a script RESTCONF or NETCONF
Transactional multi-part config change NETCONF (candidate, lock, commit where supported)
Quick checks from the shell RESTCONF with curl
Streaming interface counters and events gNMI subscriptions
Multi-vendor, vendor-neutral models gNMI or NETCONF with OpenConfig where supported

These interfaces do not replace the CLI knowledge you need to read the result. The model for a BGP neighbour still maps to the same protocol behaviour you study in the CCNP course. To try the examples without production gear, build a virtual IOS XE device as described in the lab setup guide.

For tooling that wraps these protocols, Netmiko is still the fallback when a feature has no model, and Ansible has netconf and httpapi connection types that use the same models.

References