
واحدة من مشاكل الشبكات الحديثة هي هشاشتها. العديد من قواعد التصفية ، وسياسات تبادل المعلومات الخاصة بالتوجيه ، وبروتوكولات التوجيه الديناميكية تجعل الشبكات مربكة وتخضع للعوامل البشرية. يمكن أن يحدث تعطل الشبكة عن غير قصد عند إجراء تغييرات على خريطة الطريق أو ACL (
واحد أو
اثنين ). نفتقر بالتأكيد إلى أداة لتقييم سلوك الشبكة بتكوين جديد قبل إجراء تغييرات على الإنتاج. أريد أن أعرف بالضبط ما إذا كانت الشبكة "أ" ستكون متاحة لي إذا قمت بتصفية بعض إعلانات BGP الواردة من الموفر ب؟ ما الطريق الذي ستنتقل به الحزم من الشبكة C إلى الخادم D إذا قمت بمضاعفة مقياس IGP على أحد روابط النقل؟ سوف تساعدنا أسماك القرش في الإجابة على هذه الأسئلة والعديد من الأسئلة الأخرى!
استعراض سمك السلور
أسماك القرش هي أداة لنمذجة الشبكة. الغرض الرئيسي منه هو اختبار تغييرات التكوين قبل تحويلها إلى شبكة الإنتاج. يمكن استخدام أسماك القرش أيضًا لتحليل الوضع الحالي للشبكة والتحقق منه. من الواضح أن عمليات CI / CD الحالية في عالم الشبكات تفتقر إلى أداة لاختبار التكوينات الجديدة. سمك السلور يحل هذه المشكلة.
لا يتطلب Batfish الوصول المباشر المباشر إلى معدات الشبكة الحالية ، يقوم Batfish بنماذج سلوك الشبكة استنادًا إلى البيانات الموجودة في ملفات تكوين الجهاز.
يمكن لسمكة البحر:
- تحديد حالة الجوار لبروتوكولات التوجيه الديناميكية في الشبكة (BGP ، IS-IS ، OSPF)
- حساب RIB لكل عنصر شبكة
- تحقق من إعدادات NTP و AAA و MTU
- السماح بتحديد ما إذا كانت قائمة التحكم في الوصول (ACL) تمنع مرور حركة مرور الشبكة (تمثيلية تتبع الحزمة على Cisco ASA)
- تحقق من الاتصال من طرف إلى طرف بين المضيفين داخل الشبكة
- عرض مسار حركة المرور عبر الشبكة (التتبع الافتراضي)
المنصات المدعومة:
- أريستا
- أروبا
- AWS (VPCs ، ACLs للشبكة ، VPN GW ، NAT GW ، الإنترنت GW ، مجموعات الأمان)
- Cisco (NX-OS و IOS و IOS-XE و IOS-XR و ASA)
- Dell force10
- مسبك
- iptables
- العرعر (MX ، EX ، QFX ، SRX ، سلسلة T ، PTX)
- Mrv
- شبكات بالو ألتو
- Quagga / FRR
- كوانتا
- فيوس

سمكة البحر هو تطبيق جافا. للعمل مريحة معها تمت كتابة Pybatfish - بيثون SDK.
دعنا ننتقل إلى الممارسة. سأريكم إمكانيات Batfish مع مثال.
مثال
ندير نظامين مستقلين: AS 41214 و AS 10631. كما IGP ، AS-41214 يستخدم IS-IS ، و AS-10631 - OSPF. داخل كل AS ، يتم استخدام IBGP-fullmesh. تعلن LDN-CORE-01 عن بادئة الجوار لـ BGP 135.65.0.0/19 ، MSK-CORE-01 - 140.0.0.0/24. يحدث تبادل معلومات التوجيه بين الأنظمة المستقلة عند تقاطع HKI-CORE-01 - SPB-CORE-01.
HKI-CORE-01 ، STH-CORE-01 - أجهزة توجيه Junos
LDN-CORE-01 ، AMS-CORE-01 ، SPB-CORE-01 ، MSK-CORE-01 - أجهزة توجيه Cisco IOS

تثبيت الحاوية مع Batfish والثعبان SDK:
docker pull batfish/allinone docker run batfish/allinone docker container exec -it <container> bash
تعرف على المكتبة من خلال الوضع التفاعلي بيثون:
root@ea9a1559d88e:/
bf_init_snapshot ('tmp / habr') - تقوم الوظيفة بتحميل ملفات التكوين في Batfish وتعدها للتحليل.
/ tmp / habr - دليل مع ملفات تكوين جهاز التوجيه.
root@ea9a1559d88e:/tmp/habr
الآن دعونا نحدد حالة جلسات BGP على جهاز التوجيه LDN-CORE-01:
>>> 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
حسنا كيف؟ يبدو وكأنه الحقيقة؟
LDN-CORE-01
الآن دعنا نرى ما هي طرق IS-IS الموجودة في RIB على جهاز التوجيه HKI-CORE-01 وفقًا لـ Batfish:
>>> 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
في سطر الأوامر:
showroute@HKI-CORE-01
عظيم! أفترض أنه أصبح أكثر وضوحا لك أن هناك سمكة الباتفيش.
في بداية المقال ، كتبت أنه يمكن استخدام Batfish للتحقق من تغييرات التكوين قبل إجرائها على شبكة "المعركة". الآن أقترح دراسة عملية اختبار الشبكة بناءً على
RobotFramework . لهذا ، كتبت وحدة صغيرة قائمة على PyBatfish تسمح لك بإجراء الاختبارات التالية:
- تحديد حالة جلسات BGP على الشبكة
- تحديد حالة الجوار IS-IS
- تحقق من الاتصال من طرف إلى طرف بين العقد على شبكة مع العرض التوضيحي التتبع
- تحديد حجم RIB على جهاز التوجيه لبروتوكول توجيه ديناميكي معين
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
السيناريو N1

تحت سيطرتي لا تزال نفس الشبكة. افترض أنني بحاجة إلى ترتيب الفلاتر على حدود
AS 41214 و
AS 10631 وحظرها في حزم الوصلات التي تحتوي على عناوين IP للمصدر أو الوجهة من نطاق BOGONS.
قم بإجراء الاختبار قبل إجراء التغييرات.

مرت الاختبارات.
سنجري تغييرات على تكوين الاختبار لجهاز التوجيه
HKI-CORE-01 - /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
قم بإجراء الاختبار.

لقد كنت قريبًا جدًا ، ولكن كما يوضح ناتج الاختبار ، بعد إجراء تغييرات BGP ، لم يكن الحي 192.168.30.0 - 192.168.30.1 في حالة التأسيس -> ونتيجة لذلك ، فقد اتصال IP بين النقاط 135.65.0.1 <-> 140.0.0.1. ما هو الخطأ؟ ننظر بعناية في تكوين
HKI-CORE-01 ونرى أن نظير eBGP مثبت على عناوين خاصة:
showroute@HKI-CORE-01
الخلاصة: من الضروري تغيير العناوين عند التقاطع أو إضافة الشبكة الفرعية 192.168.30.0/31 إلى الاستثناء.
سأضيف شبكة عند التقاطع إلى الاستثناء ، سأقوم بتحديث /tmp/habr/configs/HKI-CORE-01.cfg مرة أخرى:
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
قم بإجراء الاختبار.

الآن لن تمر حركة المرور غير المرغوب فيها من خلال واجهة ebgp AS 41214 - AS 10631. يمكنك إجراء تغييرات بأمان دون خوف من العواقب.
السيناريو N2

أحتاج هنا إلى إنهاء الشبكة 150.0.0.0/24 على جهاز التوجيه
MSK-CORE-01 وضمان الاتصال بين النقطتين 135.65.0.1 و 150.0.0.1
أقوم بإضافة الأسطر التالية إلى تكوين اختبار جهاز التوجيه MSK-CORE-01 - 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 !
يمكنني تغيير البرنامج النصي للاختبار وتشغيل الاختبار:
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
الآن أتوقع رؤية طريقين eBGP على جهاز التوجيه HKI-CORE-01 ، تتم إضافة فحص اتصال إضافي
لا يوجد اتصال بين 135.65.0.1 و 150.0.0.1 ، علاوة على ذلك ، يوجد على جهاز التوجيه
HKI-CORE-01 مسار eBGP واحد فقط ، بدلاً من مسارين.
تحقق من محتويات RIB على
HKI-CORE-01 عند إضافة تكوين جديد إلى جهاز التوجيه
MSK-CORE-01 :
showroute@HKI-CORE-01
لاحظ سياسة الاستيراد للبادئات الواردة من
SPB-CORE-01 :
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
قاعدة السماح 150.0.0.0/24 مفقود. إضافته إلى تكوين الاختبار وتشغيل الاختبار:
showroute@HKI-CORE-01

عظيم ، هناك اتصال بين الشبكات ، يتم اجتياز جميع الاختبارات! حتى تتمكن من إجراء هذه التغييرات على عمل شبكة "القتال".
الخاتمة
في رأيي ، باتفيش هو أداة قوية مع إمكانات هائلة. جربها وانظر لنفسك.
إذا كان هذا الموضوع مثيراً للاهتمام لك - الانضمام إلى الدردشة القصيرة ، سيسعد مطورو Batfish بالإجابة على أي أسئلة وإصلاح الأخطاء بسرعة.
batfish-org.slack.comشكرا لاهتمامكم
المراجع
www.batfish.orgwww.youtube.com/channel/UCA-OUW_3IOt9U_s60KvmJYAgithub.com/batfish/batfishmedia.readthedocs.org/pdf/pybatfish/latest/pybatfish.pdfgithub.com/showroute/batfish-habr