NAPALM Data Collection
Network Programmability and AutomationTutoriales

NAPALM Network Automation Python: Colectar Datos de Múltiples Fabricantes

Introducción

En este artículo vamos conocer las funciones y métodos de NAPALM para colectar datos en routers y switches de múltiples fabricantes. Escribiremos múltiples scripts en Python para colectar datos de esta red, que podrás usar para crear reportes o investigar sobre algún problema. Este es una continuación del artículo en el que trabajando Huawei VRP y es parte de la aventura en la que quiero enseñarles como puedes implementar Programabilidad y Automatización de Redes con Python y la librería NAPALM.

El contenido principal está en el siguiente video. Así que empieza por aquí para que puedas entender algunas secciones del artículo.

NAPALM Python

Es en esta sección es donde empezaremos a ver y disfrutar de las bondades de utilizar NAPALM para programabilidad y automatización de redes en los dispositivos Cisco y Huawei. Y es donde básicamente les comparto el código de lo visto en el video.

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

Vamos a modificar el script que hicimos en el video Trabajando con Huawei VRP para que nos imprima en una tabla informaciones como el hostname, fabricante, modelo, tiempo que tienen en operación y el número de serial, una tabla con las interfaces y otra tabla con la tabla de MAC address de los de los dispositivos Huawei y Cisco. A continuación el código modificado:

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()

En el video se encuentra la explicación de este código.

Veamos la salida del 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

Vamos a modificar el código anterior para agregar otra funcionalidad. Esta funcionalidad permitirá imprimir una tabla con información de las interfaces capa 3 de los routers, es decir las direcciones IP y sus máscaras de red. Además de esa información vamos a incluir algunos de los de los contadores de estas interfaces para visualizar los Errores o Descartes de paquetes. 

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()

En el video se encuentra la explicación de este código.

Veamos la salida de este código:

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

Aquí tenemos nuestro método get bgp neighbors que fue desarrollado para poder tener una función igual que en Cisco que me permita sacar los vecinos de  bgp, el sistema autónomo remoto, los prefijos enviados y los prefijos recibidos.

    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

A continuación el código que hemos estado trabajando incluyendo el desarrollo que habíamos hecho anteriormente para imprimir la tabla de vecinos BGP.

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()

Veamos la salida de este código:

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

Conclusión

Nuevamente me sorprendo cuando veo que en 135 líneas de códigos, tengo un script que se conecta mi red multi-vendor y en 1 minuto me da un resumen de:

  • Datos de las interfaces.
  • Datos de la tabla Mac Address de los Switches.
  • Datos de las interfaces capa 3 con estadísticas de errores y descartes de paquetes.
  • Y datos del protocolo BGP y sus vecinos.

Sorprendente no?

By Michael Alvarez

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *