Skip to main content

As network engineers, we have few tools that can help us correlate the actual state of our network devices, and our intent. In many cases maybe our intent is not clearly defined: How many EIGRP neighbors is the set of core switches really supposed to have? How many neighbors should I be learning a specific prefix from? How many entries should I have for prefix x in my EIGRP Topology or my OSPF Database? Is my intent to have all the entries installed in the Route Table as ECMP paths or should I only ever have 1 next-hop that only changes if a path becomes unavailable?  In the network engineering realm specifically, even with automation tools like Ansible - without structuring your playbook logic very specifically - there are assumptions being made about the current state of the network. Even if your Ansible repos & playbooks are structured in a declarative and idempotent fashion, they are not exactly a consumable way for a network engineer to learn about the network - and you are really only verifying that the network meets your intent whenever you execute a playbook for a specific task. 

A tool like Forward Networks not only allows us to express our network intent through both configuration state checks through NQE, AND Intent checks through the Verify component - it is an automatic way for us to verify our intent continues to be met after our changes, and even before you make the changes (if you use Workspace Networks to simulate the changes). Imagine a future where a new hire or maybe an engineer who spends more time on the tInsert technology here: VOIP, Storage, Wireless, etc] side of the house can quickly come up to speed on an entire environment - like say AWS Hybrid Cloud Connectivity - by popping open a folder and reviewing our network intent checks. This is my hope for both our network intent, and service awareness by creating Path-based Intent Checks for each service that our network delivers. 

Organizing NQE Intent Checks into easily digestible hierarchies

In my sanitized example below we are doing 3 checks - with more to be added:

  1. Verify that we are receiving routes from AWS US-EAST-1 by checking the BGP Table of both CGW Routers
    1. /**
      * @intent Verify CGW RTRs are receiving BGP NLRI for AWS US-EAST-1 Region
      * @description Each CGW RTR should be receiving a route for each AWS Region
      * from two different peers.
      */

      foreach device in network.devices
      where matches(device.name, "*CGW-RTR")
      where isPresent(device.bgpRib)
      let bgpRib = device.bgpRib
      foreach afiSafi in bgpRib.afiSafis
      foreach neighbor in afiSafi.neighbors
      /* matches takes a string as input, so convert the IPAddress to a string */
      /* We're only checking routes received from these specific peers 172.16.x.x */
      where matches(toString(neighbor.neighborAddress), "172.16.*")
      where isPresent(neighbor.adjRibInPost)
      let adjRibInPost = neighbor.adjRibInPost
      foreach route in adjRibInPost.routes
      /* Check for the US-EAST-1 Supernet in the BGP Table */
      where ipSubnet("x.x.x.x/12") in route.prefix
      select {
      deviceName: device.name,
      routePrefix: route.prefix,
      /* Cause a violation if the supernet is not found */
      violation: ipSubnet("x.x.x.x/12") not in route.prefix
      }

       

  2. Verify that we are receiving routes from AWS US-WEST-2 by checking the BGP Table of both CGW Routers
    1. This check is the same as above we just change prefixes where necessary
  3. Verify that both paths are installed in the Route Table, indicating that BGP ECMP is in effect.
    1. This particular NQE Check is looking under a VRF Instance
      1. /**
        * @intent Verify CGW RTRs Installed BGP ECMP Routes into the RT
        * @description Each CGW RTR should be receiving a route for each AWS Region
        * from two different peers.
        */

        foreach device in network.devices
        /* Only match the CGW-RTRs */
        where matches(device.name, "*CGW-RTR")
        foreach networkInstance in device.networkInstances
        /* filter for the 'aws' vrf */
        where matches(networkInstance.name, "aws")
        let afts = networkInstance.afts
        where isPresent(afts.ipv4Unicast)
        let ipv4Unicast = afts.ipv4Unicast
        foreach ipEntry in ipv4Unicast.ipEntries
        /* match only the prefixes for the AWS Regions */
        where matches(toString(ipEntry.prefix), "x.x.x.x/12" ) || matches(toString(ipEntry.prefix), "x.x.x.x/12")
        foreach nextHop in ipEntry.nextHops
        select {
        // Cause a VIOLATION if the prefixes don't have exactly 2 next hops in the RT
        // Indicating that ECMP is NOT in effect. Since object is list type we just check the
        // length
        violation: length(ipEntry.nextHops) != 2,
        deviceName: device.name,
        vrf: networkInstance.name,
        ipEntryPrefix: ipEntry.prefix,
        nextHopIp: nextHop.ipAddress,
        interfaceName: nextHop.interfaceName,
        originProtocol: nextHop.originProtocol
        }

 

In expressing network intent this way, we will create a consumable ‘repository’ of sorts for SMEs to come up to speed quickly on components of the network but also a way for us to verify that our changes do not violate our blueprint for how things should be working. I am especially excited that the last update brought the same folder style hierarchy to the Verify side of the App so we can organize our Path Based Intent Checks.

 

Happy NQEing!

Great post @BDrinkard … thanks!


Reply