Network Mapping Tool for Cisco IOS devices

Yet another free, not so sophisticated program to plot the network map of cisco switches and routers that are interconnected in a local environment. The logic of the program is pretty simple. when user enters details of the first node (IP address, username, password), the program establishes SSH connection to first node and run cdp command to learn the neighbor nodes. from the command output, it filters out the node name and the IP addresses.

For testing purpose, I created a network using GNS3 and cisco L3 router images.

This Python script is a network mapping tool using the networkx library for representing and analyzing the structure of a network, matplotlib for visualization, and netmiko for network device communication. Let’s break down the code:

Libraries

import networkx as nx 
import matplotlib.pyplot as plt
import netmiko
import re
from getpass import getpass
from queue import Queue
import signal
signal.signal(signal.SIGFPE,signal.SIG_DFL)
signal.signal(signal.SIGINT,signal.SIG_DFL)
  • The script imports several libraries:
  • networkx: A Python package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks.
  • matplotlib.pyplot: A plotting library for creating static, animated, and interactive visualizations in Python.
  • netmiko: A multi-vendor library to simplify Paramiko SSH connections to network devices.
  • re: Regular expression operations for pattern matching.
  • getpass: Used to securely input a password (though not used in this script).
  • Queue: A basic FIFO queue for storing IP addresses during network traversal.
  • signal: Used for signal handling, specifically setting default behavior for certain signals.

Function Definitions

def add_node(name, device_name, ip_address):
    '''
    Passes input arguments into structured data for creating nodes 
    '''
    node_list.append((name, {"device_name": device_name, "IP": ip_address}))
    G.add_nodes_from(node_list)

def add_edge(nodeA, nodeB, link_type):
    '''
    Passes input arguments into structured data for creating node edges and links 
    '''
    edge_list.append((nodeA, nodeB, {"type": link_type}))
    edge_labels[(nodeA, nodeB)] = link_type
    G.add_edges_from(edge_list)
  • Two functions are defined:
  • add_node: Takes arguments (name, device_name, ip_address) and appends the node information to node_list, then adds nodes to the graph (G).
  • add_edge: Takes arguments (nodeA, nodeB, link_type) and appends the edge information to edge_list, adds edges to the graph (G), and updates edge labels.

Variable Declarations

G = nx.Graph()
node_list = []
edge_list = []
edge_labels = {}
nodpos_attr = {}
queue = Queue()
known_neighbors = {}
known_ip = [] 
device = {
        "ip" :"192.168.34.2",
        "device_type" : "cisco_ios",
        "username" : "cisco",
        "password" : "cisco"
        }  # For testing purposes, the values are given in the code as dictionary variables.
  • The script initializes several variables and data structures:
  • G: A networkx graph.
  • node_list, edge_list, and edge_labels: Lists to store node information, edge information, and edge labels.
  • nodpos_attr: Dictionary for storing node positions for visualization.
  • queue: A queue for storing IP addresses during network traversal.
  • known_neighbors: A dictionary to store information about known neighbors.
  • known_ip: A list to store known IP addresses.
  • device: A dictionary with connection details for a network device.

Main Code

queue.put(device["ip"])  # First IP address passed to queue
while not queue.empty():
    device["ip"] = queue.get()
    try:
        print(f'Connecting to device {device["ip"]}')
        connection = netmiko.ConnectHandler(**device)  # Establishing SSH connection
        node_name = connection.send_command('sh run | include host')
        cdp_output = connection.send_command('show cdp neighbors detail')
        add_node(node_name[9:], node_name[9:], device["ip"])  # Adding current node to the map
        neighbors = re.findall("Device ID: .+\n.*:.*\n.*:.*\n", str(cdp_output))
        for neighbor in neighbors:
            op_nbr = re.match("Device ID: (.*)\..*\..*\n.*\n.*: (.*)", str(neighbor))
            known_neighbors[op_nbr.group(1)] = op_nbr.group(2)
            if op_nbr.group(2) not in known_ip:
                known_ip.append(op_nbr.group(2))   
                queue.put(op_nbr.group(2))  # Adding IP addresses of neighbor nodes for the next iteration
                add_edge(node_name[9:], op_nbr.group(1), "copper")  # Adding neighbor nodes as edges to the map
        connection.disconnect()
    except (netmiko.exceptions.NetmikoAuthenticationException,
            netmiko.exceptions.NetmikoTimeoutException) as error:
        error_message = re.match(".*", str(error)).group(0)
        print(f'Cannot connect to {device["ip"]} due to {error_message}')
        print('============================================================') 
print("\nKnown neighbors are:")
for kn in known_neighbors:
    print(kn+' - '+known_neighbors[kn])
  • The main code performs the following steps:
  • Initializes the queue with the first IP address.
  • Iterates over the queue until it’s empty, connecting to devices and retrieving CDP neighbor information.
  • Adds nodes and edges to the graph based on the gathered information.
  • Prints known neighbors.

Code for Plotting the Network Map

nodpos = nx.spring_layout(G)
for n in G.nodes():
    nodpos_attr[n] = nodpos[n]+[0, -0.3]
edge_labels = nx.get_edge_attributes(G, 'type')
node_labels = nx.get_node_attributes(G, 'device_name')
nx.draw_networkx(G, pos=nodpos, with_labels=True, node_color="blue", node_size=1500, font_color="white", font_weight="bold")
nx.draw_networkx_edge_labels(G, pos=nodpos, edge_labels=edge_labels, label_pos=0.5, font_color='red')
nx.draw_networkx_labels(G, pos=nodpos_attr, labels=node_labels)
plt.show()
  • This part of the code uses matplotlib and networkx to visualize the network graph. It sets the positions of nodes, draws nodes, edges, and labels, and finally shows the plot.

Overall, the script connects to a network device, retrieves CDP neighbor information, and creates a network graph using networkx and visualizes it with matplotlib. The visualization helps in understanding the network topology and the relationships between different devices.

Following is the flowchart for the program

Here is the generated output

Leave a Reply

Your email address will not be published. Required fields are marked *