Batfishред рдкрд░рд┐рдЪрдп

рдЫрд╡рд┐

рдЖрдзреБрдирд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдХреА рд╕рдорд╕реНрдпрд╛рдУрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдЙрдирдХреА рдирд╛рдЬреБрдХрддрд╛ рд╣реИред рдХрдИ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдирд┐рдпрдо, рд╕реВрдЪрдирд╛ рд╡рд┐рдирд┐рдордп рдиреАрддрд┐рдпрд╛рдВ, рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдЯрд┐рдВрдЧ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рднреНрд░рдорд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдорд╛рдирд╡ рдХрд╛рд░рдХреЛрдВ рдХреЗ рдЕрдзреАрди рд╣реЛрддреЗ рд╣реИрдВред рд░реВрдЯ-рдореИрдк рдпрд╛ ACL ( рдПрдХ , рджреЛ ) рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░рддреЗ рд╕рдордп рдПрдХ рдиреЗрдЯрд╡рд░реНрдХ рджреБрд░реНрдШрдЯрдирд╛ рдЕрдирдЬрд╛рдиреЗ рдореЗрдВ рд╣реЛ рд╕рдХрддреА рд╣реИред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рдирдП рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдХрд░рдг рдХреА рдХрдореА рд╣реИред рдореИрдВ рдареАрдХ рд╕реЗ рдЬрд╛рдирдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдХреНрдпрд╛ рдкреНрд░рджрд╛рддрд╛ рдмреА рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдмреАрдЬреАрдкреА рдШреЛрд╖рдгрд╛рдУрдВ рдореЗрдВ рд╕реЗ рдХреБрдЫ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдкрд░ рдиреЗрдЯрд╡рд░реНрдХ рдП рдореЗрд░реЗ рдкрд╛рд╕ рдЙрдкрд▓рдмреНрдз рд╣реЛрдЧрд╛? рдкреИрдХреЗрдЯреНрд╕ рдиреЗрдЯрд╡рд░реНрдХ C рд╕реЗ рд╕рд░реНрд╡рд░ D рддрдХ рдХрд┐рд╕ рдорд╛рд░реНрдЧ рд╕реЗ рдЬрд╛рдПрдВрдЧреЗ рдЕрдЧрд░ рдХрд┐рд╕реА рдПрдХ рдЯреНрд░рд╛рдВрдЬрд┐рдЯ рд▓рд┐рдВрдХ рдкрд░ рдореИрдВ IGP рдореАрдЯреНрд░рд┐рдХ рджреЛрдЧреБрдирд╛ рдХрд░ рджреЗрддрд╛ рд╣реВрдВ? рдмреИрдЯрдлрд┐рд╢ рд╣рдореЗрдВ рдЗрди рдФрд░ рдХрдИ рдЕрдиреНрдп рд╕рд╡рд╛рд▓реЛрдВ рдХреЗ рдЬрд╡рд╛рдм рджреЗрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧреА!

рдмреИрдЯрдлрд┐рд╢ рдХреА рд╕рдореАрдХреНрд╖рд╛


рдмреИрдЯрдлрд┐рд╢ рдПрдХ рдиреЗрдЯрд╡рд░реНрдХ рдореЙрдбрд▓рд┐рдВрдЧ рдЯреВрд▓ рд╣реИред рдЗрд╕рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рдЙрддреНрдкрд╛рджрди рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд▓рд┐рдП рдЙрдиреНрд╣реЗрдВ рдмрдирд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рд╣реИред рдмреИрдЯрдлрд┐рд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдиреЗрдЯрд╡рд░реНрдХ рдХреА рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдФрд░ рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдиреЗрдЯрд╡рд░реНрдХ рдХреА рджреБрдирд┐рдпрд╛ рдореЗрдВ рдореМрдЬреВрджрд╛ CI / CD рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдореЗрдВ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирдП рд╡рд┐рдиреНрдпрд╛рд╕реЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдХрд░рдг рдХрд╛ рдЕрднрд╛рд╡ рд╣реИред рдмреИрдЯрдлрд┐рд╢ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддреА рд╣реИред

рдмреИрдЯрдлрд┐рд╢ рдХреЛ рдореМрдЬреВрджрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдЙрдкрдХрд░рдг рддрдХ рд╕реАрдзреЗ рд╕реАрдзреЗ рдкрд╣реБрдВрдЪ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рдмреИрдЯрдлрд┐рд╢ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдирд┐рд╣рд┐рдд рдбреЗрдЯрд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдиреЗрдЯрд╡рд░реНрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдореЙрдбрд▓ рдХрд░рддрд╛ рд╣реИред

рдмреИрдЯрдлрд┐рд╢ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

  • рдиреЗрдЯрд╡рд░реНрдХ рдореЗрдВ рдЧрддрд┐рд╢реАрд▓ рд░реВрдЯрд┐рдВрдЧ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреА рдкрдбрд╝реЛрд╕реА рд╕реНрдерд┐рддрд┐ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ (рдмреАрдЬреАрдкреА, рдЖрдИрдПрд╕-рдЖрдИрдПрд╕, рдУрдПрд╕рдкреАрдПрдл)
  • рдкреНрд░рддреНрдпреЗрдХ рдиреЗрдЯрд╡рд░реНрдХ рддрддреНрд╡ рдХреЗ рдЖрд░рдЖрдИрдмреА рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ
  • NTP, AAA, MTU рд╕реЗрдЯрд┐рдВрдЧ рдЬрд╛рдВрдЪреЗрдВ
  • рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдПрд╕реАрдПрд▓ рдиреЗрдЯрд╡рд░реНрдХ рдЯреНрд░реИрдлрд┐рдХ рдХреЗ рдорд╛рд░реНрдЧ рдХреЛ рдЕрд╡рд░реБрджреНрдз рдХрд░рддрд╛ рд╣реИ (рд╕рд┐рд╕реНрдХреЛ рдПрдПрд╕рдП рдкрд░ рдкреИрдХреЗрдЯ-рдЯреНрд░реЗрд╕рд░ рдХрд╛ рдПрдирд╛рд▓реЙрдЧ)
  • рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рднреАрддрд░ рдореЗрдЬрдмрд╛рди рдХреЗ рдмреАрдЪ рдПрдВрдб-рдЯреВ-рдПрдВрдб рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдХреЗ рд▓рд┐рдП рдЬрд╛рдБрдЪ рдХрд░реЗрдВ
  • рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЯреНрд░реИрдлрд╝рд┐рдХ рдХрд╛ рдорд╛рд░реНрдЧ рджрд┐рдЦрд╛рдПрдВ (рд╡рд░реНрдЪреБрдЕрд▓ рдЯреНрд░реЗрд╕рд┐рдВрдЧ)


рд╕рдорд░реНрдерд┐рдд рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо:

  • рдЕрдиреНрди рдпрд╛ рдШрд╛рд╕ рдХреА рдмрд╛рд▓
  • рдЕрд░реВрдмрд╛
  • AWS (VPCs, рдиреЗрдЯрд╡рд░реНрдХ ACLs, VPN GW, NAT GW, рдЗрдВрдЯрд░рдиреЗрдЯ GW, рд╕реБрд░рдХреНрд╖рд╛ рд╕рдореВрд╣)
  • рд╕рд┐рд╕реНрдХреЛ (NX-OS, IOS, IOS-XE, IOS-XR рдФрд░ ASA)
  • рдбреЗрд▓ рдмрд▓ 10
  • рдлрд╛рдЙрдВрдбреНрд░реА
  • iptables
  • рдЬреБрдирд┐рдкрд░ (рдПрдордПрдХреНрд╕, рдИрдПрдХреНрд╕, рдХреНрдпреВрдПрдлрдПрдХреНрд╕, рдПрд╕рдЖрд░рдПрдХреНрд╕, рдЯреА-рд╕реАрд░реАрдЬрд╝, рдкреАрдЯреАрдПрдХреНрд╕)
  • MRV
  • рдкрд╛рд▓реЛ рдЕрд▓реНрдЯреЛ рдиреЗрдЯрд╡рд░реНрдХ
  • рдХреБрдЧреНрдЧрд╛ / рдПрдлрдЖрд░рдЖрд░
  • рдХреНрд╡рд╛рдВрдЯрд╛
  • VyOS

рдЫрд╡рд┐

рдмреИрдЯрдлрд┐рд╢ рдПрдХ рдЬрд╛рд╡рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИред рдЗрд╕рдХреЗ рд╕рд╛рде рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдкрд╛рдпрдмреЗрдЯрдлрд╝рд┐рд╢ - рдЕрдЬрдЧрд░ рдПрд╕рдбреАрдХреЗ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛ред

рдЕрднреНрдпрд╛рд╕ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред рдореИрдВ рдЖрдкрдХреЛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рдмреИрдЯрдлрд┐рд╢ рдХреА рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдХреЛ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ред

рдЙрджрд╛рд╣рд░рдг


рд╣рдо рджреЛ рд╕реНрд╡рд╛рдпрддреНрдд рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рддреЗ рд╣реИрдВ: 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 рдХреА рдШреЛрд╖рдгрд╛ рдХреАред рд╕реНрд╡рд╛рдпрддреНрдд рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рд░реВрдЯрд┐рдВрдЧ рд╕реВрдЪрдирд╛рдУрдВ рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдПрдЪрдХреЗрдЖрдИ-рдХреЛрд░ -01 - рдПрд╕рдкреАрдмреА-рдХреЛрд░ -01 рдХреЗ рдЬрдВрдХреНрд╢рди рдкрд░ рд╣реЛрддрд╛ рд╣реИред

HKI-CORE-01, STH-CORE-01 - рдЬреВрдиреЛрд╕ рд░реВрдЯрд░реНрд╕
LDN-CORE-01, AMS-CORE-01, SPB-CORE-01, MSK-CORE-01 - рд╕рд┐рд╕реНрдХреЛ IOS рд░реВрдЯрд░реНрд╕



рдмрдЯрдлрд╝рд┐рд╢ рдФрд░ рдЕрдЬрдЧрд░ рдПрд╕рдбреАрдХреЗ рдХреЗ рд╕рд╛рде рдХрдВрдЯреЗрдирд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:

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

рдкрд╛рдпрдерди рдЗрдВрдЯрд░реЗрдХреНрдЯрд┐рд╡ рдореЛрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП:

 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') - рдлрд╝рдВрдХреНрд╢рди рдмреИрдЯрдлрд╝рд┐рд╢ рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд░рддрд╛ рд╣реИред

/ tmp / habr - рд░рд╛рдЙрдЯрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ред

 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 

рдЕрдм LDN-CORE-01 рд░рд╛рдЙрдЯрд░ рдкрд░ BGP рд╕рддреНрд░реЛрдВ рдХреА рд╕реНрдерд┐рддрд┐ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ:

 >>> 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#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 

рдЕрдм рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдЖрдИрдПрд╕рдЖрдИ-рдЖрдИрдПрд╕ рдорд╛рд░реНрдЧ рдмрд╛рдмреАрдлрд╝рд┐рд╢ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдПрдЪрдЖрдИрдЖрдИ-рдХреЛрд░ -01 рд░рд╛рдЙрдЯрд░ рдкрд░ рдЖрд░рдЖрдИрдмреА рдореЗрдВ рдХреНрдпрд╛ рд╣реИрдВ:

 >>> 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# 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 

рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛! рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЖрдкрдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдмреИрдЯрдлрд┐рд╢ рд╣реИред

рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ, рдореИрдВрдиреЗ рд▓рд┐рдЦрд╛ рдХрд┐ рдмреИрдЯрдлрд┐рд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ "рд▓рдбрд╝рд╛рдИ" рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рд▓рд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЕрдм рдореИрдВ рд░реЛрдмреЛрдЯрдлреНрд░реЗрдорд╡рд░реНрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдиреЗрдЯрд╡рд░реНрдХ рдкрд░реАрдХреНрд╖рдг рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдХрд░рддрд╛ рд╣реВрдВ ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ PyBatfish рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдПрдХ рдЫреЛрдЯрд╛ рдореЙрдбреНрдпреВрд▓ рд▓рд┐рдЦрд╛ рдЬреЛ рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ:

  • рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдмреАрдЬреАрдкреА рд╕рддреНрд░реЛрдВ рдХреА рд╕реНрдерд┐рддрд┐ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ
  • рдЖрдИрдПрд╕-рдЖрдИрдПрд╕ рдкрдбрд╝реЛрд╕реА рдХреА рд╕реНрдерд┐рддрд┐ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ
  • рдЯреНрд░реЗрд╕ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд╕рд╛рде рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдиреЛрдбреНрд╕ рдХреЗ рдмреАрдЪ рдПрдВрдб-рдЯреВ-рдПрдВрдб рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ
  • рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдбрд╛рдпрдирд╛рдорд┐рдХ рд░реВрдЯрд┐рдВрдЧ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рд▓рд┐рдП рд░рд╛рдЙрдЯрд░ рдкрд░ рдЖрд░рдЖрдИрдмреА рдХрд╛ рдЖрдХрд╛рд░ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ

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
рдЫрд╡рд┐

рдкрд░рд┐рджреГрд╢реНрдп N рез




рдореЗрд░реЗ рдирд┐рдпрдВрддреНрд░рдг рдореЗрдВ рдЕрдм рднреА рд╡рд╣реА рдиреЗрдЯрд╡рд░реНрдХ рд╣реИред рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдореБрдЭреЗ 41214 рдФрд░ AS 10631 рдХреА рд╕реАрдорд╛ рдкрд░ рдлрд┐рд▓реНрдЯрд░ рд▓рдЧрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ 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 

рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдВред



рдореИрдВ рдмрд╣реБрдд рдХрд░реАрдм рдерд╛, рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдг рдЖрдЙрдЯрдкреБрдЯ рд╢реЛ рдХреЗ рд░реВрдк рдореЗрдВ, рдмреАрдЬреАрдкреА рдореЗрдВ рдХрд┐рдП рдЧрдП рдмрджрд▓рд╛рд╡реЛрдВ рдХреЗ рдмрд╛рдж, рдкрдбрд╝реЛрд╕ 192.168.30.0 - 192.168.30.1 рд╕реНрдерд╛рдкрд┐рдд рд░рд╛рдЬреНрдп рдореЗрдВ рдирд╣реАрдВ рд╣реИ -> рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЕрдВрдХ 135.65.1.1 <-> 140.0.0.1 рдХреЗ рдмреАрдЪ рдЖрдИрдкреА рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдЦреЛ рдЬрд╛рддреА рд╣реИред рдХреНрдпрд╛ рдЧрд▓рдд рд╣реИ? рд╣рдо HKI-CORE-01 рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдзреНрдпрд╛рди рд╕реЗ рджреЗрдЦрддреЗ рд╣реИрдВ рдФрд░ рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ eBGP peering рдирд┐рдЬреА рдкрддреЗ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рд╣реИ:

 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 

рдирд┐рд╖реНрдХрд░реНрд╖: рдЬрдВрдХреНрд╢рди рдкрд░ рдкрддреЛрдВ рдХреЛ рдмрджрд▓рдирд╛ рдпрд╛ рдЕрдкрд╡рд╛рдж рдХреЗ рд▓рд┐рдП 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 рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд╣реАрдВ рдЬрд╛рдПрдЧрд╛ 41214 - AS 10631 рдХреЗ рд░реВрдк рдореЗрдВред рдЖрдк рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рдбрд░ рдХреЗ рдмрд┐рдирд╛ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдмрджрд▓рд╛рд╡ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдкрд░рд┐рджреГрд╢реНрдп N2




рдпрд╣рд╛рдВ рдореБрдЭреЗ MSK-CORE-01 рд░рд╛рдЙрдЯрд░ рдкрд░ рдиреЗрдЯрд╡рд░реНрдХ 150.0.0.0/24 рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдЕрдВрдХ 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 

рдЕрдм рдореБрдЭреЗ HKI-CORE-01 рд░рд╛рдЙрдЯрд░ рдкрд░ рджреЛ eBGP рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рджреЗрдЦрдиреЗ рдХреА рдЙрдореНрдореАрдж рд╣реИ, рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдЪреЗрдХ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ



135.65.0.1 рдФрд░ 150.0.0.1 рдХреЗ рдмреАрдЪ рдХреЛрдИ рд╕рдВрдмрдВрдз рдирд╣реАрдВ рд╣реИ, рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, HKI-CORE-01 рд░рд╛рдЙрдЯрд░ рдкрд░ рджреЛ рдХреЗ рдмрдЬрд╛рдп рдХреЗрд╡рд▓ рдПрдХ рдИрдЬреАрдЬреАрдкреА рдорд╛рд░реНрдЧ рд╣реИред

MSK-CORE-01 рд░рд╛рдЙрдЯрд░ рдореЗрдВ рдПрдХ рдирдпрд╛ рд╡рд┐рдиреНрдпрд╛рд╕ рдЬреЛрдбрд╝рдиреЗ рдкрд░ HKI-CORE-01 рдкрд░ RIB рдХреА рд╕рд╛рдордЧреНрд░реА рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:

 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 

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# 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] 



рдорд╣рд╛рди, рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдмреАрдЪ рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рд╣реИ, рд╕рднреА рдкрд░реАрдХреНрд╖рдг рдкрд╛рд░рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ! рддреЛ рдЖрдк рдЗрди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ "рдореБрдХрд╛рдмрд▓рд╛" рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдХрд╛рдо рдореЗрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдирд┐рд╖реНрдХрд░реНрд╖


рдореЗрд░реА рд░рд╛рдп рдореЗрдВ, рдмрддреНрддреАрдлрд╝рд┐рд╢ рдПрдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЙрдкрдХрд░рдг рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдмрдбрд╝реА рдХреНрд╖рдорддрд╛ рд╣реИред рдЗрд╕реЗ рдЖрдЬрд╝рдорд╛рдПрдВ рдФрд░ рдЕрдкрдиреЗ рд▓рд┐рдП рджреЗрдЦреЗрдВред

рдпрджрд┐ рдпрд╣ рд╡рд┐рд╖рдп рдЖрдкрдХреЗ рд▓рд┐рдП рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ - рд╕реБрд╕реНрдд рдЪреИрдЯ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдВ, рддреЛ рдмреИрдЯрдлрд╝рд┐рд╢ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХрд┐рд╕реА рднреА рдкреНрд░рд╢реНрди рдХрд╛ рдЙрддреНрддрд░ рджреЗрдиреЗ рдФрд░ рдХреАрдбрд╝реЗ рдХреЛ рдЬрд▓реНрджреА рдареАрдХ рдХрд░рдиреЗ рдореЗрдВ рдкреНрд░рд╕рдиреНрди рд╣реЛрдВрдЧреЗред

batfish-org.slack.com

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

рд╕рдВрджрд░реНрдн


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/hi441532/


All Articles