Avatar

I occasionally get questions sent from engineers working on network automation. I am humbled that anyone would think of me when they are stuck on a question, and if it’s a question that I can help with I like to take the time to reply.

Recently I received an email from an engineer who was working through my Network Programmability Basics Video Course on DevNet. Their question related to understanding how the URLs for RESTCONF are constructed from the YANG models, and how to use the feature for something like updating IP addresses. It was an excellent question and allowed me to dive into the topic a bit more than I typically do during a session on YANG. I’m also a sucker for any chance to explore more of the depth of the protocols. The question (and my answer) was so good I thought more folks might be interested in checking them out.

Here is the question:

“While working through Network device APIs, video #3, “Learn to CRUD with GET, POST and DELETE using RESTCONF,” I am stuck on sending a PUT to configure GigabitEthernet2. I’m trying to understand the YANG model and how it fits in. Specifically, how to craft the resource address for the interface, where “interface” vs “interfaces” fall into the path. Also, where does “ietf-ip:ipv4” fit into the paths for working with IP addresses?”

And my answer:

First, the URL for RESTCONF is taken right from the YANG models and follows the key that I talk about in the video. So, with the ietf-interfaces model that looks like this:

moduleietf-interfaces 
   +--rw interfaces 
   |  +--rw interface* [name] 
   |     +--rw name                        string 
   |     +--rw description?                string 
   |     +--rw type                        identityref 
   |     +--rw enabled?                    boolean 
   |     +--rw link-up-down-trap-enable?   enumeration {if-mib}? 

(slightly edited for the post) 

The resource part of the URL for GigabitEthernet2 would be:  

/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2 

The question indicated confusion on “interfaces” vs “interface” in the URL.  The fact that “interface” appears 3 times in the path can make it confusing.  But there is a reason for each of them:  

  1. ietf-interfaces – the module name
  2. :interfaces – a container called “interfaces” (Note: containers in YANG are used to group and organize other attributes)
  3. interface – a list of individual network interfaces. Each interface in the list is uniquely identified by its name.

Now, let’s talk about configuring the IP address for an interface.  You can retrieve and update the IP for an interface by returning or working with the interface URI as we discussed above, but that URI is for all details of an interface, not just the IP address.  If you want to just work with the IP address, you asked a great question about the path for ietf-ip:ipv4.   

This takes us into the topic of YANG model augmentation, something I don’t go into during the Basics course, but I do talk about in this Cisco Live Session that you can watch for free.  The whole session would be great to watch as it goes deeper into NETCONF/RESTCONF/YANG, but the relevant part starts at 30 minutes. 

The short version is that through augmentation, the ietf-interfaces model is “augmented” by the ietf-ip model to add IPv4 and IPv6 addressing to an interface.  Here is a short snippet of that model:

module: ietf-ip 
  augment /if:interfaces/if:interface: 
    +--rw ipv4! 
    |  +--rw enabled?      boolean 
    |  +--rw forwarding?   boolean 
    |  +--rw mtu?          uint16 
    |  +--rw address* [ip] 
    |  |  +--rw ip                     inet:ipv4-address-no-zone 
    |  |  +--rw (subnet) 
    |  |     +--:(prefix-length) 
    |  |     |  +--rw prefix-length?   uint8 
    |  |     +--:(netmask) 
    |  |        +--rw netmask?         yang:dotted-quad {ipv4-non-contiguous-netmasks}? 

 With this new model info, we can build the path to retrieve the IPv4 address for an interface to be:  

/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2/ietf-ip:ipv4/address 

See the coloring for where the additional parts of the URI come from.  

A GET to this path would return something that looks like this:  

{ 
    "ietf-ip:address": [ 
        { 
            "ip""10.255.255.1", 
            "netmask""255.255.255.0" 
        } 
    ] 
} 

An interface can have more than one IP address, so “address” is a list.  If you knew the specific IP you wanted to retrieve, the URL would be:  

GET /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2/ietf-ip:ipv4/address=10.255.255.1 

Now suppose you want to update the IP address for this interface. There are a few options open to you, each with pros and cons.  

The first option, and most straightforward, is that you could send a PUT request to the URL for the IP address that you want to add to the configuration.  This might look like this:

PUT /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2/ietf-ip:ipv4/address=10.255.255.2 
{ 
    "ietf-ip:address": [ 
        { 
            "ip""10.255.255.2", 
            "netmask""255.255.255.0" 
        } 
    ] 
} 

This will ADD the IP 10.255.255.2 to interface GigabitEthernet2. The key here is that it adds the IP… any existing IP address on the interface will still be there.   

To remove an old IP from an interface, you could send a DELETE to the IP address.  

DELETE /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2/ietf-ip:ipv4/address=10.255.255.1 

An obvious question to ask is, “How can I change the IP of an interface in one step? Because of how the standards of NETCONF/RESTCONF/YANG are written, working with a LIST object has some annoying characteristics.  One of them is that you can’t UPDATE or DELETE an entire list in one targeted request.  This means a DELETE or PUT at the URL for the address list won’t work. 

This WON’T work
PUT /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2/ietf-ip:ipv4/address 

There is a bit of a “work around” for this limitation.  You can update the entire INTERFACE with the desired configuration using a PUT request.  In this case it is important to know that the data you send must include the entire desired interface configuration, not just the new IP addressFor example, you would need to include the current interface description along with the IP addresses.  If you left the description off, it would be removed from the interface.  This would look like:  

PUT /restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2 
{ 
    "ietf-interfaces:interface": { 
        "name""GigabitEthernet2", 
        "description""Configured by RESTCONF", 
        "type""iana-if-type:ethernetCsmacd", 
        "enabled"true, 
        "ietf-ip:ipv4": { 
            "address": [ 
                { 
                    "ip""10.255.255.1", 
                    "netmask""255.255.255.0" 
                } 
            ] 
        } 
    } 
} 

With this payload and API call, the interface would be configured with ONLY the IP listed.  Any currently configured address would be removed from the interface and replaced with this data.   

I hope this helps clarify the details behind how RESTCONF and the URLs work.  You are most definitely on the right track with these questions and wondering how it works. Part of the exploration of programmability is getting to the point where you know enough to even ask the questions.   

What questions do you have?

So what do you thinkI’m hoping that my answer helped the user who sent it my way, but what about youDid this help you better understand YANG?   

Reach out and let me know in the comments here, or over on Twitter I’m @hfpreston.  Or of course there’s always email too 😉 You can find me at hapresto@cisco.com 

Related resources  

Visit the new Developer video channel and let us know via Twitter the topics you want us to cover.