Bonjour Habr! Ceci est mon premier article sur Habré, et elle est née d'une question dans l'un des forums professionnels. La question ressemblait, pour paraphraser quelque peu, comme suit:
- Il existe un ensemble de fichiers texte contenant la sortie des tables de routage de divers périphériques réseau;
- Chaque fichier contient des informations d'un appareil;
- Les périphériques peuvent avoir un format de sortie différent pour la table de routage;
- Sur la base des données disponibles, sur demande, il est nécessaire d'afficher le chemin vers un sous-réseau arbitraire ou une adresse IP à partir de chacun des appareils;
- La sortie doit inclure sur chaque section du chemin des informations sur l'entrée de la table de routage, le long de laquelle le paquet sera routé.
J'ai trouvé la tùche intéressante et j'ai fait écho à l'un de mes propres utilitaires de réseau, qui sont prévus à l'avenir. Par conséquent, lors d'une soirée libre, aprÚs avoir réfléchi à sa solution, j'ai écrit une implémentation de preuve de concept en Python 2.7 pour les formats Cisco IOS, IOS-XE et ASA, qui répond exigences de base.
Dans l'article, je vais essayer de reproduire le train de pensée et commenter les points principaux.
Le matériel est destiné aux personnes qui connaissent déjà fondamentalement les bases du réseautage et de Python.
Bienvenue à tous les chats intéressés!
Clause de non-responsabilité
L'auteur de l'article, étant un ingénieur réseau, n'est pas un développeur professionnel et peut ne pas encore connaßtre la différence entre une interface et une classe abstraite mais toujours ouvert à la critique et à la rétroaction constructives. Les commentaires sur le code, les approches sélectionnées et les algorithmes de collÚgues plus expérimentés sont les bienvenus.
Tout le code de cet article est distribué sous la licence MIT, y compris Il est fourni «tel quel» et ne fournit aucune sorte de garantie.
Clarification des conditions et choix de l'algorithme de solution
Compte tenu de l'introduction, la tĂąche peut ĂȘtre divisĂ©e en deux parties principales: analyse des fichiers source avec des tables de routage et recherche directe du chemin Ă l'aide de donnĂ©es initialisĂ©es.
Une telle séparation permettra également, si nécessaire, d'importer des itinéraires à partir d'appareils pour rechercher un chemin arbitrairement (par exemple, via SNMP ou REST API).
Pour améliorer les performances, il est judicieux d'initialiser les fichiers une fois lors de l'exécution du script.
Un analyseur de fichiers doit reconnaĂźtre le format des tables de routage de divers systĂšmes d'exploitation. Ensuite, une option pour Cisco IOS, IOS-XE et ASA pour IPv4 sera considĂ©rĂ©e. La prise en charge d'autres formats et IPv6 peut ĂȘtre ajoutĂ©e ultĂ©rieurement.
Comme vous le savez, le choix d'un itinéraire selon la table de routage se fait selon le principe de coïncidence avec le préfixe de la plus grande longueur (correspondance de préfixe la plus longue).
Comme l'une des solutions pour une recherche rapide d'une telle correspondance, vous pouvez créer une arborescence de préfixes à partir des données source. Puisque nous n'avons pas de restrictions sur les dépendances externes, laissez-nous nous attarder sur le module SubnetTree terminé.
Il peut y avoir des boucles de routage sur la section rĂ©seau analysĂ©e, elles doivent ĂȘtre dĂ©tectĂ©es et ne pas affecter le script. De plus, sur aucun des nĆuds, il ne peut y avoir de route vers le sous-rĂ©seau souhaitĂ©. Cela devrait Ă©galement ĂȘtre pris en considĂ©ration.
S'il y a VRF sur le pĂ©riphĂ©rique, les tables de routage de chaque instance doivent ĂȘtre stockĂ©es dans des fichiers sĂ©parĂ©s, car du point de vue de la topologie, ce sont des routeurs distincts.
Les limitations des performances de iron pour l'exécution du script, le nombre et la taille des tables de routage analysées ne sont pas indiqués dans la condition, mais vous devez les garder à l'esprit.
La spécificité de l'application suggÚre une limite moyenne de 1 000 000 d'entrées dans la table de routage pour un appareil moderne. Sur un routeur avec BGP Full View en juin 2018, il peut y avoir 724 000+ itinéraires.
Selon une estimation approximative et les résultats des tests de stockage en mémoire et de traitement de 1 000 000 de préfixes, environ 500 Mo de RAM seront nécessaires. Ainsi, une station de travail à productivité moyenne avec 8 Go de RAM (nous gardons toujours à l'esprit en 2018) nous permettra d'analyser la topologie avec une capacité totale allant jusqu'à 14-16.000.000 de routes. Autrement dit, un segment d'environ 18-20 routeurs avec une vue complÚte sur chacun.
Dans la plupart des cas, cela suffit, mais pour les grands réseaux (comme le stress), vous devez soit diviser l'analyse en segments, soit transférer la logique vers une base de données insuffisante.
640 Ko suffisent Ă tout le monde. ArrĂȘtons-nous sur la version en mĂ©moire.
Analyser les fichiers source et sélectionner les structures de données
Nous allons mettre les fichiers avec les tables de routage dans un sous-répertoire séparé et en faire une variable:
RT_DIRECTORY = "./routing_tables"
Pour Cisco IOS et IOS-XE, la table de routage pourrait ressembler Ă ceci:
montrer la route ip S* 0.0.0.0/0 [1/0] via 10.220.88.1 10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks C 10.220.88.0/24 is directly connected, FastEthernet4 L 10.220.88.20/32 is directly connected, FastEthernet4 1.0.0.0/32 is subnetted, 1 subnets S 1.1.1.1 [1/0] via 212.0.0.1 [1/0] via 192.168.0.1 D EX 10.1.198.0/24 [170/1683712] via 172.16.209.47, 1w2d, Vlan910 [170/1683712] via 172.16.60.33, 1w2d, Vlan60 [170/1683712] via 10.25.20.132, 1w2d, Vlan220 [170/1683712] via 10.25.20.9, 1w2d, Vlan20 4.0.0.0/16 is subnetted, 1 subnets O E2 4.4.0.0 [110/20] via 194.0.0.2, 00:02:00, FastEthernet0/0 5.0.0.0/24 is subnetted, 1 subnets D EX 5.5.5.0 [170/2297856] via 10.0.1.2, 00:12:01, Serial0/0 6.0.0.0/16 is subnetted, 1 subnets B 6.6.0.0 [200/0] via 195.0.0.1, 00:00:04 172.16.0.0/26 is subnetted, 1 subnets i L2 172.16.1.0 [115/10] via 10.0.1.2, Serial0/0 172.20.0.0/32 is subnetted, 3 subnets O 172.20.1.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0 O 172.20.3.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0 O 172.20.2.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0 10.0.0.0/8 is variably subnetted, 5 subnets, 3 masks C 10.0.1.0/24 is directly connected, Serial0/0 D 10.0.5.0/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0 D 10.0.5.64/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0 D 10.0.5.128/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0 D 10.0.5.192/27 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0 192.168.0.0/32 is subnetted, 1 subnets D 192.168.0.1 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0 O IA 195.0.0.0/24 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0 O E2 212.0.0.0/8 [110/20] via 194.0.0.2, 00:05:35, FastEthernet0/0 C 194.0.0.0/16 is directly connected, FastEthernet0/0
Dans Cisco ASA, le format est similaire, mais au lieu des longueurs de préfixe, le masque de sous-réseau est affiché en notation décimale:
montrer l'itinéraire S 10.1.1.0 255.255.255.0 [3/0] via 10.86.194.1, outside C 10.86.194.0 255.255.254.0 is directly connected, outside S* 0.0.0.0 0.0.0.0 [1/0] via 10.86.194.1, outside
Comme vous pouvez le voir sur l'exemple, les routes, malgrĂ© la grande diversitĂ©, ont la mĂȘme structure prĂ©visible, ce qui signifie qu'elles peuvent ĂȘtre traitĂ©es par des expressions rĂ©guliĂšres.
Deux groupes mondiaux apparaissent: les itinéraires locaux + connectés et tout le reste.
Pour compliquer un peu les choses, il y a la possibilité d'avoir des routes multi-lignes avec un nombre variable d'espoirs prochains. Pour cette raison, il est problématique de lire le fichier pour le traitement ligne par ligne. Une solution consiste à traiter plusieurs correspondances avec un itérateur d'une expression réguliÚre dans un fichier chargé entiÚrement dans une variable de texte.
Nous écrirons des expressions réguliÚres en tenant compte des exigences et restrictions énumérées:
Les deux expressions contiennent des groupes nommés pour faciliter la récupération des données lors de la recherche de correspondances et de la gestion du code.
En particulier, Ă partir de chaque route, vous devez obtenir un prĂ©fixe ( sous - rĂ©seau / interface et groupes maskOrPrefixLength ) et des informations sur oĂč il mĂšne ( via des groupes de proportion / interface ).
Ătant donnĂ© que les expressions prennent en compte plusieurs options pour reprĂ©senter le prĂ©fixe, le groupe maskOrPrefixLength peut contenir un masque de sous-rĂ©seau ou une longueur de prĂ©fixe. Nous allons rĂ©duire cela Ă un seul format pendant le traitement; nous nous attarderons sur la longueur du prĂ©fixe:
def convert_netmask_to_prefix_length(mask_or_pref): if not mask_or_pref: return "" if re.match("^\/\d\d?$", mask_or_pref): return mask_or_pref if re.match("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$", mask_or_pref): return ( "/" + str(sum([bin(int(x)).count("1") for x in mask_or_pref.split(".")])) ) return ""
Ajoutez des expressions réguliÚres pour l'analyse ligne par ligne du saut suivant à partir du groupe viaPortion , en vérifiant le format des adresses IPv4 et l'entrée utilisateur:
Nous transférons maintenant la représentation de notre réseau vers des structures de données Python.
Les préfixes résultant de l'analyse des tables de routage seront utilisés comme clés dans l'arborescence des préfixes. L'objet arborescence de préfixe est hérité du module SubnetTree .
Le résultat de la recherche par préfixe dans l'arborescence renverra une liste de la liste des prochains espoirs et une représentation textuelle complÚte de l'itinéraire correspondant à partir du fichier d'origine.
En outre, créez une liste d'interfaces locales.
Chaque routeur est représenté par un dictionnaire, dans lequel nous mettons les données ci-dessus.
Nous faisons une demande Ă la table de routage dans une fonction distincte:
def route_lookup(destination, router): if destination in router['routing_table']: return router['routing_table'][destination] else: return (None, None)
Chaque routeur se verra attribuer un identifiant unique. Vous pouvez l'affecter de plusieurs façons, dans l'exemple actuel, il sera permis et clair de le faire en fonction du nom du fichier d'origine.
En conséquence, nous ajouterons les objets de routeur résultants au dictionnaire avec la clé sous la forme de cet identifiant unique.
ROUTERS = { 'router_id_1': router_1, 'router_id_n': router_n, }
Nous avons également besoin d'un mécanisme pour rechercher le prochain routeur par l'adresse IP du saut suivant, obtenue à partir de la table de routage lors de la recherche de chemin. Pour ce faire, nous créons une autre arborescence de préfixes globale avec des clés sous forme d'adresses IP de tous les routeurs connus dans la topologie et des feuilles retournées avec l'identifiant du routeur et le type d'interface.
Mettons ensemble l'analyseur pour le format IOS / IOS-XE / ASA. à l'entrée, nous lui passons la table de routage sous forme de texte, à la sortie nous obtenons le dictionnaire du routeur dans le format spécifié ci-dessus.
def parse_show_ip_route_ios_like(raw_routing_table): router = {} route_tree = SubnetTree.SubnetTree() interface_list = []
Nous enveloppons l'analyseur dans une autre fonction pour permettre l'ajout ultérieur d'analyseurs d'autres formats (par exemple, NX-OS):
def parse_text_routing_table(raw_routing_table): """ Parser functions wrapper. Add additional parsers for alternative routing table syntaxes here. """ router = parse_show_ip_route_ios_like(raw_routing_table) if router: return router
Reste donc à parcourir les fichiers texte du répertoire:
def do_parse_directory(rt_directory): new_routers = {} if not os.path.isdir(rt_directory): print("{} directory does not exist.".format(rt_directory) + "Check rt_directory variable value." ) return None start_time = time() print("Initializing files...") for FILENAME in os.listdir(rt_directory): if FILENAME.endswith('.txt'): file_init_start_time = time() with open(os.path.join(rt_directory, FILENAME), 'r') as f: print ('Opening {}'.format(FILENAME)) raw_table = f.read() new_router = parse_text_routing_table(raw_table) router_id = FILENAME.replace('.txt', '') if new_router: new_routers[router_id] = new_router if new_router['interface_list']: for iface, addr in new_router['interface_list']: GLOBAL_INTERFACE_TREE[addr]= (router_id, iface,) else: print ('Failed to parse ' + FILENAME) print (FILENAME + " parsing has been completed in %s sec".format( "{:.3f}".format(time() - file_init_start_time)) ) else: if not new_routers: print ("Could not find any valid .txt files with routing tables" + " in {} directory".format(rt_directory) ) else: print ("\nAll files have been initialized" + " in {} sec".format("{:.3f}".format(time() - start_time)) ) return new_routers
Et, aprÚs avoir décomposé tous les fichiers en structures de données ordonnées, on peut assumer la deuxiÚme partie de la tùche.
Recherche d'un chemin à travers les tables de routage traitées
En général, à ce stade, la tùche est réduite à l'analyse du graphe de réseau. Les routeurs sont des sommets du graphique, les liens L3 entre eux sont des bords.
Le dictionnaire ROUTERS stocke les identifiants des routeurs dans les clés et dans les valeurs correspondantes - les liens vers les adresses IP du prochain bond. Autrement dit, en conjonction avec GLOBAL_INTERFACE_TREE , qui renvoie les identifiants de routeur par adresse IP, pour chaque sous-réseau souhaité, il définit une table d'adjacence de graphe.
Si nous établissons des parallÚles avec de vrais routeurs, pour trouver la façon dont vous devez reproduire la logique de haut niveau de leur travail (abstrait de RIB / FIB / ASIC et d'autres optimisations) lors du traitement d'un paquet d'une recherche à la table de routage à la demande ARP (ou router_id dans notre cas) et au routage ou déposer le colis, selon le résultat.
Nous implémentons une recherche de chemin récursive sur les routeurs. Chaque section du chemin sera représentée par une feuille de router_id et raw_route_string - la chaßne de route d'origine dessus. Le chemin actuel sera écrit dans le tuple de chemin . En atteignant le point de destination, l'absence de route dans la table de routage ou de saut suivant dans la topologie étudiée, le chemin actuel sera ajouté au tuple de chemins résultant, que la fonction retournera.
def trace_route(source_router_id, target_ip, path=[]): if not source_router_id: return [path + [(None, None)]] current_router = ROUTERS[source_router_id] next_hop, raw_route_string = route_lookup(target_ip, current_router) path = path + [(source_router_id, raw_route_string)] paths = [] if next_hop: if nexthop_is_local(next_hop[0]): return [path] for nh in next_hop: next_hop_rid = get_rid_by_interface_ip(nh) if not next_hop_rid in [r[0] for r in path]: inner_path = trace_route(next_hop_rid, target_ip, path) for p in inner_path: paths.append(p) else: path = path + [(next_hop_rid+"<<LOOP DETECTED", None)] return [path] else: return [path] return paths def nexthop_is_local(next_hop): interface_types = ('Eth', 'Fast', 'Gig', 'Ten', 'Port', 'Serial', 'Vlan', 'Tunn', 'Loop', 'Null' ) for type in interface_types: if next_hop.startswith(type): return True
Ajoutez une fonction pour démarrer la recherche en mode interactif aprÚs l'initialisation des fichiers texte:
def do_user_interactive_search(): while True: print ('\n') target_subnet = raw_input('Enter Target Subnet or Host: ') if not target_subnet: continue if not REGEXP_INPUT_IPv4.match(target_subnet.replace(' ', '')): print ("incorrect input") continue lookup_start_time = time() for rtr in ROUTERS.keys(): subsearch_start_time = time() result = trace_route(rtr, target_subnet) if result: print ("\n") print ("PATHS TO {} FROM {}".format(target_subnet, rtr)) n = 1 print ('Detailed info:') for r in result: print ("Path {}:".format(n)) print ([h[0] for h in r]) for hop in r: print ("ROUTER: {}".format(hop[0])) print ("Matched route string: \n{}".format(hop[1])) else: print ('\n') n+=1 else: print ("Path search on {} has been completed in {} sec".format( rtr, "{:.3f}".format(time() - subsearch_start_time)) ) else: print ("\nFull search has been completed in {} sec".format( "{:.3f}".format(time() - lookup_start_time),) )
La touche finale pour combiner les deux parties:
def main(): global ROUTERS ROUTERS = do_parse_directory(RT_DIRECTORY) if ROUTERS: do_user_interactive_search() if __name__ == "__main__": main()
Et nous avons un code prĂȘt Ă fonctionner.
Code import os import re import SubnetTree from time import time
Vérification du script
Armé d'une petite topologie abstraite des quatre Cisco CSR-1000v :

Ils sont connectés par paires via les interfaces GigabitEthernet 2 et 3. Entre eux, il y a un quartier EIGRP, à travers lequel tous les réseaux connectés sont annoncés, y compris les réseaux sur les interfaces Loopback derriÚre chaque routeur.
Entre csr1000v-01 et csr1000v-04, deux tunnels GRE sont également levés, via les adresses IP distantes dont les routes statiques vers le réseau 10.0.0.0/8 sont enregistrées pour tester la boucle de routage.
csr1000v-01 # show route ip Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2 E1 - OSPF external type 1, E2 - OSPF external type 2 i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2 ia - IS-IS inter area, * - candidate default, U - per-user static route o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP a - application route + - replicated route, % - next hop override, p - overrides from PfR Gateway of last resort is not set S 10.0.0.0/8 [1/0] via 192.168.142.2 [1/0] via 192.168.141.2 172.16.0.0/16 is variably subnetted, 2 subnets, 2 masks C 172.16.114.0/24 is directly connected, GigabitEthernet2 L 172.16.114.5/32 is directly connected, GigabitEthernet2 192.168.2.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.2.0/24 is directly connected, GigabitEthernet1 L 192.168.2.201/32 is directly connected, GigabitEthernet1 192.168.12.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.12.0/24 is directly connected, GigabitEthernet2 L 192.168.12.201/32 is directly connected, GigabitEthernet2 192.168.13.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.13.0/24 is directly connected, GigabitEthernet3 L 192.168.13.201/32 is directly connected, GigabitEthernet3 D 192.168.24.0/24 [90/3072] via 192.168.12.202, 00:06:56, GigabitEthernet2 D 192.168.34.0/24 [90/3072] via 192.168.13.203, 00:06:56, GigabitEthernet3 192.168.141.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.141.0/30 is directly connected, Tunnel141 L 192.168.141.1/32 is directly connected, Tunnel141 192.168.142.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.142.0/30 is directly connected, Tunnel142 L 192.168.142.1/32 is directly connected, Tunnel142 192.168.201.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.201.0/24 is directly connected, Loopback201 L 192.168.201.201/32 is directly connected, Loopback201 D 192.168.202.0/24 [90/130816] via 192.168.12.202, 00:05:44, GigabitEthernet2 D 192.168.203.0/24 [90/130816] via 192.168.13.203, 00:06:22, GigabitEthernet3 D 192.168.204.0/24 [90/131072] via 192.168.13.203, 00:06:56, GigabitEthernet3 [90/131072] via 192.168.12.202, 00:06:56, GigabitEthernet2
csr1000v-02 # show route ip Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2 E1 - OSPF external type 1, E2 - OSPF external type 2 i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2 ia - IS-IS inter area, * - candidate default, U - per-user static route o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP a - application route + - replicated route, % - next hop override, p - overrides from PfR Gateway of last resort is not set 192.168.2.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.2.0/24 is directly connected, GigabitEthernet1 L 192.168.2.202/32 is directly connected, GigabitEthernet1 192.168.12.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.12.0/24 is directly connected, GigabitEthernet2 L 192.168.12.202/32 is directly connected, GigabitEthernet2 D 192.168.13.0/24 [90/3072] via 192.168.12.201, 00:46:17, GigabitEthernet2 192.168.24.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.24.0/24 is directly connected, GigabitEthernet3 L 192.168.24.202/32 is directly connected, GigabitEthernet3 D 192.168.34.0/24 [90/3072] via 192.168.24.204, 00:46:15, GigabitEthernet3 D 192.168.201.0/24 [90/130816] via 192.168.12.201, 00:36:59, GigabitEthernet2 192.168.202.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.202.0/24 is directly connected, Loopback202 L 192.168.202.202/32 is directly connected, Loopback202 D 192.168.203.0/24 [90/131072] via 192.168.24.204, 00:06:31, GigabitEthernet3 [90/131072] via 192.168.12.201, 00:06:31, GigabitEthernet2 D 192.168.204.0/24 [90/130816] via 192.168.24.204, 00:37:26, GigabitEthernet3
csr1000v-03 # show ip route Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2 E1 - OSPF external type 1, E2 - OSPF external type 2 i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2 ia - IS-IS inter area, * - candidate default, U - per-user static route o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP a - application route + - replicated route, % - next hop override, p - overrides from PfR Gateway of last resort is not set 192.168.2.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.2.0/24 is directly connected, GigabitEthernet1 L 192.168.2.203/32 is directly connected, GigabitEthernet1 D 192.168.12.0/24 [90/3072] via 192.168.13.201, 00:46:12, GigabitEthernet3 192.168.13.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.13.0/24 is directly connected, GigabitEthernet3 L 192.168.13.203/32 is directly connected, GigabitEthernet3 D 192.168.24.0/24 [90/3072] via 192.168.34.204, 00:46:12, GigabitEthernet2 192.168.34.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.34.0/24 is directly connected, GigabitEthernet2 L 192.168.34.203/32 is directly connected, GigabitEthernet2 D 192.168.201.0/24 [90/130816] via 192.168.13.201, 00:36:56, GigabitEthernet3 D 192.168.202.0/24 [90/131072] via 192.168.34.204, 00:05:51, GigabitEthernet2 [90/131072] via 192.168.13.201, 00:05:51, GigabitEthernet3 192.168.203.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.203.0/24 is directly connected, Loopback203 L 192.168.203.203/32 is directly connected, Loopback203 D 192.168.204.0/24 [90/130816] via 192.168.34.204, 00:37:22, GigabitEthernet2
csr1000v-04#show ip route Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2 E1 - OSPF external type 1, E2 - OSPF external type 2 i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2 ia - IS-IS inter area, * - candidate default, U - per-user static route o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP a - application route + - replicated route, % - next hop override, p - overrides from PfR Gateway of last resort is not set S 10.0.0.0/8 [1/0] via 192.168.142.1 [1/0] via 192.168.141.1 192.168.2.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.2.0/24 is directly connected, GigabitEthernet1 L 192.168.2.204/32 is directly connected, GigabitEthernet1 D 192.168.12.0/24 [90/3072] via 192.168.24.202, 00:46:17, GigabitEthernet3 D 192.168.13.0/24 [90/3072] via 192.168.34.203, 00:46:19, GigabitEthernet2 192.168.24.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.24.0/24 is directly connected, GigabitEthernet3 L 192.168.24.204/32 is directly connected, GigabitEthernet3 192.168.34.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.34.0/24 is directly connected, GigabitEthernet2 L 192.168.34.204/32 is directly connected, GigabitEthernet2 192.168.141.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.141.0/30 is directly connected, Tunnel141 L 192.168.141.2/32 is directly connected, Tunnel141 192.168.142.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.142.0/30 is directly connected, Tunnel142 L 192.168.142.2/32 is directly connected, Tunnel142 D 192.168.201.0/24 [90/131072] via 192.168.34.203, 00:37:02, GigabitEthernet2 [90/131072] via 192.168.24.202, 00:37:02, GigabitEthernet3 D 192.168.202.0/24 [90/130816] via 192.168.24.202, 00:05:57, GigabitEthernet3 D 192.168.203.0/24 [90/130816] via 192.168.34.203, 00:06:34, GigabitEthernet2 192.168.204.0/24 is variably subnetted, 2 subnets, 2 masks C 192.168.204.0/24 is directly connected, Loopback204 L 192.168.204.204/32 is directly connected, Loopback204
show ip route - ./routing_tables/ :
$ python2.7 traceRouteByShowIPRoute.py $ python2.7 traceRouteByShowIPRoute.py Initializing files... Opening csr1000v-01.txt csr1000v-01.txt parsing has been completed in 0.001 sec Opening csr1000v-02.txt csr1000v-02.txt parsing has been completed in 0.001 sec Opening csr1000v-03.txt csr1000v-03.txt parsing has been completed in 0.001 sec Opening csr1000v-04.txt csr1000v-04.txt parsing has been completed in 0.001 sec All files have been initialized in 0.003 sec Enter Target Subnet or Host:
, , , IP- .
.
Loopback204 192.168.204.204 csr1000v-04IP- .
Enter Target Subnet or Host: 192.168.204.204 Enter Target Subnet or Host: 192.168.204.204 PATHS TO 192.168.204.204 FROM csr1000v-04 Detailed info: Path 1: ['csr1000v-04'] ROUTER: csr1000v-04 Matched route string: L 192.168.204.204/32 is directly connected, Loopback204 Path search on csr1000v-04 has been completed in 0.000 sec PATHS TO 192.168.204.204 FROM csr1000v-03 Detailed info: Path 1: ['csr1000v-03', 'csr1000v-04'] ROUTER: csr1000v-03 Matched route string: D 192.168.204.0/24 [90/130816] via 192.168.34.204, 00:37:22, GigabitEthernet2 ROUTER: csr1000v-04 Matched route string: L 192.168.204.204/32 is directly connected, Loopback204 Path search on csr1000v-03 has been completed in 0.000 sec PATHS TO 192.168.204.204 FROM csr1000v-02 Detailed info: Path 1: ['csr1000v-02', 'csr1000v-04'] ROUTER: csr1000v-02 Matched route string: D 192.168.204.0/24 [90/130816] via 192.168.24.204, 00:37:26, GigabitEthernet3 ROUTER: csr1000v-04 Matched route string: L 192.168.204.204/32 is directly connected, Loopback204 Path search on csr1000v-02 has been completed in 0.000 sec PATHS TO 192.168.204.204 FROM csr1000v-01 Detailed info: Path 1: ['csr1000v-01', 'csr1000v-03', 'csr1000v-04'] ROUTER: csr1000v-01 Matched route string: D 192.168.204.0/24 [90/131072] via 192.168.13.203, 00:06:56, GigabitEthernet3 [90/131072] via 192.168.12.202, 00:06:56, GigabitEthernet2 ROUTER: csr1000v-03 Matched route string: D 192.168.204.0/24 [90/130816] via 192.168.34.204, 00:37:22, GigabitEthernet2 ROUTER: csr1000v-04 Matched route string: L 192.168.204.204/32 is directly connected, Loopback204 Path 2: ['csr1000v-01', 'csr1000v-02', 'csr1000v-04'] ROUTER: csr1000v-01 Matched route string: D 192.168.204.0/24 [90/131072] via 192.168.13.203, 00:06:56, GigabitEthernet3 [90/131072] via 192.168.12.202, 00:06:56, GigabitEthernet2 ROUTER: csr1000v-02 Matched route string: D 192.168.204.0/24 [90/130816] via 192.168.24.204, 00:37:26, GigabitEthernet3 ROUTER: csr1000v-04 Matched route string: L 192.168.204.204/32 is directly connected, Loopback204 Path search on csr1000v-01 has been completed in 0.000 sec Full search has been completed in 0.001 sec
, . :
csr1000v-01#show ip route 192.168.204.204 csr1000v-01#show ip route 192.168.204.204 Routing entry for 192.168.204.0/24 Known via "eigrp 200", distance 90, metric 131072, type internal Redistributing via eigrp 200 Last update from 192.168.13.203 on GigabitEthernet3, 00:02:15 ago Routing Descriptor Blocks: 192.168.13.203, from 192.168.13.203, 00:02:15 ago, via GigabitEthernet3 Route metric is 131072, traffic share count is 1 Total delay is 5020 microseconds, minimum bandwidth is 1000000 Kbit Reliability 255/255, minimum MTU 1500 bytes Loading 1/255, Hops 2 * 192.168.12.202, from 192.168.12.202, 00:02:15 ago, via GigabitEthernet2 Route metric is 131072, traffic share count is 1 Total delay is 5020 microseconds, minimum bandwidth is 1000000 Kbit Reliability 255/255, minimum MTU 1500 bytes Loading 1/255, Hops 2
csr1000v-01 equal-cost EIGRP csr1000v-02 csr1000v-03.
, : ['csr1000v-01', 'csr1000v-03', 'csr1000v-04'] ['csr1000v-01', 'csr1000v-02', 'csr1000v-04'].
csr1000v-02#show ip route 192.168.204.204 csr1000v-02#show ip route 192.168.204.204 Routing entry for 192.168.204.0/24 Known via "eigrp 200", distance 90, metric 130816, type internal Redistributing via eigrp 200 Last update from 192.168.24.204 on GigabitEthernet3, 00:08:48 ago Routing Descriptor Blocks: * 192.168.24.204, from 192.168.24.204, 00:08:48 ago, via GigabitEthernet3 Route metric is 130816, traffic share count is 1 Total delay is 5010 microseconds, minimum bandwidth is 1000000 Kbit Reliability 255/255, minimum MTU 1500 bytes Loading 1/255, Hops 1
csr1000v-03#show ip route 192.168.204.204 csr1000v-3#show ip route 192.168.204.204 Routing entry for 192.168.204.0/24 Known via "eigrp 200", distance 90, metric 130816, type internal Redistributing via eigrp 200 Last update from 192.168.34.204 on GigabitEthernet2, 00:08:45 ago Routing Descriptor Blocks: * 192.168.34.204, from 192.168.34.204, 00:08:45 ago, via GigabitEthernet2 Route metric is 130816, traffic share count is 1 Total delay is 5010 microseconds, minimum bandwidth is 1000000 Kbit Reliability 255/255, minimum MTU 1500 bytes Loading 1/255, Hops 1
csr1000v-2 csr1000v-3 EIGRP csr1000v-4.
, : ['csr1000v-02', 'csr1000v-04'] ['csr1000v-03', 'csr1000v-04'] .
csr1000v-04#show ip route 192.168.204.204 csr1000v-04#show ip route 192.168.204.204 Routing entry for 192.168.204.204/32 Known via "connected", distance 0, metric 0 (connected) Routing Descriptor Blocks: * directly connected, via Loopback204 Route metric is 0, traffic share count is 1
csr1000v-4 Connnected Loopback204.
Local : ['csr1000v-04'].
10.10.10.0/24 ( )Enter Target Subnet or Host: 10.10.10.0/24 Enter Target Subnet or Host: 10.10.10.0/24 PATHS TO 10.10.10.0/24 FROM csr1000v-04 Detailed info: Path 1: ['csr1000v-04', 'csr1000v-01', 'csr1000v-04<<LOOP DETECTED'] ROUTER: csr1000v-04 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.1 [1/0] via 192.168.141.1 ROUTER: csr1000v-01 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.2 [1/0] via 192.168.141.2 ROUTER: csr1000v-04<<LOOP DETECTED Matched route string: None Path 2: ['csr1000v-04', 'csr1000v-01', 'csr1000v-04<<LOOP DETECTED'] ROUTER: csr1000v-04 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.1 [1/0] via 192.168.141.1 ROUTER: csr1000v-01 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.2 [1/0] via 192.168.141.2 ROUTER: csr1000v-04<<LOOP DETECTED Matched route string: None Path search on csr1000v-04 has been completed in 0.000 sec PATHS TO 10.10.10.0/24 FROM csr1000v-03 Detailed info: Path 1: ['csr1000v-03'] ROUTER: csr1000v-03 Matched route string: None Path search on csr1000v-03 has been completed in 0.000 sec PATHS TO 10.10.10.0/24 FROM csr1000v-02 Detailed info: Path 1: ['csr1000v-02'] ROUTER: csr1000v-02 Matched route string: None Path search on csr1000v-02 has been completed in 0.000 sec PATHS TO 10.10.10.0/24 FROM csr1000v-01 Detailed info: Path 1: ['csr1000v-01', 'csr1000v-04', 'csr1000v-01<<LOOP DETECTED'] ROUTER: csr1000v-01 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.2 [1/0] via 192.168.141.2 ROUTER: csr1000v-04 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.1 [1/0] via 192.168.141.1 ROUTER: csr1000v-01<<LOOP DETECTED Matched route string: None Path 2: ['csr1000v-01', 'csr1000v-04', 'csr1000v-01<<LOOP DETECTED'] ROUTER: csr1000v-01 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.2 [1/0] via 192.168.141.2 ROUTER: csr1000v-04 Matched route string: S 10.0.0.0/8 [1/0] via 192.168.142.1 [1/0] via 192.168.141.1 ROUTER: csr1000v-01<<LOOP DETECTED Matched route string: None Path search on csr1000v-01 has been completed in 0.003 sec Full search has been completed in 0.004 sec
.
:
csr1000v-01#show ip route 10.10.10.0 255.255.255.0 csr1000v-01#show ip route 10.10.10.0 255.255.255.0 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 Routing Descriptor Blocks: * 192.168.142.2 Route metric is 0, traffic share count is 1 192.168.141.2 Route metric is 0, traffic share count is 1
csr1000v-04#show ip route 10.10.10.0 255.255.255.0 csr1000v-04#show ip route 10.10.10.0 255.255.255.0 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 Routing Descriptor Blocks: 192.168.142.1 Route metric is 0, traffic share count is 1 * 192.168.141.1 Route metric is 0, traffic share count is 1
csr1000v-01 csr1000v-04 GRE- 10.0.0.0/8. .
:
PATHS TO 10.10.10.0/24 FROM csr1000v-01 Path 1: ['csr1000v-01', 'csr1000v-04', 'csr1000v-01<<LOOP DETECTED'] Path 2: ['csr1000v-01', 'csr1000v-04', 'csr1000v-01<<LOOP DETECTED'] PATHS TO 10.10.10.0/24 FROM csr1000v-04 Path 1: ['csr1000v-04', 'csr1000v-01', 'csr1000v-04<<LOOP DETECTED'] Path 2: ['csr1000v-04', 'csr1000v-01', 'csr1000v-04<<LOOP DETECTED']
csr1000v-02#show ip route 10.10.10.0 255.255.255.0 csr1000v-02#show ip route 10.10.10.0 255.255.255.0 % Network not in table
csr1000v-3#show ip route 10.10.10.0 255.255.255.0 csr1000v-3#show ip route 10.10.10.0 255.255.255.0 % Network not in table
csr1000v-02 csr1000v-03 . .
, , , .
Conclusion
, . MacBook Pro Intel Core i5 8GB RAM 700.000+ 6.85 ( 100 ). 320-350.
( ).
. IPv6 SubnetTree .
Python3, , raw_input input .
, , â , " " , " ", ..
Policy Based Routing ( PBR ) . , .
, - .
, .