How do i automate a MAC deal with interface report?
As 2020 was overall I got an excellent issue in over email from the customer We’d already been exchanging ideas upon automation along with for a little. It was just an ideal task and distraction to focus on as I obtained ready to begin my holiday break.
The gist of the question is:
As with a whole lot of things within tech, once I dove within were a variety of interesting items that I learned, and questions concerning the workflow up came.
< h1>My Assumptions and Approach
With any task, it’s import to create out there some guardrails to scope yourself within. Right here’s what We developed for this one.
- I wanted to develop a tool that may be used across different conditions, and wasn’t strongly associated with a specific system or topology.
- The use case in the question specified the need to focus on the ARP table from network products for the Mac pc address interface report. I followed this process in my own script, so in case a MAC tackle was within a MAC desk, but no corresponding ARP access was found the Mac pc address is ignored.
- I assumed there is a subset of gadgets in the system that performed the Level 3 perform, and where we’d verify ARP tables. The easiest method of identifying this subset had been to create it an insight to the script.
- Our interest is within access ports where Mac pc Addresses arrive, not inter-change trunks. This meant having the ability to ignore or eliminate cases where Mac pc addresses arrive on trunks automatically will be important. I’ve found most system engineers use common change interfaces (usually port-channel) as inter-switch hyperlinks. The script takes being an input a listing of interface titles to skip/disregard when reporting interfaces in which a MAC address is available.
- The resulting information from the script is really a JSON document. I proceeded to go with this particular as it’s an excellent format to allow all afterwards manipulation of the info.
As I prefer to build things to have the ability to share always, I’ve posted the ultimate script to GitHub at https://github.com/hpreston/demo_mac_to_interface_tool. Many people are welcome to utilize it since it is, or create from it on your own requirements. But remember this all essential caveat:
This script is provided for example only, and will not include any liability or guarantee for damage. Before working this script against your system, you need to test it thoroughly, and understand the impacts it shall have.
How to utilize the script:
Suppose you need to leverage this ensure that you script it within your lab. This script is made using pyATS, an open supply Python system automation framework from Cisco. In case you are not used to pyATS, I’d motivate one to checkout the Getting Started Guide upon DevNet.
Begin by installing pyATS within your Python virtual atmosphere. I’ve included a requirements file which has the edition of pyATS I useful for the task, but any newer edition should work.
python3.7 -m venv venv source venv/bin/activate pip install -r specifications.txt
First, you’ll have to generate a Testbed for the network to begin with. A Testbed is similar to an inventory document from Ansible or another automation device. The testbed file is usually formatted in YAML, but could be produced from an Excel/CSV document or other strategies. For full information on Testbed creation, have a look at Creating Testbed YAML File in the documentation.
You have the testbed document once, you’d operate the script with the command such as this:
python mac pc_lookup.py --testbed testbed.yaml --l3device leaf01-1 oob01 --skipinterface "Port-channel2"
The parameter “l3gadget” takes a set of device titles from the testbed which have the ARP information the outcomes will undoubtedly be built from. And “skipinterface” will be the list of interswitch hyperlink interface names to disregard in the full total results.
Note: It is possible to operate “python mac_lookup.py –assist” for information on the parameters.
The script would run and offer output such as this:
Building Mac pc Address list through ARP info on devices leaf01-1, oob01 Looking up Coating 3 IP -> MAC Mappings. Checking L3 gadget leaf01-1 Checking L3 gadget oob01 Finding out about interfaces where Mac pc addresses are found upon the testbed. The next interfaces will undoubtedly be ignored: Port-channel2 No ARP for Mac pc Tackle bcf1.f2dc.29a5 found. No ARP for Mac pc Deal with 0050.5661.c275 found. Saving leads to file 'results.json'. Disconnecting from all products. Disconnecting from leaf01-1 Disconnecting from oob01 Disconnecting from spine01-1
The resulting “results.json” file could have data that appears such as this:
"0050.568c.7aa1": "ip": "172.19.248.55", "interfaces": [ "device": "spine01-1", "interface": "Ethernet1/7", "mac_type": "dynamic", "vlan": "41" ] , "0050.5661.4bba": "ip": "172.19.6.11", "interfaces": [ "device": "spine01-1", "interface": "Ethernet1/6", "mac_type": "dynamic", "vlan": "30" ] , "000c.29aa.086b": "ip": "172.19.6.12", "interfaces": [ "device": "spine01-1", "interface": "Ethernet1/6", "mac_type": "dynamic", "vlan": "30" ]
How it functions, a peak beneath the hood
I highly encourage one to go through the full script to seriously understand how it functions. I did my far better provide comments and illustrations within to greatly help describe the movement and the proceedings. This was as much for me for anyone else who could possibly be interested in it. But you can find few parts of the event and logic that I believe are well worth discussing directly here.
I wanted to create this as an instrument that anyone might use, which means a CLI kind utility typically. I opted to leverage the regular argparse utility from Python, though you can find other libraries available aswell. Click is a different one I’ve used often before for better quality tools.
The key section of argparse is allowing users to supply inputs to the script at run time. That is observed in this area of the code:
parser.add_argument( "--testbed", dest="testbed", help="testbed YAML document", type=str, default=None, ) parser.add_argument( "--l3device", dest="layer3_devices", help="Layer 3 Gadgets whose ARP tables will undoubtedly be gathered.", type=str, nargs="+", ) parser.add_argument( "--skipinterface", dest="skip_interface", help="Interface brands to skip understanding MACs on. Most useful for known trunks commonly.", type=str, nargs="*", default=, ) parser.add_argument( "--outputfile", dest="output_file", assist="File to save lots of the collected information to in JSON format.", type=str, default="results.json", )
< h2>Project functions and flow
You can find six steps to the script.
- Connect to all or any devices in the testbed apply for the network
- Identify which testbed devices will be the “layer 3 devices” where we’ll lookup ARP information
- Generate the original MAC list (technically a Python dictionary) from the ARP tables on the Layer 3 Devices
- Add interface details for every discovered MAC address
- Create the outcomes.json file
- Disconnect from all devices (we don’t desire to leave open VTY line connections)
Apart from writing out the full total results file, I created Python functions for every of the steps. This permitted for modular examining of the program code during development, and opportunities for future reusability.
It is a very basic function that first attempts to initialize a fresh Genie testbed object utilizing the provided testbed filename. Provided that the testbed document is formatted properly, this should succeed, but when there is one the script shall exit.
Tip: It is possible to verify your testbed document with “pyats validate testbed testbed.yaml”
The function attempts for connecting to all gadgets in the testbed then. Should a ConnectionError end up being raised because of device link failing, a note is composed to the display screen to notify an individual. However the failure for connecting to a tool does NOT cause the complete script to error.
The list is taken by this function of layer3_devices provided as input, and runs the correct “arp_lookup_command” for the platform utilizing the command parsing ability in pyATS.
I developed a dictionary for the most likely platforms and the correct command:
arp_lookup_command = "nxos": "display ip arp vrf all", "iosxr": "show arp details", "iosxe": "display ip arp", "ios": "present ip arp",
arp_info = gadget.parse(arp_lookup_command[device.os])
One of many benefits of pyATS is that the parser shall come back not the clear textual content output, but a good Python object we are able to work with rather. Here is a good example of what the returned information would look like
"interfaces": "Ethernet1/3": "ipv4": "neighbors": "172.16.252.2": "ip": "172.16.252.2", "link_layer_address": "5254.0016.18d2", "physical_interface": "Ethernet1/3", "origin": "dynamic", "age": "00:10:51" , "statistics": "entries_total": 8
You can easily see the set of commands which can be parsed with pyATS inside the documentation.
"0050.56bf.6f29": "ip": "10.10.20.49", "interfaces":  , "5254.0006.91c9": "ip": "10.10.20.172", "interfaces": 
This function is where we reach the real goal of our script. The interfaces where each Mac pc address is situated in the network is linked and identified to the ARP entry. This is done utilizing the command parsing features of pyATS with the order “show mac address-table”. This can generate a good Python object that appears like this:
"mac_table": "vlans": "999": "vlan": 999, "mac_addresses": "5254.0000.c816": "mac_address": "5254.0000.c816", "interfaces": "GigabitEthernet0/3": "interface": "GigabitEthernet0/3", "entry_type": "dynamic" , "total_mac_addresses": 3
An easy, but multi-level, group of Python conditionals and loops are accustomed to process this data for every device inside the testbed. It appears like this.
for vlan_id, vlan in mac_deal with_table["mac_desk"]["vlans"].items(): for mac_address, macintosh_details in vlan["mac pc_addresses"].items(): if mac_tackle in macs.keys(): for interface in macintosh_details["interfaces"].values(): if interface["interface"] not really in ignored_interface_titles: if "mac_kind" in interface.keys(): mac_type = interface["mac pc_type"] elif "entry_kind" in interface.keys(): mac_type = interface["access_type"] else: mac_kind = "N/A" macs[mac_deal with]["interfaces"].append( "device": device.name, "interface": interface["interface"], "mac_type": mac_type, "vlan": vlan_id, ) else: printing(f"No ARP for Macintosh Address mac_address found.")
Working our way by means of it:
- We have to loop over each VLAN returned from the desk. Each MAC table access is linked with a particular VLAN because the MAC Address Desk is linked with a Level 2 domain.
- Following we’ll loop over every Mac pc address listed within the VLAN
- The conditional “if macintosh_address in macs.keys():” is where we just process Macintosh addresses that had a corresponding ARP access found previously.
- The third loop loops over each interface entry for the Mac pc address in the table. Typically there would just be one user interface listed, but the item from Genie supports situations where there may be several.
- Next up is where in fact the list is known as by us of interface brands that we don’t desire to consider. They are the CPU, Supervisor, or Interswitch Links which were supplied as script inputs.
- As soon as we’ve gotten during that, the interfaces checklist for every MAC address inside our dictionary is updated to add these devices, interface, MAC kind, and VLAN ID where it had been found.
I believe that about addresses the fundamentals of the example. Based on your knowledge with Python, this script might seem simple overly, or possible very duper challenging. The Python subjects (loops, conditionals, features, etc) are straightforward. The complexity originates from automating the procedure and workflow that might be completed in a manual style. That’s why the most crucial section of any project such as this is getting started with a clear knowledge of the scope of the target, along with how you can do it manually.
What do you consider? Is this kind or sort of script ideal for you? What perhaps you have automated with pyATS? I understand I’ve noticed discussions from the grouped community about Twitter, LinkedIn, and Webex Groups from plenty of engineers finding it fun to resolve issues with Python and pyATS.