NAPALM Data Collection

Introduction

In this article we will learn about the functions and methods of NAPALM to collect data on routers and switches from multiple vendors. We will write multiple Python scripts to collect data from this network, which you can use to create reports or investigate a problem. This is a continuation of the article “Working with Huawei VRP” on and it is part of the adventure in which I want to show you how you can implement Network Programmability and Automation with Python and the NAPALM library.

The main content is in the following video. So start here so that you can understand some sections of the article.

NAPALM Python

It is in this section where we will begin to see and enjoy the benefits of using NAPALM for programmability and network automation in Cisco and Huawei devices. And it is here where I basically share the code of what was seen in the video.

NAPALM Python: Get Facts, Get Interfaces and Get MAC Address table

We are going to modify the script that we did in the video Working with Huawei VRP so that it prints information in a table such as the hostname, manufacturer, model, time they have in operation and the serial number, a table with the interfaces and another table with the MAC address table of the Huawei and Cisco devices. Here is the modified code:

import napalm
from tabulate import tabulate
def main():
    driver_ios = napalm.get_network_driver("ios")
    driver_iosxr = napalm.get_network_driver("iosxr")
    driver_vrp = napalm.get_network_driver("ce")
    device_list = [["ios-sw2","ios", "switch"],["iosxr-r1", "iosxr", "router"],
    ["ios-r3", "ios", "router"],["vrp-r2", "vrp", "router"],["vrp-sw1", "vrp", "switch"]]
    network_devices = []
    for device in device_list:
        if device[1] == "ios":
            network_devices.append(
                            driver_ios(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
        elif device[1] == "iosxr":
            network_devices.append(
                            driver_iosxr(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
        elif device[1] == "vrp":
            network_devices.append(
                            driver_vrp(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
    devices_table = [["hostname", "vendor", "model", "uptime", "serial_number"]]
    devices_table_int = [["hostname","interface","is_up", "is_enabled", "description", "speed", "mtu", "mac_address"]]
    devices_mac_table = [["hostname","mac", "interface", "vlan", "static"]]
    
    for device in network_devices:
        print("Connecting to {} ...".format(device.hostname))
        device.open()
        print("Getting device facts")
        device_facts = device.get_facts()
        devices_table.append([device_facts["hostname"],
                              device_facts["vendor"],
                              device_facts["model"],
                              device_facts["uptime"],
                              device_facts["serial_number"]
                              ])
        print("Getting device interfaces")
        device_interfaces = device.get_interfaces()
        for interface in device_interfaces:
            if device_interfaces[interface]['is_up']:    
                devices_table_int.append([device_facts["hostname"],
                                      interface,
                                      device_interfaces[interface]['is_up'],
                                      device_interfaces[interface]['is_enabled'],
                                      device_interfaces[interface]['description'],
                                      device_interfaces[interface]['speed'],
                                      device_interfaces[interface]['mtu'],
                                      device_interfaces[interface]['mac_address']
        ])
    
        if "SW" in device_facts["hostname"]:
            print("Getting Mac Address Table from Switch")
            device_mac_info = device.get_mac_address_table()
            for mac_entry in device_mac_info:
                devices_mac_table.append([device_facts["hostname"],
                                          mac_entry["mac"],
                                          mac_entry["interface"],
                                          mac_entry["vlan"],
                                          mac_entry["static"],                
                ])
        device.close()
        print("Done.")
    print(tabulate(devices_table, headers="firstrow"))
    print()
    print(tabulate(devices_table_int, headers="firstrow"))
    print()
    print(tabulate(devices_mac_table, headers="firstrow"))
    print()
if __name__ == '__main__':
    main()

In the video you will find the explanation of this code.

Let’s see the output of the Script:

Connecting to ios-sw2 ...
Getting device facts
Getting device interfaces
Getting Mac Address Table from Switch
Done.
Connecting to iosxr-r1 ...
Getting device facts
Getting device interfaces
Done.
Connecting to ios-r3 ...
Getting device facts
Getting device interfaces
Done.
Connecting to vrp-r2 ...
Getting device facts
Getting device interfaces
Done.
Connecting to vrp-sw1 ...
Getting device facts
Getting device interfaces
Getting Mac Address Table from Switch
Done.
hostname    vendor    model      uptime  serial_number
----------  --------  -------  --------  ---------------------
IOS-SW2     Cisco     IOSv         1380  9QEN7MU6YX0
IOSXR-R1    Cisco                  1394
IOS-R3      Cisco     IOSv         1380  95ZAVRE4Q305F6ET85347
VRP-R2      Huawei    NE40E        1320  []
VRP-SW1     Huawei    CE6800       1320  []

hostname    interface                  is_up    is_enabled    description                         speed  mtu    mac_address
----------  -------------------------  -------  ------------  --------------------------------  -------  -----  -----------------
IOS-SW2     GigabitEthernet0/0         True     True                                               1000  1500   50:00:00:0A:00:00
IOS-SW2     GigabitEthernet0/1         True     True          Connected to IOSXR-R1 L2-Trunk       1000  1500   50:00:00:0A:00:01
IOS-SW2     GigabitEthernet0/2         True     True                                               1000  1500   50:00:00:0A:00:02
IOS-SW2     GigabitEthernet0/3         True     True          to_PC_1                              1000  1500   50:00:00:0A:00:03
IOS-SW2     GigabitEthernet1/0         True     True                                               1000  1500   50:00:00:0A:00:04
IOS-SW2     GigabitEthernet1/1         True     True                                               1000  1500   50:00:00:0A:00:05
IOS-SW2     GigabitEthernet1/2         True     True                                               1000  1500   50:00:00:0A:00:06
IOS-SW2     GigabitEthernet1/3         True     True                                               1000  1500   50:00:00:0A:00:07
IOS-SW2     Vlan10                     True     True          Management 10.10.10.10/24            1000  1500   50:00:00:0A:80:0A
IOSXR-R1    GigabitEthernet0/0/0/0     True     True          to_IOS-R3 Gi0/2 External             1000  1514   50:00:00:09:00:01
IOSXR-R1    GigabitEthernet0/0/0/1     True     True          to_IOS-SW2 Gi0/1                     1000  1514   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/1.1   True     True          to_IOS-SW2 Gi0/1 Vlan 20             1000  1518   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/1.10  True     True          to_IOS-SW2 Gi0/1 Vlan 10             1000  1518   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/2     True     True          to_VRP-R2 Eth1/0/2 External          1000  1514   50:00:00:09:00:03
IOSXR-R1    Loopback0                  True     True          Management IP                           0  1500
IOSXR-R1    Null0                      True     True                                                  0  1500
IOS-R3      GigabitEthernet0/0         True     True          to_IOSXR-R1 Gi0/0/0/0 External       1000  1500   50:00:00:08:00:00
IOS-R3      GigabitEthernet0/1         True     True          to_VRP-R2 Eth1/0/1 External          1000  1500   50:00:00:08:00:01
IOS-R3      Loopback0                  True     True                                               8000  1514
IOS-R3      Loopback1                  True     True                                               8000  1514
IOS-R3      Loopback100                True     True          ***CISCO LOOPBACK 100****            8000  1514
VRP-R2      Ethernet1/0/0.30           True     True          to_VRP-SW1 GE 1/0/0 - VLAN 30          -1  1500   38:49:80:01:01:00
VRP-R2      Ethernet1/0/1              True     True          to_IOS-R3 Gi0/1 - External             -1  1500   38:49:80:01:01:01
VRP-R2      Ethernet1/0/2              True     True          to_IOSXR-R1 Gi0/0/0/2 - External       -1  1500   38:49:80:01:01:02
VRP-R2      LoopBack0                  True     True          to_VRP-SW2 GE 1/0/1 - VLAN 1           -1  1500
VRP-R2      LoopBack100                True     True          test                                   -1  1500
VRP-R2      LoopBack200                True     True          ***HUAWEI LOOPBACK 200****             -1  1500
VRP-R2      NULL0                      True     True                                                 -1  1500
VRP-SW1     GE1/0/0                    True     True          to_VRP-R2 Eth 1/0/0 - LAN              -1         70:7B:E8:CD:0D:7B
VRP-SW1     GE1/0/3                    True     True          to_PC1 - LAN                           -1         70:7B:E8:CD:0D:7B
VRP-SW1     NULL0                      True     True                                                 -1  1500
VRP-SW1     Vlanif30                   True     True                                                 -1  1500   70:7B:E8:CD:0D:7B

hostname    mac                interface      vlan  static
----------  -----------------  -----------  ------  --------
IOS-SW2     0A:00:27:00:00:19  Gi0/0             1  False
IOS-SW2     50:00:00:09:00:02  Gi0/1             1  False
IOS-SW2     00:50:00:00:0B:00  Gi0/3            10  False
IOS-SW2     50:00:00:09:00:02  Gi0/1            10  False
VRP-SW1     38:49:80:01:01:00  GE1/0/0          30  False

NAPALM Python: Get Interfaces IP

We are going to modify the code above to add other functionality. This functionality will allow you to print a table with information on the layer 3 interfaces of the routers, that is, the IP addresses and their network masks. In addition to this information, we are going to include some of the counters of these interfaces to display the Errors or Discards of packets.

import napalm
from tabulate import tabulate
def main():
    driver_ios = napalm.get_network_driver("ios")
    driver_iosxr = napalm.get_network_driver("iosxr")
    driver_vrp = napalm.get_network_driver("ce")
    device_list = [["ios-sw2","ios", "switch"],["iosxr-r1", "iosxr", "router"],
    ["ios-r3", "ios", "router"],["vrp-r2", "vrp", "router"],["vrp-sw1", "vrp", "switch"]]
    network_devices = []
    for device in device_list:
        if device[1] == "ios":
            network_devices.append(
                            driver_ios(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
        elif device[1] == "iosxr":
            network_devices.append(
                            driver_iosxr(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
        elif device[1] == "vrp":
            network_devices.append(
                            driver_vrp(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
    devices_table = [["hostname", "vendor", "model", "uptime", "serial_number"]]
    devices_table_int = [["hostname","interface","is_up", "is_enabled", "description", "speed", "mtu", "mac_address"]]
    devices_mac_table = [["hostname","mac", "interface", "vlan", "static"]]
    devices_int_ip_table = [["hostname","interface","is_up","ipv4/mask", "tx_errors","rx_errors","tx_discards","rx_discards"]]
    
    for device in network_devices:
        print("Connecting to {} ...".format(device.hostname))
        device.open()
        print("Getting device facts")
        device_facts = device.get_facts()
        devices_table.append([device_facts["hostname"],
                              device_facts["vendor"],
                              device_facts["model"],
                              device_facts["uptime"],
                              device_facts["serial_number"]
                              ])
        print("Getting device interfaces")
        device_interfaces = device.get_interfaces()
        for interface in device_interfaces:
            if device_interfaces[interface]['is_up']:    
                devices_table_int.append([device_facts["hostname"],
                                      interface,
                                      device_interfaces[interface]['is_up'],
                                      device_interfaces[interface]['is_enabled'],
                                      device_interfaces[interface]['description'],
                                      device_interfaces[interface]['speed'],
                                      device_interfaces[interface]['mtu'],
                                      device_interfaces[interface]['mac_address']
        ])
    
        if "SW" in device_facts["hostname"]:
            print("Getting Mac Address Table from Switch")
            device_mac_info = device.get_mac_address_table()
            for mac_entry in device_mac_info:
                devices_mac_table.append([device_facts["hostname"],
                                          mac_entry["mac"],
                                          mac_entry["interface"],
                                          mac_entry["vlan"],
                                          mac_entry["static"],                
                ])
        print("Getting physical interfaces ip and counters")
        device_interfaces_ip = device.get_interfaces_ip()
        device_interfaces_counters = device.get_interfaces_counters()
        for interface in device_interfaces_ip:
            if device_interfaces[interface]['is_up'] and interface in device_interfaces_counters:
                ip_address = list(device_interfaces_ip[interface]['ipv4'].keys())[0]
                devices_int_ip_table.append([device_facts["hostname"],
                                      interface,
                                      device_interfaces[interface]['is_up'],
                                      "{}/{}".format(ip_address,
                                                     device_interfaces_ip[interface]['ipv4'][ip_address]['prefix_length']),
                                      device_interfaces_counters[interface]['tx_errors'],
                                      device_interfaces_counters[interface]['rx_errors'],
                                      device_interfaces_counters[interface]['tx_discards'],
                                      device_interfaces_counters[interface]['rx_discards']
                ])
        device.close()
        print("Done.")
    print(tabulate(devices_table, headers="firstrow"))
    print()
    print(tabulate(devices_table_int, headers="firstrow"))
    print()
    print(tabulate(devices_mac_table, headers="firstrow"))
    print()
    print(tabulate(devices_int_ip_table, headers="firstrow"))
if __name__ == '__main__':
    main()

In the video you will find the explanation of this code.

Let’s see the output of the Script:

Connecting to ios-sw2 ...
Getting device facts
Getting device interfaces
Getting Mac Address Table from Switch
Getting physical interfaces ip and counters
Done.
Connecting to iosxr-r1 ...
Getting device facts
Getting device interfaces
Getting physical interfaces ip and counters
Done.
Connecting to ios-r3 ...
Getting device facts
Getting device interfaces
Getting physical interfaces ip and counters
Done.
Connecting to vrp-r2 ...
Getting device facts
Getting device interfaces
Getting physical interfaces ip and counters
Done.
Connecting to vrp-sw1 ...
Getting device facts
Getting device interfaces
Getting Mac Address Table from Switch
Getting physical interfaces ip and counters
Done.
hostname    vendor    model      uptime  serial_number
----------  --------  -------  --------  ---------------------
IOS-SW2     Cisco     IOSv         1440  9QEN7MU6YX0
IOSXR-R1    Cisco                  1478
IOS-R3      Cisco     IOSv         1440  95ZAVRE4Q305F6ET85347
VRP-R2      Huawei    NE40E        1380  []
VRP-SW1     Huawei    CE6800       1440  []

hostname    interface                  is_up    is_enabled    description                         speed  mtu    mac_address
----------  -------------------------  -------  ------------  --------------------------------  -------  -----  -----------------
IOS-SW2     GigabitEthernet0/0         True     True                                               1000  1500   50:00:00:0A:00:00
IOS-SW2     GigabitEthernet0/1         True     True          Connected to IOSXR-R1 L2-Trunk       1000  1500   50:00:00:0A:00:01
IOS-SW2     GigabitEthernet0/2         True     True                                               1000  1500   50:00:00:0A:00:02
IOS-SW2     GigabitEthernet0/3         True     True          to_PC_1                              1000  1500   50:00:00:0A:00:03
IOS-SW2     GigabitEthernet1/0         True     True                                               1000  1500   50:00:00:0A:00:04
IOS-SW2     GigabitEthernet1/1         True     True                                               1000  1500   50:00:00:0A:00:05
IOS-SW2     GigabitEthernet1/2         True     True                                               1000  1500   50:00:00:0A:00:06
IOS-SW2     GigabitEthernet1/3         True     True                                               1000  1500   50:00:00:0A:00:07
IOS-SW2     Vlan10                     True     True          Management 10.10.10.10/24            1000  1500   50:00:00:0A:80:0A
IOSXR-R1    GigabitEthernet0/0/0/0     True     True          to_IOS-R3 Gi0/2 External             1000  1514   50:00:00:09:00:01
IOSXR-R1    GigabitEthernet0/0/0/1     True     True          to_IOS-SW2 Gi0/1                     1000  1514   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/1.1   True     True          to_IOS-SW2 Gi0/1 Vlan 20             1000  1518   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/1.10  True     True          to_IOS-SW2 Gi0/1 Vlan 10             1000  1518   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/2     True     True          to_VRP-R2 Eth1/0/2 External          1000  1514   50:00:00:09:00:03
IOSXR-R1    Loopback0                  True     True          Management IP                           0  1500
IOSXR-R1    Null0                      True     True                                                  0  1500
IOS-R3      GigabitEthernet0/0         True     True          to_IOSXR-R1 Gi0/0/0/0 External       1000  1500   50:00:00:08:00:00
IOS-R3      GigabitEthernet0/1         True     True          to_VRP-R2 Eth1/0/1 External          1000  1500   50:00:00:08:00:01
IOS-R3      Loopback0                  True     True                                               8000  1514
IOS-R3      Loopback1                  True     True                                               8000  1514
IOS-R3      Loopback100                True     True          ***CISCO LOOPBACK 100****            8000  1514
VRP-R2      Ethernet1/0/0.30           True     True          to_VRP-SW1 GE 1/0/0 - VLAN 30          -1  1500   38:49:80:01:01:00
VRP-R2      Ethernet1/0/1              True     True          to_IOS-R3 Gi0/1 - External             -1  1500   38:49:80:01:01:01
VRP-R2      Ethernet1/0/2              True     True          to_IOSXR-R1 Gi0/0/0/2 - External       -1  1500   38:49:80:01:01:02
VRP-R2      LoopBack0                  True     True          to_VRP-SW2 GE 1/0/1 - VLAN 1           -1  1500
VRP-R2      LoopBack100                True     True          test                                   -1  1500
VRP-R2      LoopBack200                True     True          ***HUAWEI LOOPBACK 200****             -1  1500
VRP-R2      NULL0                      True     True                                                 -1  1500
VRP-SW1     GE1/0/0                    True     True          to_VRP-R2 Eth 1/0/0 - LAN              -1         70:7B:E8:CD:0D:7B
VRP-SW1     GE1/0/3                    True     True          to_PC1 - LAN                           -1         70:7B:E8:CD:0D:7B
VRP-SW1     NULL0                      True     True                                                 -1  1500
VRP-SW1     Vlanif30                   True     True                                                 -1  1500   70:7B:E8:CD:0D:7B

hostname    mac                interface      vlan  static
----------  -----------------  -----------  ------  --------
IOS-SW2     0A:00:27:00:00:19  Gi0/0             1  False
IOS-SW2     50:00:00:09:00:02  Gi0/1             1  False
IOS-SW2     00:50:00:00:0B:00  Gi0/3            10  False
IOS-SW2     50:00:00:09:00:02  Gi0/1            10  False
VRP-SW1     38:49:80:01:01:00  GE1/0/0          30  False

hostname    interface                  is_up    ipv4/mask            tx_errors    rx_errors    tx_discards    rx_discards
----------  -------------------------  -------  -----------------  -----------  -----------  -------------  -------------
IOS-SW2     Vlan10                     True     10.10.10.10/24               0            0              0              0
IOSXR-R1    GigabitEthernet0/0/0/0     True     172.17.2.1/30                0            0              0              0
IOSXR-R1    GigabitEthernet0/0/0/1.1   True     192.168.56.101/24            0            0              0            480
IOSXR-R1    GigabitEthernet0/0/0/1.10  True     10.10.10.1/24                0            0              0              0
IOSXR-R1    GigabitEthernet0/0/0/2     True     172.17.1.1/30                0            0              0              0
IOS-R3      GigabitEthernet0/0         True     172.17.2.2/30                0            0              0              0
IOS-R3      GigabitEthernet0/1         True     172.17.3.1/30                0            0              0              0
IOS-R3      Loopback0                  True     192.168.21.103/32            0            0              0              0
IOS-R3      Loopback1                  True     10.20.20.1/24                0            0              0              0
IOS-R3      Loopback100                True     4.4.4.100/32                 0            0              0              0
VRP-R2      Ethernet1/0/0.30           True     10.30.30.1/24                0            0              0              0
VRP-R2      Ethernet1/0/1              True     172.17.3.2/30                0            0              0              0
VRP-R2      Ethernet1/0/2              True     172.17.1.2/30                0            0              0              0
VRP-R2      LoopBack0                  True     192.168.21.202/32            0            0              0              0
VRP-R2      LoopBack200                True     4.4.4.200/32                 0            0              0              0
VRP-SW1     Vlanif30                   True     10.30.30.31/24               0            0              0              0

NAPALM Python: BGP Neighbors

Here we have our get bgp neighbors method that was developed to be able to have a function just like in Cisco that allows me to get the bgp neighbors, the remote autonomous system, the prefixes sent and the prefixes received.

    def get_bgp_neighbors(self):
        """
        {
            "global": {
                "router_id": "192.168.21.102",
                "peers": {
                    "172.17.1.1": {
                        "local_as": 200,
                        "remote_as": 100,
                        "remote_id": "192.168.21.101",
                        "is_up": true,
                        "is_enabled": true,
                        "description": "",
                        "uptime": 142,
                        "address_family": {
                            "ipv4 unicast": {
                                "received_prefixes": 5,
                                "accepted_prefixes": 5,
                                "sent_prefixes": 2
                            }
                        }
                    }
                }
            }
        }
        """
        afi_supported = {
            "Ipv6 Unicast" : "ipv6 unicast",
            "Ipv4 Unicast" : "ipv4 unicast",
            "Vpnv4 All" : "vpnv4 unicast",
            "Vpnv6 All" : "vpnv6 unicast"
        }
        bgp_neighbors = {}
        command_bgp = "display bgp all summary"
        output = self.device.send_command(command_bgp)
        if output == "":
            return bgp_neighbors
        #Regular Expressions
        re_separator = r"\n\s*(?=Address Family:\s*\w+)"
        re_vpn_instance_separator = r"\n\s*(?=VPN-Instance\s+[-_a-zA-Z0-9]+)"
        re_address_family = r"Address Family:(?P<address_family>\w+\s\w+)"
        re_global_router_id = r"BGP local router ID :\s+(?P<glob_router_id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
        re_global_local_as = r"Local AS number :\s+(?P<local_as>{})".format(ASN_REGEX)
        re_vrf_router_id = r"VPN-Instance\s+(?P<vrf>[-_a-zA-Z0-9]+), [rR]outer ID\s+" \
                              r"(?P<vrf_router_id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
        re_peers = r"(?P<peer_ip>({})|({}))\s+" \
                   r"(?P<as>{})\s+\d+\s+\d+\s+\d+\s+(?P<updown_time>[a-zA-Z0-9:]+)\s+" \
                   r"(?P<state>[a-zA-Z0-9\(\)]+)\s+(?P<received_prefixes>\d+)\s+(?P<adv_prefixes>\d+)".format(
                            IPV4_ADDR_REGEX, IPV6_ADDR_REGEX, ASN_REGEX)
        re_remote_rid = r"Remote router ID\s+(?P<remote_rid>{})".format(IPV4_ADDR_REGEX)
        re_peer_description = r"Peer's description:\s+\"(?P<peer_description>.*)\""
        #Separation of AFIs
        afi_list = re.split(re_separator, output, flags=re.M)
        #return afi_list
        bgp_global_router_id = ""
        bgp_global_local_as = ""
        for afi in afi_list:
            match_afi = re.search(re_global_router_id,afi, flags=re.M)
            match_local_as = re.search(re_global_local_as,afi, flags=re.M)
            if match_afi is not None:
                bgp_global_router_id = match_afi.group('glob_router_id')
                bgp_global_local_as = match_local_as.group('local_as')
            
            match_afi = re.search(re_address_family, afi, flags=re.M)
            if match_afi is not None and any((s in match_afi.group('address_family') for s in ['Ipv4 Unicast','Ipv6 Unicast'])):
                bgp_neighbors.update({"global": {"router_id": bgp_global_router_id, "peers" : {}}})
                for peer in afi.splitlines():
                    match_peer = re.search(re_peers, peer, flags=re.M)
                    
                    if match_peer:
                        peer_bgp_command = ""
                        if "Ipv6" in match_afi.group('address_family'):
                            peer_bgp_command = "display bgp ipv6 peer {} verbose".format(match_peer.group('peer_ip'))
                        else:
                            peer_bgp_command = "display bgp peer {} verbose".format(match_peer.group('peer_ip'))
                        
                        peer_detail = self.device.send_command(peer_bgp_command)
                        match_remote_rid = re.search(re_remote_rid, peer_detail, flags=re.M)
                        match_peer_description = re.search(re_peer_description, peer_detail, flags=re.M)
                      
                        bgp_neighbors["global"]["peers"].update( { 
                        match_peer.group('peer_ip'): { 
                        "local_as": int(bgp_global_local_as), 
                        "remote_as": int(match_peer.group('as')), 
                        "remote_id": "" if match_remote_rid is None else match_remote_rid.group('remote_rid'), 
                        "is_up": True if "Established" in match_peer.group('state') else False, 
                        "is_enabled": False if "Admin" in match_peer.group('state') else True, 
                        "description": "" if match_peer_description is None else match_peer_description.group('peer_description'), 
                        "uptime": int(self.bgp_time_conversion(match_peer.group('updown_time'))), 
                        "address_family": { 
                            afi_supported[match_afi.group('address_family')]: { 
                                "received_prefixes": int(match_peer.group('received_prefixes')), 
                                "accepted_prefixes": "Unknown", 
                                "sent_prefixes": int(match_peer.group('adv_prefixes')) 
                                           }
                                        }
                               }
                            })
            
            elif match_afi is not None and any((s in match_afi.group('address_family') for s in ['Vpnv4 All','Vpnv6 All'])):
                if bgp_neighbors['global'] is False:
                    bgp_neighbors.update({"global": {"router_id": bgp_global_router_id, "peers" : {}}})
                #Separation of VPNs
                vpn_instance_list = re.split(re_vpn_instance_separator, afi, flags=re.M)
                
                for vpn_peers in vpn_instance_list:
                    if "VPN-Instance " not in vpn_peers:
                        for peer in vpn_peers.splitlines():
                            match_peer = re.search(re_peers, peer, flags=re.M)
                            if match_peer:
                                if bgp_neighbors["global"]["peers"][match_peer.group('peer_ip')]:
                                   bgp_neighbors["global"]["peers"][match_peer.group('peer_ip')]["address_family"].update(
                                   { 
                                    afi_supported[match_afi.group('address_family')]: { 
                                        "received_prefixes": int(match_peer.group('received_prefixes')), 
                                        "accepted_prefixes": "Unknown", 
                                        "sent_prefixes": int(match_peer.group('adv_prefixes')) 
                                                   }
                                                }
                                   ) 
                                else:
                                    peer_bgp_command = ""
                                    if "Ipv6" in match_afi.group('address_family'):
                                        peer_bgp_command = "display bgp ipv6 peer {} verbose".format(match_peer.group('peer_ip'))
                                    else:
                                        peer_bgp_command = "display bgp peer {} verbose".format(match_peer.group('peer_ip'))            
                                    peer_detail = self.device.send_command(peer_bgp_command)
                                    match_remote_rid = re.search(re_remote_rid, peer_detail, flags=re.M)
                                    match_peer_description = re.search(re_peer_description, peer_detail, flags=re.M)
                                    
                                    bgp_neighbors["global"]["peers"].update( { 
                                    match_peer.group('peer_ip'): { 
                                    "local_as": int(bgp_global_local_as), 
                                    "remote_as": int(match_peer.group('as')), 
                                    "remote_id": "" if match_remote_rid is None else match_remote_rid.group('remote_rid'), 
                                    "is_up": True if "Established" in match_peer.group('state') else False, 
                                    "is_enabled": False if "Admin" in match_peer.group('state') else True, 
                                    "description": "" if match_peer_description is None else match_peer_description.group('peer_description'), 
                                    "uptime": int(self.bgp_time_conversion(match_peer.group('updown_time'))), 
                                    "address_family": { 
                                       afi_supported[match_afi.group('address_family')]: { 
                                            "received_prefixes": int(match_peer.group('received_prefixes')), 
                                            "accepted_prefixes": "Unknown", 
                                            "sent_prefixes": int(match_peer.group('adv_prefixes')) 
                                                       }
                                                    }
                                           }
                                        })
                    else:
                        match_vrf_router_id = re.search(re_vrf_router_id, vpn_peers, flags=re.M)
                        if match_vrf_router_id is None:
                            msg = "No Match Found"
                            raise ValueError(msg)
                        peer_vpn_instance = match_vrf_router_id.group('vrf')
                        peer_router_id = match_vrf_router_id.group('vrf_router_id')
                        bgp_neighbors.update({peer_vpn_instance: {
                                        "router_id": peer_router_id, "peers" : {}}})
                        for peer in vpn_peers.splitlines():
                                    
                            match_peer = re.search(re_peers, peer, flags=re.M)
                            if match_peer:
                                peer_bgp_command = ""
                                afi_vrf = ""
                                if "Ipv6" in match_afi.group('address_family'):
                                    peer_bgp_command = "display bgp ipv6 peer {} verbose".format(match_peer.group('peer_ip'))
                                    afi_vrf = "ipv6 unicast"
                                else:
                                    peer_bgp_command = "display bgp peer {} verbose".format(match_peer.group('peer_ip'))
                                    afi_vrf = "ipv4 unicast"
                                
                                peer_detail = self.device.send_command(peer_bgp_command)
                                match_remote_rid = re.search(re_remote_rid, peer_detail, flags=re.M)
                                match_peer_description = re.search(re_peer_description, peer_detail, flags=re.M)
                                bgp_neighbors[peer_vpn_instance]["peers"].update( { 
                                match_peer.group('peer_ip'): { 
                                "local_as": int(bgp_global_local_as), 
                                "remote_as": int(match_peer.group('as')), 
                                "remote_id": "" if match_remote_rid is None else match_remote_rid.group('remote_rid'), 
                                "is_up": True if "Established" in match_peer.group('state') else False, 
                                "is_enabled": False if "Admin" in match_peer.group('state') else True, 
                                "description": "" if match_peer_description is None else match_peer_description.group('peer_description'), 
                                "uptime": int(self.bgp_time_conversion(match_peer.group('updown_time'))),         
                                "address_family": { 
                                    afi_vrf: { 
                                        "received_prefixes": int(match_peer.group('received_prefixes')), 
                                        "accepted_prefixes": "Unknown", 
                                        "sent_prefixes": int(match_peer.group('adv_prefixes')) 
                                                   }
                                                }
                                       }
                                    })
        return bgp_neighbors

Here is the code that we have been working on including the development we had done previously to print the BGP neighbors table.

import napalm
from tabulate import tabulate
def main():
    driver_ios = napalm.get_network_driver("ios")
    driver_iosxr = napalm.get_network_driver("iosxr")
    driver_vrp = napalm.get_network_driver("ce")
    device_list = [["ios-sw2","ios", "switch"],["iosxr-r1", "iosxr", "router"],
    ["ios-r3", "ios", "router"],["vrp-r2", "vrp", "router"],["vrp-sw1", "vrp", "switch"]]
    network_devices = []
    for device in device_list:
        if device[1] == "ios":
            network_devices.append(
                            driver_ios(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
        elif device[1] == "iosxr":
            network_devices.append(
                            driver_iosxr(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
        elif device[1] == "vrp":
            network_devices.append(
                            driver_vrp(
                            hostname = device[0],
                            username = "codingnetworks",
                            password = "Coding.Networks1"
                            )
                              )
    devices_table = [["hostname", "vendor", "model", "uptime", "serial_number"]]
    devices_table_int = [["hostname","interface","is_up", "is_enabled", "description", "speed", "mtu", "mac_address"]]
    devices_mac_table = [["hostname","mac", "interface", "vlan", "static"]]
    devices_int_ip_table = [["hostname","interface","is_up","ipv4/mask", "tx_errors","rx_errors","tx_discards","rx_discards"]]
    devices_table_bgp = [["hostname", "neighbor", "remote-as", "status", "sent prefixes", "received prefixes"]]
    for device in network_devices:
        print("Connecting to {} ...".format(device.hostname))
        device.open()
        print("Getting device facts")
        device_facts = device.get_facts()
        devices_table.append([device_facts["hostname"],
                              device_facts["vendor"],
                              device_facts["model"],
                              device_facts["uptime"],
                              device_facts["serial_number"]
                              ])
        print("Getting device interfaces")
        device_interfaces = device.get_interfaces()
        for interface in device_interfaces:
            if device_interfaces[interface]['is_up']:    
                devices_table_int.append([device_facts["hostname"],
                                      interface,
                                      device_interfaces[interface]['is_up'],
                                      device_interfaces[interface]['is_enabled'],
                                      device_interfaces[interface]['description'],
                                      device_interfaces[interface]['speed'],
                                      device_interfaces[interface]['mtu'],
                                      device_interfaces[interface]['mac_address']
        ])
    
        if "SW" in device_facts["hostname"]:
            print("Getting Mac Address Table from Switch")
            device_mac_info = device.get_mac_address_table()
            for mac_entry in device_mac_info:
                devices_mac_table.append([device_facts["hostname"],
                                          mac_entry["mac"],
                                          mac_entry["interface"],
                                          mac_entry["vlan"],
                                          mac_entry["static"],                
                ])
        print("Getting physical interfaces ip and counters")
        device_interfaces_ip = device.get_interfaces_ip()
        device_interfaces_counters = device.get_interfaces_counters()
        for interface in device_interfaces_ip:
            if device_interfaces[interface]['is_up'] and interface in device_interfaces_counters:
                ip_address = list(device_interfaces_ip[interface]['ipv4'].keys())[0]
                devices_int_ip_table.append([device_facts["hostname"],
                                      interface,
                                      device_interfaces[interface]['is_up'],
                                      "{}/{}".format(ip_address,
                                                     device_interfaces_ip[interface]['ipv4'][ip_address]['prefix_length']),
                                      device_interfaces_counters[interface]['tx_errors'],
                                      device_interfaces_counters[interface]['rx_errors'],
                                      device_interfaces_counters[interface]['tx_discards'],
                                      device_interfaces_counters[interface]['rx_discards']
                ])
        if not "SW" in device_facts["hostname"]:
            print("Getting device BGP Neighbors")
            device_bgp_peers = device.get_bgp_neighbors()
            address_fam = "ipv4 unicast"
            if "IOSXR" in device_facts["hostname"]:
                address_fam = "ipv4"
            for bgp_neighbor in device_bgp_peers['global']['peers']:
                devices_table_bgp.append([device_facts["hostname"],
                                          bgp_neighbor,
                                          device_bgp_peers['global']['peers'][bgp_neighbor]['remote_as'],
                                          device_bgp_peers['global']['peers'][bgp_neighbor]['is_up'],
                                          device_bgp_peers['global']['peers'][bgp_neighbor]['address_family'][address_fam]['sent_prefixes'],
                                          device_bgp_peers['global']['peers'][bgp_neighbor]['address_family'][address_fam]['received_prefixes']
                                     ])
        device.close()
        print("Done.")
    print(tabulate(devices_table, headers="firstrow"))
    print()
    print(tabulate(devices_table_int, headers="firstrow"))
    print()
    print(tabulate(devices_mac_table, headers="firstrow"))
    print()
    print(tabulate(devices_int_ip_table, headers="firstrow"))
    print()
    print(tabulate(devices_table_bgp, headers="firstrow"))
if __name__ == '__main__':
    main()

Let’s see the output of the Script:

Connecting to ios-sw2 ...
Getting device facts
Getting device interfaces
Getting Mac Address Table from Switch
Getting physical interfaces ip and counters
Done.
Connecting to iosxr-r1 ...
Getting device facts
Getting device interfaces
Getting physical interfaces ip and counters
Getting device BGP Neighbors
Done.
Connecting to ios-r3 ...
Getting device facts
Getting device interfaces
Getting physical interfaces ip and counters
Getting device BGP Neighbors
Done.
Connecting to vrp-r2 ...
Getting device facts
Getting device interfaces
Getting physical interfaces ip and counters
Getting device BGP Neighbors
Done.
Connecting to vrp-sw1 ...
Getting device facts
Getting device interfaces
Getting Mac Address Table from Switch
Getting physical interfaces ip and counters
Done.
hostname    vendor    model      uptime  serial_number
----------  --------  -------  --------  ---------------------
IOS-SW2     Cisco     IOSv         1620  9QEN7MU6YX0
IOSXR-R1    Cisco                  1678
IOS-R3      Cisco     IOSv         1680  95ZAVRE4Q305F6ET85347
VRP-R2      Huawei    NE40E        1620  []
VRP-SW1     Huawei    CE6800       1620  []

hostname    interface                  is_up    is_enabled    description                         speed  mtu    mac_address
----------  -------------------------  -------  ------------  --------------------------------  -------  -----  -----------------
IOS-SW2     GigabitEthernet0/0         True     True                                               1000  1500   50:00:00:0A:00:00
IOS-SW2     GigabitEthernet0/1         True     True          Connected to IOSXR-R1 L2-Trunk       1000  1500   50:00:00:0A:00:01
IOS-SW2     GigabitEthernet0/2         True     True                                               1000  1500   50:00:00:0A:00:02
IOS-SW2     GigabitEthernet0/3         True     True          to_PC_1                              1000  1500   50:00:00:0A:00:03
IOS-SW2     GigabitEthernet1/0         True     True                                               1000  1500   50:00:00:0A:00:04
IOS-SW2     GigabitEthernet1/1         True     True                                               1000  1500   50:00:00:0A:00:05
IOS-SW2     GigabitEthernet1/2         True     True                                               1000  1500   50:00:00:0A:00:06
IOS-SW2     GigabitEthernet1/3         True     True                                               1000  1500   50:00:00:0A:00:07
IOS-SW2     Vlan10                     True     True          Management 10.10.10.10/24            1000  1500   50:00:00:0A:80:0A
IOSXR-R1    GigabitEthernet0/0/0/0     True     True          to_IOS-R3 Gi0/2 External             1000  1514   50:00:00:09:00:01
IOSXR-R1    GigabitEthernet0/0/0/1     True     True          to_IOS-SW2 Gi0/1                     1000  1514   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/1.1   True     True          to_IOS-SW2 Gi0/1 Vlan 20             1000  1518   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/1.10  True     True          to_IOS-SW2 Gi0/1 Vlan 10             1000  1518   50:00:00:09:00:02
IOSXR-R1    GigabitEthernet0/0/0/2     True     True          to_VRP-R2 Eth1/0/2 External          1000  1514   50:00:00:09:00:03
IOSXR-R1    Loopback0                  True     True          Management IP                           0  1500
IOSXR-R1    Null0                      True     True                                                  0  1500
IOS-R3      GigabitEthernet0/0         True     True          to_IOSXR-R1 Gi0/0/0/0 External       1000  1500   50:00:00:08:00:00
IOS-R3      GigabitEthernet0/1         True     True          to_VRP-R2 Eth1/0/1 External          1000  1500   50:00:00:08:00:01
IOS-R3      Loopback0                  True     True                                               8000  1514
IOS-R3      Loopback1                  True     True                                               8000  1514
IOS-R3      Loopback100                True     True          ***CISCO LOOPBACK 100****            8000  1514
VRP-R2      Ethernet1/0/0.30           True     True          to_VRP-SW1 GE 1/0/0 - VLAN 30          -1  1500   38:49:80:01:01:00
VRP-R2      Ethernet1/0/1              True     True          to_IOS-R3 Gi0/1 - External             -1  1500   38:49:80:01:01:01
VRP-R2      Ethernet1/0/2              True     True          to_IOSXR-R1 Gi0/0/0/2 - External       -1  1500   38:49:80:01:01:02
VRP-R2      LoopBack0                  True     True          to_VRP-SW2 GE 1/0/1 - VLAN 1           -1  1500
VRP-R2      LoopBack100                True     True          test                                   -1  1500
VRP-R2      LoopBack200                True     True          ***HUAWEI LOOPBACK 200****             -1  1500
VRP-R2      NULL0                      True     True                                                 -1  1500
VRP-SW1     GE1/0/0                    True     True          to_VRP-R2 Eth 1/0/0 - LAN              -1         70:7B:E8:CD:0D:7B
VRP-SW1     GE1/0/3                    True     True          to_PC1 - LAN                           -1         70:7B:E8:CD:0D:7B
VRP-SW1     NULL0                      True     True                                                 -1  1500
VRP-SW1     Vlanif30                   True     True                                                 -1  1500   70:7B:E8:CD:0D:7B

hostname    mac                interface      vlan  static
----------  -----------------  -----------  ------  --------
IOS-SW2     0A:00:27:00:00:19  Gi0/0             1  False
IOS-SW2     50:00:00:09:00:02  Gi0/1             1  False
IOS-SW2     00:50:00:00:0B:00  Gi0/3            10  False
IOS-SW2     50:00:00:09:00:02  Gi0/1            10  False
VRP-SW1     38:49:80:01:01:00  GE1/0/0          30  False

hostname    interface                  is_up    ipv4/mask            tx_errors    rx_errors    tx_discards    rx_discards
----------  -------------------------  -------  -----------------  -----------  -----------  -------------  -------------
IOS-SW2     Vlan10                     True     10.10.10.10/24               0            0              0              0
IOSXR-R1    GigabitEthernet0/0/0/0     True     172.17.2.1/30                0            0              0              0
IOSXR-R1    GigabitEthernet0/0/0/1.1   True     192.168.56.101/24            0            0              0            552
IOSXR-R1    GigabitEthernet0/0/0/1.10  True     10.10.10.1/24                0            0              0              0
IOSXR-R1    GigabitEthernet0/0/0/2     True     172.17.1.1/30                0            0              0              0
IOS-R3      GigabitEthernet0/0         True     172.17.2.2/30                0            0              0              0
IOS-R3      GigabitEthernet0/1         True     172.17.3.1/30                0            0              0              0
IOS-R3      Loopback0                  True     192.168.21.103/32            0            0              0              0
IOS-R3      Loopback1                  True     10.20.20.1/24                0            0              0              0
IOS-R3      Loopback100                True     4.4.4.100/32                 0            0              0              0
VRP-R2      Ethernet1/0/0.30           True     10.30.30.1/24                0            0              0              0
VRP-R2      Ethernet1/0/1              True     172.17.3.2/30                0            0              0              0
VRP-R2      Ethernet1/0/2              True     172.17.1.2/30                0            0              0              0
VRP-R2      LoopBack0                  True     192.168.21.202/32            0            0              0              0
VRP-R2      LoopBack200                True     4.4.4.200/32                 0            0              0              0
VRP-SW1     Vlanif30                   True     10.30.30.31/24               0            0              0              0

hostname    neighbor      remote-as  status      sent prefixes    received prefixes
----------  ----------  -----------  --------  ---------------  -------------------
IOSXR-R1    172.17.1.2          200  True                    7                    4
IOSXR-R1    172.17.2.2          300  True                    7                    4
IOS-R3      172.17.2.1          100  True                    7                    5
IOS-R3      172.17.3.2          200  True                    7                    5
VRP-R2      172.17.1.1          100  True                    7                    5
VRP-R2      172.17.3.1          300  True                    7                    5

Conclusion

Again I am surprised when I see that in 135 lines of code, I have a script that connects my multi-vendor network and in 1 minute it gives me a summary of:

  • Data of the interfaces.
  • Data from the Mac Address table of the Switches.
  • Layer 3 interface data with packet discard and error statistics.
  • And data from the BGP protocol and its neighbors.

Surprising no?

By Michael Alvarez

2 Comments

  1. Excellent job Michael!
    Huawei VRP is a pain in the butt when it comes to automating things. I like how you implemented BGP neighbor function with so much effort. Maybe you can consider contributing to the current huawei-ce or huawei-vrp repo on github.
    Also, your code is missing some stuff(IPV4_ADDR_REGEX, IPV6_ADDR_REGEX, ASN_REGEX and bgp_time_conversion function) in order to run straight out of box.
    Do you have a github account that I can follow?

    1. Thanks Kevin. I have considered to contribute on current huawei-ce, i just haven’t dedicate the time to push the code i have developed. But you motivated to do it. I just update my github account, you can find me on: codingnetworksb.

Leave a Reply

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