Provisioning MPLS L3 VPN’s w/async Python + RestConf

Introduction/Rambilings

https://github.com/thecraigus/mpls-auto-provision/tree/master

When initially getting into code and marrying it with network engineering, I wasn’t overly obsessed with the speed of execution – my code ran (most of the time) and that was that. Whatever I scripted tended to be faster than manually typing it out box-by-box anyway, any attempt at micro-optimizations tended to be the death of progress for me. I would obsess over timing a function and re-writing it rather than making significant progress in overall functionality – should I do a standard loop or list comprehension!?

However, there comes a time when looking at code execution and efficiency makes sense when looking at the big picture. Parallel execution of configuration changes against network devices typically fits this use case.

There are multiple schools of thought when it comes to this in the python world, one is threading and another other is asyncio.

For whatever reason in my studies and general labbing I have always gravitated down the path of writing async code vs threads, I’m unsure why – I think I just found async code a little easier to read/write and understand conceptually in the beginning – so I guess I ran with this approach. A great breakdown of the differences and use cases is outlined here (http://masnun.rocks/2016/10/06/async-python-the-different-forms-of-concurrency/)

I recently wanted to look at a small proof of concept in my lab for provisioning MPLS L3 VPNs with async RestConf API calls. Hopefully, it gives an outline of writing async code in a network engineering context and maybe inspires you to start coding/swap to async (if you dont already) 🙂

Lab Overview

In our hypothetical scenario, we administer an MPLS L3 VPN provider infrastructure, whenever we onboard a new customer we have to manually configure each PE node with the new customer VRF, BGP configuration, and Service Interface southbound to the access network on each PE node.

With the projected growth of the company, this process needs to be streamlined, error-free, fast, and ensure configuration consistency across the network. (‘fast’ is all relative I suppose, but in a code context we should look to eliminate the use of blocking functions and try to do as much as we can at the time same time)

In terms of hardware, the MPLS backbone network consists of 4 CSR1000V (3 Acting as PE nodes) routers with the RestConf API exposed. The access network is administered by a different BU and there is currently no initiative to automate this functionality.

Code Overview

As we are using RestConf we need to choose a HTTP library for working with the API, requests seems like an obvious choice – however as requests does not support asyncio (and fast is one of our requirements) we will be using aiohttp.

The async and await keywords are of particular importance when working with asyncio, By prepending the async keyword at the start of a function we essentially transform it into a ‘coroutine’ and lets python know that this should be ran asynchronously inside the event loop, the ‘await’ keyword hands control back to the event loop and can be used to ensure we don’t block execution of our code. From the function, we are returning the awaitable object.

In the context of the below – we are essentially saying “don’t wait for the API response, see if there is anything else to do”

The above logic is repeated throughout the code, there are specific class methods that create the configuration on the target devices (VRF, MP-BGP and Service Interfaces)

If we look at the main function it is again defined as a coroutine. We are instantiating a class for each of our PE nodes and by using the asyncio.create_task() method we are able to package together tasks that can be executed concurrently

I broke the create VRF, Update MpBGP and Provision Service interface out into three separate tasks with an async sleep function between them. If I ran them all within the same task I ran into some dependency issues / issues with the netconf data store syncing – I’m assuming this isn’t the most elegant way to do this however it works!

We are passing our main coroutine into the event loop and instructing it to run until complete.

(Please place passwords in environment vars)

Code Run

Lets onboard a new customer!

In my config.ini file, I have the details of a new customer for that we want to create a L3 VPN for. The customer information be in a backend database or presented through an API – however for proof of concept this will do.

Other Burger chains are available – however, BK is king for a reason 🙂

Let’s quickly check our PE nodes, we only have 3 VPN’s configured thus far.

Run the code! – seemed to go without a hitch

Let’s check the PE nodes! – Looks like our new L3 VPN has been created as expected and prefixes are being exchanged.

Conclusion

There it is, async restconf calls! As always, all code is available on my github.

I appreciate you can’t see the speed in a writeup but trust me it’s substantially quicker than using a blocking library such as requests 🙂

All code below:-

https://github.com/thecraigus/mpls-auto-provision/tree/master

Leave a comment