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?