def test_controlplane(isFailed): # Define a list of Spine switches spines = set(bfq.nodeProperties(nodes='spine.*').answer().frame()['Node']) logging.info("Progress: Analyzing control plane properties") # Get all BGP session status for leaf nodes bgp = bfq.bgpSessionStatus(nodes='leaf.*').answer().frame() # All leaves should have at least one peering with each spine violators = bgp.groupby('Node').filter( lambda x: set(x['Remote_Node']).difference(spines) != set([])) if len(violators) > 0: logging.error( "Found leaves that do not have at least one peering to each spine") logging.error(violators[['Node', 'Remote_Node']]) isFailed = True else: logging.info("All leaves have at least one peering with each spine") # All leaves should only peer with spines non_spines = bgp[~bgp['Remote_Node'].str.contains('spine', na=False)] if len(non_spines) > 0: logging.error("Leaves do not only peer with spines") logging.error(non_spines[['Node', 'Remote_Node']]) isFailed = True else: logging.info("Leaves only peer with spines") return isFailed
def plot_bgp_graph(): """ This function extracts BGP session compatibility and plots a graph of BGP neighborships. """ # Run batfish query to identify BGP neighbors bgpneigh = bfq.bgpSessionStatus().answer().frame() # Conditional check to ensure the BGP session list is not empty if bgpneigh.empty: print(Fore.RED + " ==> NO BGP NEIGHBORS FOUND") else: print(Fore.YELLOW + " ==> PLOTTING BGP GRAPH") bgpneigh_json = json.loads(bgpneigh.to_json(orient="index")) # Initialise list to track nodes that are already plotted. mapped_node = [] # Initialise list to track links that are already plotted mapped_link_list = [] # initialise a drawing named BGP diagram.add_diagram("BGP") for key in bgpneigh_json: # Initialise local list to map current link and reverse of current link. current_link = [] current_link_reverse = [] # Extract details of the neighbor neighbor = bgpneigh_json[key] # Extract node id and remote node if of each neighbor node_id = f'{neighbor["Node"]}\n({neighbor["Local_AS"]})' remote_node_id = f'{neighbor["Remote_Node"]}\n({neighbor["Remote_AS"]})' # Check if node has already been plotted # plot the node is not and add node to mapped_node list if node_id not in mapped_node: diagram.add_node(id=f"{node_id}") mapped_node.append(node_id) # Check if remote node has already been plotted # plot the remote node is not and add remote node to mapped_node list if remote_node_id not in mapped_node: diagram.add_node(id=f"{remote_node_id}") mapped_node.append(remote_node_id) # Extract details of current link and reverse of the current link current_link = [f"{node_id}", f"{remote_node_id}"] current_link_reverse = [f"{remote_node_id}", f"{node_id}"] if current_link not in mapped_link_list: diagram.add_link( f"{node_id}", f"{remote_node_id}", label=f'{node_id}({neighbor["Local_IP"]})' f' == {neighbor["Established_Status"]}' f' == {remote_node_id}({neighbor["Remote_IP"]})', ) mapped_link_list.append(current_link) mapped_link_list.append(current_link_reverse)
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
"base_lab_Spine1", "base_lab_Spine2", "base_lab_Leaf1", "base_lab_Leaf2", "base_lab_Leaf3", "base_lab_Leaf4" ] #Check to see if all interfaces will come up when this is deployed print("******** Showing all of the Interfaces which are connected ********") int_check = bfq.interfaceProperties(properties="Active").answer() print(int_check) #Check to show all of the edge connected services print("******** Showing all of the edge connected servivces ********") edge_services = bfq.bgpEdges().answer().frame() print(edge_services) #Check for peerings peerings print("******** Showing BGP peering sessions for all nodes ********") bgp_peers = bfq.bgpSessionStatus(nodes='/Leaf/').answer().frame() print(bgp_peers) #Make sure that we can achieve multipathing to the spines loopbacks print( "********** Checking leaf switches for loopback connectivity to spines ********" ) for spineloopback0 in spine_lo0: routes_filtered = bfq.routes(network=spineloopback0).answer().frame() print(routes_filtered) #Check to see if leaf 1 can traceroute to all devices #for device in devices: # headers = HeaderConstraints(dstIps=device) # print(bfq.traceroute(startLocation="leaf1[Loopback0]", headers=headers).answer().frame())
print(bgp_sess_comp.answer().frame()) # Bgp Session status print("#"*100) print("Return the status of configured BGP sessions.") print("#"*100) bgp_sess_status = bfq.bgpSessionCompatibility(nodes='arista', remoteNodes='n9k') print(bgp_sess_status.answer().frame()) bgp_sess_status = bfq.bgpSessionCompatibility(nodes='n9k', remoteNodes='arista') print(bgp_sess_status.answer().frame()) # Bgp session print("#"*100) print("Another way to return bgp session status") print("#"*100) print((bfq.bgpSessionStatus(nodes='arista').answer()).frame()) # Defined Structures print("#"*100) print("Lists the structures defined in the network, along with the files and line numbers in which they are defined.") print("#"*100) print(bfq.definedStructures().answer().frame()) # Detect Loops print("#"*100) print("Detect forwarding loops.") print("#"*100) print(bfq.detectLoops().answer().frame()) # List edges types print("#"*100)
def analyse_network(report_dir): """ This function runs batfish questions and captures the query results into a spread sheet. :param report_dir: defines the directory in which the analysis report gets saved """ # Captures the status of the configurations that were Parsed. parse_status = bfq.fileParseStatus().answer().frame() # Batfish question to extract node properties print(Fore.YELLOW + " ==> GETTING NODE PROPERTIES") np = bfq.nodeProperties().answer().frame() # Batfish question to extract interface properties print(Fore.YELLOW + " ==> GETTING INTERFACE PROPERTIES") interface = bfq.interfaceProperties().answer().frame() # Batfish question to extract VLAN properties print(Fore.YELLOW + " ==> GETTING VLAN PROPERTIES") vlan_prop = bfq.switchedVlanProperties().answer().frame() # Batfish question to extract IP Owners print(Fore.YELLOW + " ==> GETTING IPOWNERS") ip_owners = bfq.ipOwners().answer().frame() # Batfish question to extract L3 edges print(Fore.YELLOW + " ==> GETTING L3 EDGES") l3edge = bfq.layer3Edges().answer().frame() # Batfish question to extract MPLAG properties print(Fore.YELLOW + " ==> GETTING MLAG PROPERTIES") mlag = bfq.mlagProperties().answer().frame() # Batfish question to extract OSPF configuration print(Fore.YELLOW + " ==> GETTING OSPF CONFIGURATION") ospf_config = bfq.ospfProcessConfiguration().answer().frame() # Batfish question to extract OSPF area configuration print(Fore.YELLOW + " ==> GETTING OSPF AREA CONFIGURATION") ospf_area_config = bfq.ospfAreaConfiguration().answer().frame() # Batfish question to extract OSPF interface configuration print(Fore.YELLOW + " ==> GETTING OSPF INTERFACE CONFIGURATION") ospf_interface = bfq.ospfInterfaceConfiguration().answer().frame() # Batfish question to extract OSPF Session compatability print(Fore.YELLOW + " ==> GETTING OSPF SESSION COMPATABILITY") ospf_session = bfq.ospfSessionCompatibility().answer().frame() # Batfish question to extract BGP configuration print(Fore.YELLOW + " ==> GETTING BGP CONFIGURATION") bgp_config = bfq.bgpProcessConfiguration().answer().frame() # Batfish question to extract BGP peer configuration print(Fore.YELLOW + " ==> GETTING BGP PEER CONFIGURATION") bgp_peer_config = bfq.bgpPeerConfiguration().answer().frame() # Batfish question to extract BGP session compatibility print(Fore.YELLOW + " ==> GETTING BGP SESSION COMPATIBILITY") bgp_session = bfq.bgpSessionStatus().answer().frame() # Batfish question to extract routing table print(Fore.YELLOW + " ==> GETTING ROUTE TABLE") routing = bfq.routes().answer().frame() # Batfish question to extract F5 VIP configuration print(Fore.YELLOW + " ==> GETTING F5 VIP CONFIGURATION") f5_vip = bfq.f5BigipVipConfiguration().answer().frame() # Batfish question to extract Named Structures print(Fore.YELLOW + " ==> GETTING NAMED STRUCTURES") named_structure = bfq.namedStructures().answer().frame() # Batfish question to extract Structure deginitions print(Fore.YELLOW + " ==> GETTING STRUCTURE DEFINITIONS") def_structure = bfq.definedStructures().answer().frame() # Batfish question to extract referenced structures print(Fore.YELLOW + " ==> GETTING REFERENCED STRUCTURES") ref_structure = bfq.referencedStructures().answer().frame() # Batfish question to extract undefined references print(Fore.YELLOW + " ==> GETTING UNDEFINED STRUCTURE REFERENCES") undefined_references = bfq.undefinedReferences().answer().frame() # Batfish question to extract used structures print(Fore.YELLOW + " ==> GETTING UNUSED STRUCTURES") unused_structure = bfq.unusedStructures().answer().frame() # Setting the path and file name were the analysis report will be saved analysis_report_file = report_dir + "/" + NETWORK_NAME + "_analysis_report.xlsx" print(Fore.YELLOW + " ==> GENERATING REPORT") # Writes previously computed configuration analysis into a excel file with pd.ExcelWriter(analysis_report_file) as f: parse_status.to_excel(f, sheet_name="parse_satus", engine="xlsxwriter") np.to_excel(f, sheet_name="node_properties", engine="xlsxwriter") interface.to_excel(f, sheet_name="interface_properties", engine="xlsxwriter") vlan_prop.to_excel(f, sheet_name="vlan_properties", engine="xlsxwriter") ip_owners.to_excel(f, sheet_name="IPOwners", engine="xlsxwriter") l3edge.to_excel(f, sheet_name="l3edges", engine="xlsxwriter") mlag.to_excel(f, sheet_name="mlag", engine="xlsxwriter") ospf_session.to_excel(f, sheet_name="ospf_session", engine="xlsxwriter") ospf_config.to_excel(f, sheet_name="ospf_config", engine="xlsxwriter") ospf_area_config.to_excel(f, sheet_name="ospf_area_config", engine="xlsxwriter") ospf_interface.to_excel(f, sheet_name="ospf_interface", engine="xlsxwriter") bgp_config.to_excel(f, sheet_name="bgp_config", engine="xlsxwriter") bgp_peer_config.to_excel(f, sheet_name="bgp_peer_config", engine="xlsxwriter") bgp_session.to_excel(f, sheet_name="bgp_session", engine="xlsxwriter") routing.to_excel(f, sheet_name="routing_table", engine="xlsxwriter") f5_vip.to_excel(f, sheet_name="f5_vip", engine="xlsxwriter") named_structure.to_excel(f, sheet_name="named_structure", engine="xlsxwriter") def_structure.to_excel(f, sheet_name="defined_structures", engine="xlsxwriter") ref_structure.to_excel(f, sheet_name="referrenced_structures", engine="xlsxwriter") undefined_references.to_excel(f, sheet_name="undefined_references", engine="xlsxwriter") unused_structure.to_excel(f, sheet_name="unused_structure", engine="xlsxwriter")
import re import pandas as pd NETWORK_NAME = "cumulus" BASE_SNAPSHOT_NAME = "cumulus" SNAPSHOT_PATH = "/Users/anthony/batfish/networks/example/candidate" load_questions() print("[*] Initializing BASE_SNAPSHOT") bf_set_network(NETWORK_NAME) bf_init_snapshot(SNAPSHOT_PATH, name=BASE_SNAPSHOT_NAME, overwrite=True) #print(bfq.bgpSessionStatus().answer().frame()) bgpLeafStatus = bfq.bgpSessionStatus(nodes="/leaf/").answer().frame() #bgpSessStatus.set_index("Node", inplace=True) #print(bgpSessStatus.loc[['leaf01'], ['Remote_Node']]) #print(bgpSessStatus.loc['leaf01'].Remote_Node) for index, row in bgpLeafStatus.iterrows(): #print(row['Node'], row['Remote_Node']) if(re.match(r'spine', str(row['Remote_Node'])) is not None): print("%s Has A Matching Spine BGP Neighbor" %str(row['Node'])) else: print("%s Does NOT Have A Matching Spine BGP Neighbor" %str(row['Node'])) ############################################################################################################# bgpSpineStatus = bfq.bgpSessionStatus(nodes="/spine/").answer().frame() for index, row in bgpSpineStatus.iterrows():
import pandas as pd from pybatfish.client.commands import * from pybatfish.datamodel import Edge, Interface from pybatfish.datamodel.answer import TableAnswer from pybatfish.datamodel.flow import (HeaderConstraints, PathConstraints) from pybatfish.question import bfq, load_questions # batfish host bf_session.host = "localhost" load_questions() bf_set_network('neteng-lab') bf_init_snapshot('/home/lab/repos/network-ci-pipeline/batfish-snapshots', name='neteng-lab', overwrite=True) pd.set_option('display.min_rows', 400) pd.set_option('display.max_rows', 400) bgpSessStat = bfq.bgpSessionStatus(nodes='vmx-01', remoteNodes='vmx-02', status='Established').answer().frame() print(bgpSessStat) bgpSessStat[bgpSessStat.Established_Status == "ESTABLISHED"] assert len(bgpSessStat[bgpSessStat.Established_Status == "ESTABLISHED"]) == 1, "BGP session Down"
from pybatfish.client.commands import * from pybatfish.question.question import load_questions from pybatfish.datamodel.flow import (HeaderConstraints,PathConstraints) from pybatfish.question import bfq NETWORK_NAME = "cumulus" BASE_SNAPSHOT_NAME = "cumulus" SNAPSHOT_PATH = "/Users/anthony/batfish/networks/example/candidate" load_questions() print("[*] Initializing BASE_SNAPSHOT") bf_set_network(NETWORK_NAME) bf_init_snapshot(SNAPSHOT_PATH, name=BASE_SNAPSHOT_NAME, overwrite=True) bgpSessStat = bfq.bgpSessionStatus().answer().frame() print(bgpSessStat) if len(bgpSessStat[bgpSessStat['Established_Status'] != 'ESTABLISHED']) > 0: print("Not All Devices Are Established") else: print("All BGP Sessions Are Good")