Why the Networking Industry Needs a Mini-NETCONF, and Needs It NOW

PyEZ Screenshot

In my last couple of posts I looked at the concept of managing network device configurations in an abstracted fashion – that is, saying what you want to configure rather than how it should be configured. To that end I looked at Tail-f’s NCS product – a very capable commercial offering that takes big steps in that direction.

However, maybe it’s possible to take smaller steps with the Junos PyEZ library. In this post I’ll look in theory at how this might work in a product that’s ostensibly only for Juniper, and look at why there’s need for a “Mini-NETCONF” to be adopted by the networking industry as a whole.

In case you haven’t come across the Junos PyEZ libraries before, I have written a number of posts discussing the Junos PyEZ Python libraries that might be good background.

Gather Facts

When I last spoke to the Junos PyEX author, Juniper’s Jeremy Schulman, we discussed the importance of beginning any process by gathering facts – a classic DevOps approach. As this applies to PyEZ, that means figuring out what device you’re connecting to. That’s not just because it’s useful information, but also because different devices may need to be queried in slightly different ways. By knowing at the start of the process what device type you connect to, you can adjust all future commands to suit.

The insight is Jeremy’s (though he is keen to stress that it’s not his idea), but I’d already noted that this is precisely what PyEZ does when you connect to a device – it effectively says “What are you?” Without having to issue any explicit request, connecting to a device also queries it to find out what it is – the “facts”. In my post on using PyEZ interactively you can see this:

john@ubuntu:~$ ./pyez srx1

Please provide password for user 'script' on device 'srx1'.
Password:
Connected to srx1 as dev
>>> 
>>> pp (dev.facts)
{'2RE': False,
 'RE0': {'last_reboot_reason': '0x1:power cycle/failure ',
         'model': 'RE-SRX100H',
         'status': 'OK',
         'up_time': '19 days, 19 hours, 42 minutes, 41 seconds'},
         'fqdn': None,
 'hostname': None,
 'ifd_style': 'CLASSIC',
 'model': 'DELL J-SRX100H',
 'personality': 'SRX_BRANCH',
 'serialnumber': 'AB9110AE0730',
 'switch_style': 'VLAN',
 'version': '10.3R2.11',
 'version_info': junos.version_info(major=(10, 3), type=R, minor=2, build=11)}
 >>>

Out of the gate we know a bunch of information about this device, including the code version and the personality, which is derived from the model name – in this case a Dell branded SRX100H. SRX users will recognize the importance of distinguishing between SRX High End and SRX Branch devices, so knowing this from the start is important.

Dare to Dream

If this works for Junos, perhaps it might work elsewhere. In theory, consider this:

john@ubuntu:~$ ./pyez cisco1

Please provide password for user 'script' on device 'cisco1'.
Password:
Connected to cisco1 as dev
>>> 
>>> pp (dev.facts)
{'2RE': False,
 'RE0': {'last_reboot_reason': '0x1:power cycle/failure ',
         'model': '7206VXR',
         'status': 'OK',
         'up_time': '19 days, 19 hours, 42 minutes, 41 seconds'},
         'fqdn': lab.com,
 'hostname': cisco1,
 'ifd_style': 'CLASSIC',
 'model': 'Cisco 7206VXR',
 'personality': 'IOS',
 'serialnumber': 'AB9110AE0730',
 'version': '12.4(13)T',
 'version_info': os.version_info(major=(12, 4), type=T, minor=13)}
 >>>

Why not? What we would need in order for this to work is that all the manufacturers agree to have a standard way to get this information.

I Shall Call It “Mini-Me”

The PyEZ libraries use NETCONF to query Juniper devices, and this would likely make a great standard mechanism if only all manufacturers could be persuaded to support it across all their product lines – with at least enough functionality to find out what kind of device it is. That way any querying tool could identify what level of support would be offered and what configuration style to follow.

For example, even if Cisco does not wish to support XML for legacy IOS, why not have a mini NETCONF listener that will respond to one request only – to give enough information about the device that a tool like PyEZ or Tail-f’s NCS would know that it would need to use the CLI for configuration instead. As the OEM for the most commonly deployed NETCONF services, Tail-f would no doubt prefer that a full implementation went in every time. However, in terms of assisting manufacturers in quickly deploying a common initial access mechanism I like the idea of a minimal NETCONF agent whose simplicity means it could quickly and easily be deployed across a wide range of platforms without the significant level of development effort I would assume is required to implement a full NETCONF agent with complete query and configuration abilities.

If not NETCONF, then something would be nice. We may need a little more than default SNMP polls, but maybe that’s the way forward short term? Perhaps the frustration is that you end up writing a library that has to start with NETCONF, fall back to SNMP, and if not, try SSH, then telnet, and so forth until a successful method is found (and ironically with SSH/telnet you need to identify the platform in order to know what command to issue…).

And if They Don’t?

What happens if the industry can’t agree on a standard fact-gathering mechanism? Well we can always return to telling our scripts what kind of device they are connecting to. Using the Perl module “Net::Appliance::Session” module for example, you have to tell the module what kind of device you are connecting to:

 use Net::Appliance::Session;

 my $s = Net::Appliance::Session->new({
     personality => 'ios',
     transport => 'SSH',
     host => 'hostname.example',
 });

The ‘personality’ element tells the module what to expect from the device, including the nature of the prompt, how to deal with paged output, and so on. With that set, you can issue (platform-specific) commands fairly easily. To be clear, this is not a module that meets any of my goals except for the abstraction of the CLI interaction. Wouldn’t it be interesting if this tool could optionally initiate a connection to a mini-NETCONF agent and determine for itself what personality to use?

Now let’s assume that we have some kind of wonderful tool that abstracts configuration and makes it vendor agnostic. We know that capabilities and configuration options can change with new code releases, so how does such a tool use the correct conversion of the abstracted requirements to an implementation? Well, assuming we have the appropriate codebooks for each version of code, it’s a snap to use the appropriate one based on the output from our mini-NETCONF. More usefully – and to me this is very important – if a code upgrade takes place, because your tool gathers facts before doing anything, it can either change codebook automatically after a software upgrade to a device or, equally helpful, it can flag up if you are trying to configure a device for which no codebook has been installed. This is, presumably, preferable to just using what you had before and hoping it all still works.

Lack of a common fact-gathering interface is not an insurmountable problem, but it sure is inelegant, and the manual configuration process inevitably means that mistakes will be made at some point.

Uh, You Mentioned PyEZ?

Ok, back on topic. The reason I wanted to talk about PyEZ is that despite being a Juniper (and open source) project, it has the potential to be used across multiple vendors. Gather facts, identify that you’re talking to an NXOS device, then use the same type of Tables and Views structure to extract information from the end device. With some smart coding within PyEZ, it would be possible to the library itself to abstract the choice of table and view based on the device platform to which you are connecting. If you want to view a routing table, why do you care if there’s a different XML command for that in NXOS versus Junos OS?

Tables and Views

Remember that in the PyEZ libraries, the way you see data in your script (the view) is separated from how it’s extracted (the table). The table contains the actual RPC call that needs to be made, and the view pulls together the data from the table in a format that we want to work with (and only returning the data we ask for). Here’s a sample from my post about YAML in Junos PyEZ:

### ------------------------------------------------------
### show route <destination>
### ------------------------------------------------------

RouteTable:
  rpc: get-route-information
  args_key: destination
  item: route-table/rt 
  key: rt-destination
  view: RouteTableView

RouteTableView:
  groups:
    entry: rt-entry
  fields_entry:
    # fields taken from the group 'entry'
    protocol: protocol-name
    via: nh/via | nh/nh-local-interface

This is all very Junos specific right now, but it doesn’t have to be. I’m no YAML guru, but let’s assume that we choose to implement this for Junos OS and NXOS. Perhaps the updated code might eventually look like this (this is major pseudo-code, not intended to actually work!):

### ------------------------------------------------------
### show route <destination>
### ------------------------------------------------------

RouteTable:
  view: RouteTableView
  junos:
    rpc: get-route-information
    args_key: destination
    item: route-table/rt 
    key: rt-destination
  nxos:
    rpc: show/ip/route/
    args_key: destination
    item: TABLE 
    key: ipprefix

RouteTableView:
  junos:
    groups:
      entry: ipprefix
    fields_ipprefix:
      # fields taken from the group 'ipprefix'
      protocol: protocol-name
      via: nh/via | nh/nh-local-interface
  nxos:
    groups:
      entry: rt-entry
    fields_entry:
      # fields taken from the group 'entry'
      protocol: TABLE_path/ROW_path/clientname
      via: nh/via | TABLE_path/ROW_path/ipnexthop

Alternatively, Jeremy suggests, rather than bundling these all in the same files we might want to have the same table/view definitions in multiple folders – for IOS, NXOS, Junos etc. Thinking about it, his way is much more scalable and makes adding the necessary code to support new (or just the relevant) devices much simpler depending on your needs. Just as with Tail-f’s NCS, you may need to split those further, perhaps by code revision, to get the right results. Maybe we could define a default option for undefined code (if we chose to use it)?

Arrgggh, Cisco

I’ve not played with NETCONF on Cisco before, so I did some quick searches on the XML RPC call to grab the IP route table. It seems to me – and please educate me if I’m wrong – that Juniper have built a relatively simple set of commands, perhaps due in part to the legacy of JUNOScript. Even so, the difference between Junos and NXOS seems somewhat staggering. If I read correctly, to show the IP routing table for Junos using XML RPC I believe I could say this:

<rpc>
    <get-route-information />
</rpc>

And to show the same in NXOS:

<nf:rpc message-id="3" xmlns="http://www.cisco.com/nxos:1.0:urib"
 xmlns:nf="urn:ietf:params:xml:ns:netconf:base:1.0">
<nf:get>
  <nf:filter type="subtree">
    <show>
     <ip>
       <route/>
     </ip>
   </show>
  </nf:filter>
 </nf:get>
</nf:rpc>

I’m not even going to dig into the output that NXOS appears to generate, except to say that it appears to be unnecessarily unpleasant compared to the Junos XML reply.

Maybe I’m wrong about all this and I just landed on some bad pages. Did I miss a trick?

Putting It Together

Assuming I can figure out the Cisco RPC commands properly, this new table and view could be used to grab routing tables from any NXOS or Junos device without caring which is which. So long as I build the RouteTableView to map response data back to a consistent format between Junos OS and NXOS, my scripts won’t care which is which either because the data will appear to be the same. And this is all because the process when we want to populate the RouteTable table on a device is to gather facts then behave accordingly. From the user (script in this case) perspective though, all we did was request a routing table and let the underlying intelligence deal with the rest and return the results to us in a known format.

Good Theory

This is all (well, mostly) imagination, but it doesn’t have to be. What’s clear is that to make it easier to move towards my abstracted automated world, we need a way to identify with we’re working with. Give us that and writing the code to implement that abstraction becomes a little easier. Tools like Junos PyEX make it relatively easy for the user to customize what they want, and I’ll be interested to see if this is a direction the product ever takes.

What do you think? Is this the right approach, or am I off on the wrong path? Do you see this implemented already, and if so, where? I value your feedback, so please share as I believe this is an important discussion.

 

 

Disclosures

Tail-f was a paid presenter at Networking Field Day 7, and while I received no compensation for my attendance at this event, my travel, accommodation and meals were paid for by Tech Field Day. I was explicitly not required or obligated to blog, tweet, or otherwise write about or endorse the sponsors, but if I choose to do so I am free to give my honest opinions about the vendors and their products, whether positive or negative.

Juniper have been a paid presenter at multiple Networking Field Days, but Junos PyEZ has not been among the topics discussed while I was in attendance.

Please see my Disclosures page for more information.

4 Comments on Why the Networking Industry Needs a Mini-NETCONF, and Needs It NOW

  1. Great post! You’re hitting on many of the things about the NETCONF protocol that I believe has a chance to make a lasting change on how we program networks.

    As for cisco and NETCONF, there are now IOS-XRv builds with a new implementation of NETCONF (and YANG) that works very well.

    We’re getting there 😉

  2. Hi John,

    Thank you, and great blog post.

    If any vendor/ISV would like to discuss this topic in more depth, or understand the architectural decisions/ideas in the Junos PyEZ, please reach out and we can setup a google-hangout event.

    Cheers,

    — Jeremy

    @nwkautomaniac

  3. Regarding industry-standard facts gathering, I believe we’ll have to wait for YANG to be implemented on more platforms. This will be the standard means of representing operational and configuration state.

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.