The best place for network developers

Access Point – automatic report

Generating automatic report about Access Points in our network infrastructure

Do you remember when last time local IT / your colleague / HelpDesk / anyone asked you for gathering a report about some devices which are connected in your network? Do you remember all the boring stuff that you had to do? Login into 5, 10, 15… 50 devices and gathering information like IP, port number, description, device name, mac address?

For sure, we know that there are monitoring tools / systems that gather most of these logs and generate reports. Still, there is a lot of cases that are very customized and logs/reports have to be collected manually because e.g. for some reason monitoring tool does not collect each part which is really needed. Or sometimes creating a report in such tool is much more complex than… python script.

And yes, here is the answer! We can use a python code which is:

  • Flexible
  • Customized
  • Fast
  • Can do all the stuff like logging on network devices and collects all information for us.

Imagine a beautiful Monday when your manager ask for creating a report about how many Access Points are connected to which switch, what is each AP’s mac address, platform and IP address…

Let us write a python code which will do this task for us!

Firstly, have a look at our lab topology:

As we can see, we have 3 switches, their IP addresses are,, To these switches there are connected 6 Access Points. As a result, we expect csv file with 6 lines (excluding “head” line) with detailed information about each AP like Switch ID, port number, AP’s name, IP, MAC address and AP’s model name.

In our script we are going to use the following libraries:

  • netmiko – library which will be used to connect to our network device
  • time – will be used to modify our report name
  • csv – report will be generated as csv file
  • re – regex library to gather requested data from devices
  1. current_date = time.strftime("%Y_%m_%d")
  2. outputFile = open('ap_report_' + current_date + '.csv', 'a', newline='')
  3. outputWriter = csv.writer(outputFile)
  4. outputWriter.writerow(["switch IP", "neighbor IP", "neighbor platform", "neighbor capabilities", "neighbor outgoing port number", "neighbor mac address"])

We begin our script with defining output file name (we are going to generate the report as a csv file).

Line 1 defines current date in format: year (%Y) month (%m) and day (%d). As a result, we will receive report name as e.g. “ap_report_2019_09_19.csv”.

In line 4 we defined a head – first row – in our csv file report.

  1. ips = ['', '', '', '']
  2. for ip in ips:
  3. cisco_switch = {
  4. 'device_type': 'cisco_ios',
  5. 'ip': ip,
  6. 'username': 'cisco',
  7. 'password': 'cisco',
  8. 'port': 22,
  9. 'secret': 'cisco'
  10. }
  11. net_connect = ConnectHandler(**cisco_switch)
  12. time.sleep(1)

Next thing is defining devices (switches) that we are going to connect to and gather logs. In Line 1 we define list of IPs in which. With second line (for loop) we will connect to device by device.

Then, we are defining our devices information like passwords, enable passwords, ports etc. The only variable here is ip, that will be fulfilled one by one with each iteration of for loop.

  1. get_cdp_output = net_connect.send_command('show cdp neigh')
  2. time.sleep(1)
  3. device_and_interface_regex = re.compile(r'(AP-\d)\s+(Gig \d/\d|Fas \d/\d) ')
  4. device_and_interface_found = device_and_interface_regex.findall(get_cdp_output)
  5. time.sleep(2)

As we did already a connection to our device (line 11 in previous section), we can send first command (line 1) to our device: show cdp neighbor. Then, in lines 3-4, we do a regex to find in CDP output Access Points’ names which are connected to FastEthernet ports on our switch. Via regex.findall method (line 4) we look for all matches that will be found in our output.

Why do we use regex as “(AP-\d)\s+(Gig \d/\d| Fas \d/\d)”? Have a look on CDP output from SW-1:

Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge
                  S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone, 
                  D - Remote, C - CVTA, M - Two-port Mac Relay 
Device ID        Local Interface     Holdtime    Capability  Platform  Port ID
AP-4          Fas 0/1           177              R B   AIR-CAP2702I-E-K9 GigabitEthernet0
AP-5          Fas 0/2           121              R B   AIR-CAP2702I-E-K9 GigabitEthernet0
AP-6          Fas 0/3           172              R B   AIR-CAP2702I-E-K9 GigabitEthernet0

We would like to find all access points, we also have a rule in our company that all AP names begins from AP- so this is why we look for this string in regex. Then we know that all our interfaces on switches are Gigabit or FastEthernet ports this is why we use syntax “Gig|Fas” in regex form.

If you are going to use regex, I can recommend using, you can easily verify here your regex query. As you also can see in the match information – we can distinguish groups of our matches (this is done with “()” in a regex query). This is very useful when you are looking for multiple data. Then, you can make only one query and collect all data that you need.

Let we have a look on what our script found, we can do that with printing output (print (device_and_interface_found)):

[(‘AP-4’, ‘Fas 0/1’), (‘AP-5’, ‘Fas 0/2’), (‘AP-6’, ‘Fas 0/3’)]

As you can see, we received a list of tuples, where each tuple contains of device name and interface name to which this device is connected to.

  1. for i in range(0, len(device_and_interface_found)):
  2. get_cdp_det_output = net_connect.send_command('show cdp neighbors ' +
  3. str(device_and_interface_found[i][1])+ ' det')

Next, as we can see in line 1, we create another for loop, now we will make as many iterations as many devices we found in previous section.

In lines 2-3 we are sending next command to our device, we collected information in one of previous sections about to which Gigabit / FastEthernet port access points are connected to. Here we provide this information to gather more detailed information about our neighbor on each interface.

SW-1 #sh cdp neighbors Fas0/1 det
Device ID: AP-4
Entry address(es):
  IP address:
Platform: cisco AIR-CAP2702I-E-K9,  Capabilities: Trans-Bridge Source-Route-Bridge IGMP
Interface: FastEthernet 0/1,  Port ID (outgoing port): GigabitEthernet0
Holdtime : 162 sec
Version :
Cisco IOS Software, C2700 Software (AP3G2-K9W8-M), Version 15.3(3)JD16, RELEASE SOFTWARE (fc1)
Technical Support:
Copyright (c) 1986-2018 by Cisco Systems, Inc.
Compiled Tue 05-Jun-18 02:41 by prod_rel_team
advertisement version: 2
Duplex: full
Power drawn: 16.800 Watts
Power request id: 28845, Power management id: 4
Power request levels are:16800 15400 13000 0 0
Power Available TLV:
    Power request id: 0, Power management id: 0, Power available: 0, Power management level: 0
Management address(es):
  IP address:
  1. ip_regex = re.compile(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b')
  2. device_regex = re.compile(r'Device ID: (\S+)')
  3. platform_regex = re.compile(r'Platform: (\S+ \S+)')
  4. outgoing_port_regex = re.compile(r'\(outgoing port\): (\S+)')
  6. ip_found = ip_regex.findall(get_cdp_det_output)
  7. device_found = device_regex.findall(get_cdp_det_output)
  8. platform_found = platform_regex.findall(get_cdp_det_output)
  9. outgoing_found = outgoing_port_regex.findall(get_cdp_det_output)

Now we can see 3 regex definitions (lines 1-3). These regexes are quite easy… maybe except ip_regex. The syntax in line 1 looks for IP address in out output. In a separate article I am going to write more about looking for IP addresses with regex but here logic rule is quite trivial – we look for 1 to 3 ({1,3}) digits ((\d)) when each of them is separate by comma (\.\). As a result, we must find any IP address (e.g. – do we have 4 sections? Yes. Are they separated by commas? Yes. Is in every section from one to three digits? Yes. So yes! This is IP address!)

Last two regex forms are just looking for a string (Platform or outgoing port) and then look for a word which is after the string (\S+).

Lines 5-7 are finding our matches in the get_cdp_det_output output.

  1. get_arp_output = net_connect.send_command('show ip arp | i ' + str(ip_found[0]))
  3. mac_regex = re.compile(r'((?:[0-9a-f]{4}\.){2}[0-9a-f]{4})')
  4. mac_found = mac_regex.findall(get_arp_output)

The last information that we must gather is MAC address. The MAC address can be easily found in arp table. We already know which IP address we are looking for so we add “include” and this IP address as we can see above.

Then we do a regex searching. The regex logic for mac addresses is very complex. Also, please note that the syntax of presenting MAC address can be different on different devices. We are going to write a separate article about regexes and there you will find more information about looking for mac addresses on different platforms.

  1. outputWriter.writerow([ip, device_found[0], ip_found[0], platform_found[0], outgoing_found[0], mac_found[0]])

The command in line 1 adds a row in our csv file. The [0] in brackets is because when we use regex.findall method for regex, we always create a list of results. In our code we always look for the first result of regex search, so we added this “0”.

Finally, let we have a look on our results and let we check if our code runs ok:

As a result, let we go on our switch let we check our current configuration on these interfaces:

As we can see results presented in CSV report file are absolutely the same as in our lab topology so we without any doubts we can send this report to our manager*

*this process could also be automated… we could write a piece of code to automatically send the report when it is generated directly to our manager 😊

And as always, you can find full script on our GitHub:

Access Point – automatic report

Do you remember when last time local IT / your colleague / HelpDesk / anyone asked you for gathering a report about some devices which are connected in your network? Do you remember all the boring stuff that you had to do? Login into 5, 10, 15… 50 devices and gathering information like IP, port number, description, device name, mac address?

Building lab environment

Every time I have to automate specific kind of a job I write down and answer project specific questions, which help me to prepare algorithm and general idea, how a new solution will work.

Of course, this list can be easily extended during algorithm preparation. A good approach is to prepare small working solution and extend it, every time you need it, by adding new functionality. Building small peaces and extracting specific functions will help in troubleshooting, reduce downtime during writing a code and of course, give a better planning and estimation of time when whole project will be finished.

Automatic interface configuration

For all of us entering same commands / text into CLI becomes boring after some time. Do you remember your fascination when you created a VLAN 10, connected two switches together and they pinged each other? Yes, probably for most of us were very enthusiastic that time. But after some time copying same command, creating same VLANs can become a little bit boring. What can we do to make it faster, better and less prone to mistakes?