NETCONF and RESTCONF on IOS XE: Enable, Verify, Curl - 夜莺博客

NETCONF and RESTCONF on IOS XE: Enable, Verify, Curl

Every IOS XE box sold in the last decade speaks two model-driven APIs, and most of them are still being managed by screen-scraping the CLI. NETCONF gives you transactional XML sessions over SSH port 830; RESTCONF gives you HTTP verbs over HTTPS with JSON or XML, which means you can test a change with curl before you write a single line of Python. This article covers enabling both services, proving they are alive, reading and modifying data with real YANG paths and payloads, and the failure modes that stop each service from working in production.

The appeal of model-driven interfaces is that you stop parsing human-formatted text. Instead of a regular expression against show ip interface brief, you ask the device for a structured object that is defined by a published YANG model, and the device answers with the same keys and the same types every time. That consistency is what makes automation survivable across IOS XE versions, platforms and reboots.

Enable the Services

Both services are configured with a handful of lines from global configuration mode. The order matters because the crypto key and the HTTPS server are prerequisites.

conf t
 hostname R1
 ip domain-name lab.local
 username apiuser privilege 15 secret STRONG_PASSWORD
 crypto key generate rsa modulus 2048
 ip ssh version 2
 ip http secure-server
 netconf-yang
 restconf
end

netconf-yang turns on NETCONF over SSH; restconf requires the HTTPS server, so ip http secure-server must be enabled and reachable. The hostname and domain name are not cosmetic: the router builds its self-signed certificate and its SSH key from hostname.domain-name, so a missing ip domain-name is one of the most common reasons a certificate cannot be generated.

AAA, not the local user, should be the real access control in production. A local privilege 15 account is convenient for a lab, but on a live device you want the API traffic authenticated and authorized by TACACS+ or RADIUS with an explicit privilege level, and you want the API reachable only on a management VRF or a dedicated management interface. The HTTP server and NETCONF subsystem are part of the control plane; exposing them on a data-port VLAN is an invitation for trouble.

ip access-list standard MGMT-API
 permit 10.10.10.0 0.0.0.255
 deny any log
!
line vty 0 4
 transport input ssh
 access-class MGMT-API in

Keeping the API behind an access list and off the transit paths costs nothing and removes an entire class of risk. If you must run it on a shared interface, at minimum restrict the source addresses that can open TCP 830 and TCP 443.

Verify on the Device

show platform software yang-management process
show netconf-yang status
show netconf-yang sessions
show ip http server status
show netconf-yang sessions detail

The management process table should show confd and nes running. If RESTCONF refuses connections, the HTTPS server is the first suspect; if NETCONF refuses, check SSH v2 and that port 830 is permitted by any management ACL. On some platforms the first RESTCONF request after a reboot is slow because the YANG model set has to be loaded and cached, so a curl timeout on the very first call is not automatically a broken configuration.

You can also confirm the listener from the shell if the platform exposes a guest shell or bash:

Router#show ip http server status
HTTP server status: Enabled
HTTP server port: 80
HTTP server active session modules: ALL
HTTPS server status: Enabled
HTTPS server port: 443
NETCONF-YANG status: Enabled

Two commands tell you almost everything during an incident: show netconf-yang sessions shows who is connected and from where, and show netconf-yang sessions detail shows how many RPCs each session has executed. A stuck session with an idle timer is worth clearing so it does not hold a datastore lock.

Reading Data with RESTCONF

RESTCONF maps YANG nodes onto a URL path. A list key becomes a path segment with an equals sign, and the top-level module name is the anchor of the whole path.

GET /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2
Accept: application/yang-data+json

{ "ietf-interfaces:interface": {
    "name": "GigabitEthernet2",
    "description": "uplink",
    "enabled": true } }

The same request from a shell, with authentication, is a single line:

curl -k -u apiuser:STRONG_PASSWORD \
  -H "Accept: application/yang-data+json" \
  https://10.10.10.11/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2

Operational state lives under ...-oper models, for example the Cisco IOS XE interfaces operational model, so a config read and a state read use different paths. Configuration data is served from the running datastore, while counters, link state and statistics are served from the operational datastore:

curl -k -u apiuser:STRONG_PASSWORD \
  -H "Accept: application/yang-data+json" \
  https://10.10.10.11/restconf/data/Cisco-IOS-XE-interfaces-oper:interfaces/interface=GigabitEthernet2

Useful read-only helpers are the discovery endpoints. /restconf/data/ietf-yang-library:modules-state lists the modules the device can serve, and /restconf/data/ietf-restconf-monitoring:restconf-state/capabilities tells you which encodings and which depth of filtering you can request. Query parameters such as ?content=config, ?content=nonconfig, ?depth=2 and ?fields=... let you trim the answer, which matters on large models where a full read returns thousands of lines.

Patching a Change

PATCH /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2
Content-Type: application/yang-data+json

{"ietf-interfaces:interface": {"description": "uplink-to-spine1"}}

The curl equivalent, which also sets a comment and uses the JSON patch type, looks like this:

curl -k -u apiuser:STRONG_PASSWORD -X PATCH \
  -H "Content-Type: application/yang-data+json" \
  -d '{"ietf-interfaces:interface":{"description":"uplink-to-spine1"}}' \
  https://10.10.10.11/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2

Use PATCH for a partial update and PUT only when you intend to replace the whole resource - a PUT with one leaf silently removes the siblings you did not send. This is the single most damaging mistake in RESTCONF scripting: sending a minimal PUT payload and wiping a policy map, an IP address or an access group. Prefer application/yang-data+json with PATCH, and read the resource back afterwards to confirm the change landed.

Common HTTP outcomes to know: 409 means another session holds the datastore lock, 400 usually means a bad path or model name, 401/403 are authentication and YANG privilege problems. A 415 means the Content-Type did not match the payload; a 500 with a YANG error tag usually points at a value that violates a model constraint, such as an out-of-range VLAN or an interface name that does not exist on this platform.

Code Meaning in RESTCONF First thing to check
400 Malformed path, module or payload Spelling of the module and list key
401 / 403 Auth failure or insufficient privilege AAA method list and privilege level
404 Resource not found Is the node config or oper?
409 Datastore locked by another session show netconf-yang sessions
415 Unsupported media type Content-Type header

NETCONF for Transactional Work

<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
  <get>
    <filter type="subtree">
      <interfaces xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-interfaces-oper"/>
    </filter>
  </get>
</rpc>

NETCONF is the better fit when several objects must change as one unit or must be rolled back together, and it is the transport the automation frameworks expect. Always read the capabilities list first: not every image offers a candidate datastore or commit, so do not assume Junos-style commit semantics exist on IOS XE. The capability set is delivered in the <hello> exchange immediately after the SSH subsystem opens, and it is the contract that tells a client what it may do.

<ncclient>
<capability>urn:ietf:params:netconf:base:1.0</capability>
<capability>urn:ietf:params:netconf:base:1.1</capability>
<capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability>
<capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
</capability>

If candidate is not advertised, you edit the running datastore directly and rollback-on-error is your only safety net. A minimal Python session with ncclient demonstrates the handshake and a filtered read:

from ncclient import manager

with manager.connect(host="10.10.10.11", port=830, username="apiuser",
                     password="STRONG_PASSWORD", hostkey_verify=False) as m:
    print(m.server_capabilities)
    cfg = m.get_config(source="running",
        filter=("subtree", "<interfaces xmlns='urn:ietf:params:xml:ns:yang:ietf-interfaces'/>"))
    print(cfg.xml)

For a change that must be atomic, wrap the edits in a single <edit-config> with a default-operation of merge, add a <test-option>test-then-set</test-option> so the device validates before committing, and rely on rollback-on-error to undo the whole transaction if any one edit fails. That is the practical difference between NETCONF and firing a sequence of CLI lines over SSH: either every leaf lands or none of them do.

Authentication and Authorization on the API

Both APIs ride on existing AAA. A user who authenticates successfully but has no task or group authorization gets a 403 rather than a 401, and that distinction saves time. Verify the method lists that actually apply:

show running-config | section aaa
show aaa authentication
show aaa authorization
show users
debug ip http all

The dependency graph is worth internalising: RESTCONF needs the HTTP secure server, the secure server needs a crypto key, the crypto key needs a hostname and domain name, and all of it needs AAA authorization for the YANG task set. When someone reports "the API worked yesterday", walk that chain from the bottom up rather than restarting the service.

Troubleshooting Common Failures

  • Connection refused on 443. ip http secure-server is missing or the RSA key was never generated.
  • Connection refused on 830. netconf-yang is not enabled, SSH is on version 1, or an ACL blocks the port.
  • Empty JSON body. The path resolves but the node is operational, not configuration - move to the -oper model.
  • 409 Conflict. A previous session left a lock; close it or clear the stale session.
  • Model not found. The image does not include that YANG module; check the yang-library modules-state listing.
  • Works with curl -k but fails in Python. The certificate chain is untrusted - import the CA or disable verification deliberately, never by accident.

Testing Checklist

  1. Enable both services, then confirm with the four show commands above.
  2. Read one interface over RESTCONF with curl before attempting any write.
  3. Write with PATCH, then re-read to prove the change landed.
  4. Verify the same change in the CLI (show running-config interface GigabitEthernet2) - the model and the CLI must agree.
  5. Read the capabilities list and record whether candidate and rollback-on-error are supported.
  6. Store the working curl calls as the first regression test in your automation repository.

Once the read and patch calls are stable, the same endpoints are what Ansible, NAPALM and ncclient will use under the hood, so a few minutes spent proving them by hand pays back every time a playbook misbehaves.

Related reading: NETCONF, RESTCONF and gNMI compared, pyATS and Genie: parsing show commands and state diff, NetBox IPAM: prefixes, VLANs and IP addresses and Prometheus SNMP exporter for network devices.

原文链接:Cisco: RESTCONF Protocol configuration guide