Fledermausfisch Einführung

Bild

Eines der Probleme moderner Netzwerke ist ihre Fragilität. Viele Filterregeln, Richtlinien für den Routing-Informationsaustausch und dynamische Routing-Protokolle machen Netzwerke verwirrend und unterliegen menschlichen Faktoren. Ein Netzwerkabsturz kann unbeabsichtigt auftreten, wenn Änderungen an einer Routenkarte oder ACL ( eins , zwei ) vorgenommen werden. Es fehlt definitiv ein Tool, um das Verhalten eines Netzwerks mit einer neuen Konfiguration zu bewerten, bevor Änderungen an der Produktion vorgenommen werden. Ich möchte sicher wissen, ob Netzwerk A für mich verfügbar ist, wenn ich einige der von Anbieter B erhaltenen BGP-Ankündigungen herausfiltere. Auf welcher Route werden die Pakete von Netzwerk C zu Server D geleitet, wenn ich auf einer der Transitverbindungen die IGP-Metrik verdopple? Batfish hilft uns bei der Beantwortung dieser und vieler anderer Fragen!

Bewertung von Batfish


Batfish ist ein Netzwerkmodellierungswerkzeug. Der Hauptzweck besteht darin, Konfigurationsänderungen zu testen, bevor sie im Produktionsnetzwerk vorgenommen werden. Batfish kann auch verwendet werden, um den aktuellen Status des Netzwerks zu analysieren und zu überprüfen. Bestehende CI / CD-Prozesse in der Netzwerkwelt verfügen eindeutig nicht über ein Tool zum Testen neuer Konfigurationen. Batfish löst dieses Problem.

Batfish erfordert keinen direkten direkten Zugriff auf vorhandene Netzwerkgeräte. Batfish modelliert das Netzwerkverhalten basierend auf den in den Gerätekonfigurationsdateien enthaltenen Daten.

Batfish kann:

  • Bestimmen des Nachbarstatus von dynamischen Routing-Protokollen im Netzwerk (BGP, IS-IS, OSPF)
  • Berechnen Sie die RIB jedes Netzwerkelements
  • Überprüfen Sie die NTP-, AAA- und MTU-Einstellungen
  • Ermöglichen Sie die Bestimmung, ob die ACL den Durchgang des Netzwerkverkehrs blockiert (analog zum Packet-Tracer auf dem Cisco ASA).
  • Überprüfen Sie die End-to-End-Konnektivität zwischen Hosts im Netzwerk
  • Zeigen Sie den Verkehrspfad durch das Netzwerk an (virtuelle Ablaufverfolgung).


Unterstützte Plattformen:

  • Arista
  • Aruba
  • AWS (VPCs, Netzwerk-ACLs, VPN GW, NAT GW, Internet GW, Sicherheitsgruppen)
  • Cisco (NX-OS, IOS, IOS-XE, IOS-XR und ASA)
  • Dell force10
  • Gießerei
  • iptables
  • Wacholder (MX, EX, QFX, SRX, T-Serie, PTX)
  • Mrv
  • Palo-Alt-Netzwerke
  • Quagga / FRR
  • Quanta
  • Vyos

Bild

Batfish ist eine Java-Anwendung. Für die bequeme Arbeit wurde Pybatfish - Python SDK geschrieben.

Lass uns weiter üben. Ich werde Ihnen die Möglichkeiten von Batfish anhand eines Beispiels zeigen.

Beispiel


Wir verwalten zwei autonome Systeme: AS 41214 und AS 10631. Als IGP verwendet AS-41214 IS-IS und AS-10631 - OSPF. In jedem AS wird IBGP-Fullmesh verwendet. LDN-CORE-01 gibt das Präfix 135.65.0.0/19 der BGP-Nachbarn, MSK-CORE-01 - 140.0.0.0/24 bekannt. Der Austausch von Routing-Informationen zwischen autonomen Systemen erfolgt an der Kreuzung von HKI-CORE-01 - SPB-CORE-01.

HKI-CORE-01, STH-CORE-01 - Junos-Router
LDN-CORE-01, AMS-CORE-01, SPB-CORE-01, MSK-CORE-01 - Cisco IOS-Router



Installieren Sie den Container mit Batfish und dem Python SDK:

docker pull batfish/allinone docker run batfish/allinone docker container exec -it <container> bash 

Lernen Sie die Bibliothek im interaktiven Python-Modus kennen:

 root@ea9a1559d88e:/# python3 -------------------- >>> from pybatfish.client.commands import bf_logger, bf_init_snapshot >>> from pybatfish.question.question import load_questions >>> from pybatfish.question import bfq >>> import logging >>> bf_logger.setLevel(logging.ERROR) >>> load_questions() >>> bf_init_snapshot('tmp/habr') 'ss_e8065858-a911-4f8a-b020-49c9b96d0381' 

bf_init_snapshot ('tmp / habr') - Die Funktion lädt Konfigurationsdateien in Batfish und bereitet sie für die Analyse vor.

/ tmp / habr - ein Verzeichnis mit Routerkonfigurationsdateien .

 root@ea9a1559d88e:/tmp/habr# tree . `-- configs |-- AMS-CORE-01.cfg |-- HKI-CORE-01.cfg |-- LDN-CORE-01.cfg |-- MSK-CORE-01.cfg |-- SPB-CORE-01.cfg `-- STH-CORE-01.cfg 1 directory, 6 files 

Lassen Sie uns nun den Status von BGP-Sitzungen auf dem LDN-CORE-01-Router ermitteln:

 >>> bgp_peers = bfq.bgpSessionStatus(nodes='LDN-CORE-01').answer().frame() >>> bgp_peers Node VRF Local_AS Local_IP Remote_AS Remote_Node Remote_IP Session_Type Est_Status 0 ldn-core-01 default 41214 172.20.20.1 41214 sth-core-01 172.20.20.2 IBGP EST 1 ldn-core-01 default 41214 172.20.20.1 41214 ams-core-01 172.20.20.3 IBGP EST 2 ldn-core-01 default 41214 172.20.20.1 41214 hki-core-01 172.20.20.4 IBGP EST 

Und wie? Klingt nach der Wahrheit?

 LDN-CORE-01#show ip bgp summary … Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 172.20.20.2 4 41214 629 669 9 0 0 00:56:51 0 172.20.20.3 4 41214 826 827 9 0 0 01:10:18 0 172.20.20.4 4 41214 547 583 9 0 0 00:49:24 1 

Nun wollen wir sehen, welche IS-IS-Routen in der RIB des HKI-CORE-01-Routers laut Batfish enthalten sind:

 >>> isis_routes = bfq.routes(nodes='HKI-CORE-01', protocols='isis').answer().frame() >>> isis_routes Node VRF Network Next_Hop Next_Hop_IP Protocol Admin_Distance Metric Tag 0 hki-core-01 default 172.20.20.3/32 ams-core-01 10.0.0.6 isisL2 18 20 None 1 hki-core-01 default 172.20.20.1/32 ams-core-01 10.0.0.6 isisL2 18 30 None 2 hki-core-01 default 172.20.20.2/32 sth-core-01 10.0.0.4 isisL2 18 10 None 3 hki-core-01 default 172.20.20.1/32 sth-core-01 10.0.0.4 isisL2 18 30 None 4 hki-core-01 default 10.0.0.0/31 sth-core-01 10.0.0.4 isisL2 18 20 None 5 hki-core-01 default 10.0.0.2/31 ams-core-01 10.0.0.6 isisL2 18 20 None 

In der Kommandozeile:

 showroute@HKI-CORE-01# run show route table inet.0 protocol isis inet.0: 18 destinations, 18 routes (18 active, 0 holddown, 0 hidden) + = Active Route, - = Last Active, * = Both 10.0.0.0/31 *[IS-IS/18] 00:51:25, metric 20 > to 10.0.0.4 via ge-0/0/0.0 10.0.0.2/31 *[IS-IS/18] 00:51:45, metric 20 > to 10.0.0.6 via ge-0/0/1.0 172.20.20.1/32 *[IS-IS/18] 00:51:25, metric 30 to 10.0.0.4 via ge-0/0/0.0 > to 10.0.0.6 via ge-0/0/1.0 172.20.20.2/32 *[IS-IS/18] 00:51:25, metric 10 > to 10.0.0.4 via ge-0/0/0.0 172.20.20.3/32 *[IS-IS/18] 00:51:45, metric 20 > to 10.0.0.6 via ge-0/0/1.0 

Großartig! Ich nehme an, es ist Ihnen klarer geworden, dass es Batfish gibt.

Am Anfang des Artikels schrieb ich, dass Batfish verwendet werden kann, um Konfigurationsänderungen zu überprüfen, bevor sie in das "Battle" -Netzwerk übernommen werden. Jetzt schlage ich vor, den Prozess des Testens eines auf RobotFramework basierenden Netzwerks in Betracht zu ziehen . Zu diesem Zweck habe ich ein kleines Modul auf Basis von PyBatfish geschrieben, mit dem Sie die folgenden Überprüfungen durchführen können:

  • Bestimmen Sie den Status von BGP-Sitzungen im Netzwerk
  • Bestimmen Sie den IS-IS-Nachbarstatus
  • Überprüfen Sie die End-to-End-Konnektivität zwischen Knoten in einem Netzwerk mit Ablaufverfolgungsdemonstration
  • Bestimmen Sie die Größe der RIB auf dem Router für ein bestimmtes dynamisches Routing-Protokoll

LibraryBatfish.py
 import logging from pybatfish.client.commands import bf_logger, bf_init_snapshot from pybatfish.question.question import load_questions, list_questions from pybatfish.question import bfq from pybatfish.datamodel.flow import HeaderConstraints, PathConstraints from robot.api import logger class LibraryBatfish(object): def __init__(self, snapshot): bf_logger.setLevel(logging.ERROR) load_questions() bf_init_snapshot(snapshot) def check_bgp_peers(self): not_established_peers = list() bgp_peers = bfq.bgpSessionStatus().answer() for peer in bgp_peers.rows: if peer.get('Established_Status') != 'ESTABLISHED': not_established_peers.append(dict.fromkeys(peer.get('Local_IP').split(), peer.get('Remote_IP').get('value'))) if len(not_established_peers) == 0: return 1 else: logger.warn('BGP neighbors are not in an established state:') for neighborship in not_established_peers: for peer in neighborship: logger.warn('{} - {}'.format(peer, neighborship.get(peer))) return 0 def check_routes(self, node, protocol): routes = bfq.routes(nodes=node, protocols=protocol).answer() return len(routes.rows) def check_isis_neighbors(self, description): not_isis_enabled_links = list() for link in self._get_isis_enabled_links(description): if link not in self._get_isis_neighbors(): not_isis_enabled_links.append(link) if len(not_isis_enabled_links) == 0: return 1 else: for link in not_isis_enabled_links: logger.warn('{} {} has no IS-IS neighbor'.format(link.get('hostname'), link.get('interface'))) return 0 def ping(self, source_ip, destination_ip): ip_owners = bfq.ipOwners().answer() traceroute = self._get_traceroute_status(source_ip, destination_ip, ip_owners) reverse_traceroute = self._get_traceroute_status(destination_ip, source_ip, ip_owners) if traceroute == True and reverse_traceroute == True: self._show_trace(source_ip, destination_ip, ip_owners) return 1 else: logger.warn('Ping {} -> {} failed'.format(source_ip, destination_ip)) return 0 def _get_traceroute_status(self, source_ip, destination_ip, addresses): tracert = self._unidirectional_virtual_traceroute(source_ip, destination_ip, addresses) isAccepted = True if tracert != None: for trace in tracert.rows[0].get('Traces'): if trace.get('disposition') != 'ACCEPTED': isAccepted = False if isAccepted == True: return True else: return False def _get_paths(self, source_ip, destination_ip, addresses): tracert = self._unidirectional_virtual_traceroute(source_ip, destination_ip, addresses) traces = tracert.rows[0].get('Traces') paths = dict() path_number = 1 for trace in traces: if trace.get('disposition') == 'ACCEPTED': path = list() for hop in trace.get('hops'): path.append(hop.get('node').get('name')) paths[path_number] = path path_number += 1 return paths def _unidirectional_virtual_traceroute(self, source_ip, destination_ip, addresses): for address in addresses.rows: if address.get('IP') == source_ip: node = address.get('Node').get('name') int = address.get('Interface') headers = HeaderConstraints(srcIps=source_ip, dstIps=destination_ip, ipProtocols=['ICMP']) try: tracert = bfq.traceroute(startLocation="{}[{}]".format(node,int), headers=headers).answer() return tracert except: logger.warn('{} address has not been found'.format(source_ip)) def _get_isis_enabled_links(self, description='core-link'): isis_enabled_links = list() interfaces = bfq.interfaceProperties().answer() for int in interfaces.rows: if int.get('Description') != None and description in int.get('Description'): isis_enabled_links.append({'hostname' : int.get('Interface').get('hostname'), 'interface' : int.get('Interface').get('interface')}) return isis_enabled_links def _get_isis_neighbors(self): isis_neighbors = list() isis_adjacencies = bfq.edges(edgeType='isis').answer() for neighbor in isis_adjacencies.rows: isis_neighbors.append(neighbor.get('Interface')) return isis_neighbors def _show_trace(self, source_ip, destination_ip, addresses): logger.console('\nTraceroute to {} from {}'.format(destination_ip, source_ip)) paths = self._get_paths(source_ip, destination_ip, addresses) path_num = 1 for path in paths: n = 1 logger.console('\n Path N{}'.format(path_num)) for hop in paths.get(path): logger.console(' {} {}'.format(n, hop)) n += 1 path_num += 1 


batfish-test.robot
Bild

Szenario N1




Unter meiner Kontrolle befindet sich immer noch das gleiche Netzwerk. Angenommen, ich muss die Filter an der Grenze zwischen AS 41214 und AS 10631 ordnen und an den Verbindungspaketen blockieren, die Quell- oder Ziel-IP-Adressen aus dem BOGONS-Bereich enthalten.

Führen Sie den Test aus, bevor Sie Änderungen vornehmen.

Bild

Tests bestanden.

Wir werden Änderungen an der Testkonfiguration des HKI-CORE-01- Routers vornehmen - /tmp/habr/configs/HKI-CORE-01.cfg:

 set firewall family inet filter BOGONS term TERM010 from address 0.0.0.0/8 set firewall family inet filter BOGONS term TERM010 from address 10.0.0.0/8 set firewall family inet filter BOGONS term TERM010 from address 100.64.0.0/10 set firewall family inet filter BOGONS term TERM010 from address 127.0.0.0/8 set firewall family inet filter BOGONS term TERM010 from address 169.254.0.0/16 set firewall family inet filter BOGONS term TERM010 from address 172.16.0.0/12 set firewall family inet filter BOGONS term TERM010 from address 192.0.2.0/24 set firewall family inet filter BOGONS term TERM010 from address 192.88.99.0/24 set firewall family inet filter BOGONS term TERM010 from address 192.168.0.0/16 set firewall family inet filter BOGONS term TERM010 from address 198.18.0.0/15 set firewall family inet filter BOGONS term TERM010 from address 198.51.100.0/24 set firewall family inet filter BOGONS term TERM010 from address 203.0.113.0/24 set firewall family inet filter BOGONS term TERM010 from address 224.0.0.0/4 set firewall family inet filter BOGONS term TERM010 from address 240.0.0.0/4 set firewall family inet filter BOGONS term TERM010 then discard set firewall family inet filter BOGONS term PERMIT-IP-ANY-ANY then accept set interfaces ge-0/0/2.0 family inet filter input BOGONS set interfaces ge-0/0/2.0 family inet filter output BOGONS 

Führen Sie den Test aus.



Ich war sehr nah dran, aber wie die Testausgabe zeigt, befindet sich die Nachbarschaft 192.168.30.0 - 192.168.30.1 nach den vorgenommenen BGP-Änderungen nicht im Status "Etabliert" -> Infolgedessen geht die IP-Konnektivität zwischen den Punkten 135.65.0.1 <-> 140.0.0.1 verloren. Was ist los Wir sehen uns die HKI-CORE-01- Konfiguration genau an und stellen fest, dass eBGP-Peering auf privaten Adressen installiert ist:

 showroute@HKI-CORE-01# show interfaces ge-0/0/2 | display set set interfaces ge-0/0/2 description SPB-CORE-01 set interfaces ge-0/0/2 unit 0 family inet filter input BOGONS set interfaces ge-0/0/2 unit 0 family inet filter output BOGONS set interfaces ge-0/0/2 unit 0 family inet address 192.168.30.0/31 

Schlussfolgerung: Es ist erforderlich, die Adressen an der Kreuzung zu ändern oder das Subnetz 192.168.30.0/31 zur Ausnahme hinzuzufügen.

Ich werde der Ausnahme ein Netzwerk an der Kreuzung hinzufügen und /tmp/habr/configs/HKI-CORE-01.cfg erneut aktualisieren:

 set firewall family inet filter BOGONS term TERM005 from address 192.168.0.0/31 set firewall family inet filter BOGONS term TERM005 then accept 

Führen Sie den Test aus.



Jetzt wird unerwünschter Datenverkehr nicht mehr über die ebgp-Schnittstelle AS 41214 - AS 10631 geleitet. Sie können ohne Änderungen sicher Konsequenzen ändern.

Szenario N2




Hier muss ich das Netzwerk 150.0.0.0/24 auf dem MSK-CORE-01- Router beenden und die Konnektivität zwischen den Punkten 135.65.0.1 und 150.0.0.1 sicherstellen

Ich füge der Testkonfiguration des MSK-CORE-01-Routers die folgenden Zeilen hinzu: tmp / habr / configs / MSK-CORE-01.cfg:

 interface Loopback2 ip address 150.0.0.1 255.255.255.255 ! ip route 150.0.0.0 255.255.255.0 Null0 ! router bgp 10631 ! address-family ipv4 network 150.0.0.0 mask 255.255.255.0 ! 

Ich ändere das Testskript und führe den Test aus:

 git diff HEAD~ diff --git a/batfish-robot.robot b/batfish-robot.robot index 8d963c5..ce8cb6a 100644 --- a/batfish-robot.robot +++ b/batfish-robot.robot @@ -5,7 +5,7 @@ Library LibraryBatfish.py tmp/habr ${ISIS-ENABLED-LINK-DESCRIPTION} ISIS-LINK ${NODE} HKI-CORE-01 ${PROTOCOL} ebgp -${RIB-SIZE} 1 +${RIB-SIZE} 2 *** Test Cases *** ISIS @@ -27,3 +27,8 @@ Ping [Documentation] Test end-to-end ICMP connectivity & show traceroute ${result}= Ping 135.65.0.1 140.0.0.1 Should Be Equal As Integers ${result} 1 + +Ping2 + [Documentation] Test end-to-end ICMP connectivity & show traceroute + ${result}= Ping 135.65.0.1 150.0.0.1 + Should Be Equal As Integers ${result} 1 

Jetzt erwarte ich zwei eBGP-Routen auf dem HKI-CORE-01-Router. Eine zusätzliche Konnektivitätsprüfung wird hinzugefügt



Es besteht keine Verbindung zwischen 135.65.0.1 und 150.0.0.1. Außerdem gibt es auf dem HKI-CORE-01- Router nur eine eBGP-Route anstelle von zwei.

Überprüfen Sie den Inhalt der RIB auf dem HKI-CORE-01, wenn Sie dem MSK-CORE-01- Router eine neue Konfiguration hinzufügen:

 showroute@HKI-CORE-01# run show route table inet.0 protocol bgp inet.0: 20 destinations, 20 routes (19 active, 0 holddown, 1 hidden) + = Active Route, - = Last Active, * = Both 135.65.0.0/19 *[BGP/170] 02:25:38, MED 0, localpref 100, from 172.20.20.1 AS path: I, validation-state: unverified > to 10.0.0.4 via ge-0/0/0.0 to 10.0.0.6 via ge-0/0/1.0 140.0.0.0/24 *[BGP/170] 01:38:02, localpref 100 AS path: 10631 I, validation-state: unverified > to 192.168.30.1 via ge-0/0/2.0 showroute@HKI-CORE-01# run show route table inet.0 protocol bgp hidden detail inet.0: 20 destinations, 20 routes (19 active, 0 holddown, 1 hidden) 150.0.0.0/24 (1 entry, 0 announced) BGP /-101 Next hop type: Router, Next hop index: 563 Address: 0x940f43c Next-hop reference count: 4 Source: 192.168.30.1 Next hop: 192.168.30.1 via ge-0/0/2.0, selected Session Id: 0x9 State: <Hidden Ext> Local AS: 41214 Peer AS: 10631 Age: 1:42:03 Validation State: unverified Task: BGP_10631.192.168.30.1+179 AS path: 10631 I Localpref: 100 Router ID: 10.68.1.1 Hidden reason: rejected by import policy 

Beachten Sie die Importrichtlinie für Präfixe, die von SPB-CORE-01 empfangen wurden:

 set protocols bgp group AS10631 import FROM-AS10631 set protocols bgp group AS10631 neighbor 192.168.30.1 description SPB-CORE-01 set protocols bgp group AS10631 neighbor 192.168.30.1 peer-as 10631 set policy-options policy-statement FROM-AS10631 term TERM010 from route-filter 140.0.0.0/24 exact set policy-options policy-statement FROM-AS10631 term TERM010 then accept set policy-options policy-statement FROM-AS10631 term DENY then reject 

Die Regel, die 150.0.0.0/24 zulässt, fehlt. Fügen Sie es der Testkonfiguration hinzu und führen Sie den Test aus:

 showroute@HKI-CORE-01# show | compare [edit policy-options policy-statement FROM-AS10631 term TERM010 from] route-filter 140.0.0.0/24 exact { ... } + route-filter 150.0.0.0/24 exact; [edit] 



Großartig, es gibt Konnektivität zwischen den Netzwerken, alle Tests sind bestanden! Sie können diese Änderungen also an der Arbeit des "Kampf" -Netzwerks vornehmen.

Fazit


Meiner Meinung nach ist Batfish ein mächtiges Werkzeug mit großem Potenzial. Probieren Sie es aus und überzeugen Sie sich selbst.

Wenn dieses Thema für Sie interessant ist - nehmen Sie am Slack-Chat teil. Die Batfish-Entwickler beantworten gerne alle Fragen und beheben Fehler schnell.

batfish-org.slack.com

Danke für die Aufmerksamkeit.

Referenzen


www.batfish.org

www.youtube.com/channel/UCA-OUW_3IOt9U_s60KvmJYA

github.com/batfish/batfish

media.readthedocs.org/pdf/pybatfish/latest/pybatfish.pdf

github.com/showroute/batfish-habr

Source: https://habr.com/ru/post/de441532/


All Articles