def build_directed_graph(self) -> Dict[str, Set[str]]: pending_nodes = [] visited = set() poped = set() edge = {} for interface in self.interfaces: node_name = interface.split(":")[0] if "border" in node_name: pending_nodes.append(node_name) visited.add(node_name) while len(pending_nodes) > 0: node = pending_nodes.pop(0) poped.add(node) # if node not in edge: # edge[node] = [] results = bfq.layer3Edges(nodes=node).answer(snapshot=self.snapshot).frame() for idx, result in results.iterrows(): hostname = result.Remote_Interface.hostname if hostname not in edge: edge[hostname] = set() if hostname not in poped: edge[hostname].add(node) if hostname in visited: continue pending_nodes.append(hostname) visited.add(hostname) return edge
def get_internal_interfaces(self) -> Set[str]: affected_interfaces = set() for node in self.affected_nodes: results = bfq.layer3Edges(nodes=node).answer(snapshot=self.snapshot).frame() for idx, result in results.iterrows(): affected_interfaces.add(interface_to_str(result.Remote_Interface)) return affected_interfaces
def plot_l3_graph(): """ This function extracts L3 edges and plots a graph of L3 relationships """ # Run batfish query to identify L3 edges l3edges = bfq.layer3Edges().answer().frame() # Conditional check to ensure the L3 edges list is not empty if l3edges.empty: print(Fore.RED + " ==> NO L3 ADJENCIES FOUND") else: print(Fore.YELLOW + " ==> PLOTTING L3 NETWORK GRAPH") l3edges_json = json.loads(l3edges.to_json(orient="index")) # Initialise list to track nodes that are already plotted. mapped_node = [] # Initialise list to track links that are already plotted # initialise a drawing named L3 diagram.add_diagram("L3") for key in l3edges_json: # Initialise local list to map current link and reverse of current link. current_link = [] current_link_reverse = [] # Extract details of the neighbor neighbor = l3edges_json[key] node_id = f'{neighbor["Interface"]["hostname"]}' remote_node_id = f'{neighbor["Remote_Interface"]["hostname"]}' # 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) diagram.add_link( f"{node_id}", f"{remote_node_id}", label=f'{node_id}({neighbor["IPs"]})' f' == VLAN {key}' f' == {remote_node_id}({neighbor["Remote_IPs"]})', )
def print_debugging_info(): parse_status = bfq.fileParseStatus().answer().frame() print("----------------------") print(parse_status) print("----------------------") parse_warning = bfq.parseWarning().answer().frame() print("----------------------") print(parse_warning) print("----------------------") # vxlanEdges,layer3Edges node_properties_trunc = bfq.nodeProperties( properties="Interfaces").answer().frame() print(node_properties_trunc) print("---------") print(bfq.undefinedReferences().answer().frame()) print("layer1Edges") print("----------------------") print(bfq.layer1Edges().answer().frame()) print("LAYER3_EDGES") print("----------------------") print(bfq.layer3Edges().answer().frame()) print("----------------------") print(bfq.undefinedReferences().answer().frame()) # Get edges of type layer 3 (IP layer) print(bfq.edges(edgeType="layer3").answer().frame())
def build_topology(base: str, config_path: str, reachable_nodes: Set[str], sensitive_nodes: Set[str]) -> Topology: reachable_interfaces = get_reachable_interfaces_endnodes( base, config_path, reachable_nodes) interfaces = set() results = bfq.interfaceProperties().answer().frame() for _, result in results.iterrows(): interfaces.add(interface_to_str(result.Interface)) links = [] results = bfq.layer3Edges().answer(snapshot=base).frame() for _, result in results.iterrows(): i1 = result.Interface i1_str = interface_to_str(i1) i2 = result.Remote_Interface i2_str = interface_to_str(i2) type = "accessible" if i1.hostname in sensitive_nodes or i2.hostname in sensitive_nodes: type = "sensitive" if i1_str not in reachable_interfaces or i2_str not in reachable_interfaces: type = "protected" links.append((i1_str, i2_str, type)) return Topology(reachable_interfaces, interfaces.difference(reachable_interfaces), links)
def razbor_l3edge(): vyvod = bfq.layer3Edges().answer().frame() return vyvod
from pybatfish.question import bfq from pybatfish.datamodel import HeaderConstraints, PathConstraints, Hop from pybatfish.question.question import load_questions from pybatfish.client.commands import bf_init_snapshot, bf_set_network, bf_upload_diagnostics from typing import List import json from command import * from policy import * from experiment import * from utils import * import json import sys load_questions() bf_init_snapshot("configs/multihosts") result = bfq.layer3Edges().answer().frame() bf_init_snapshot("configs/Working_Enterprise") result = bfq.layer3Edges().answer().frame() # compute_issue_reachable_nodes("configs/Working_Enterprise", "configs/issues/working-enterprise/ospf") # compute_issue_reachable_nodes("configs/Working_Enterprise", "configs/issues/working-enterprise/reconfiguration") # compute_issue_reachable_nodes("configs/Working_Enterprise", "configs/working-enterprise/vlan") compute_issue_reachable_nodes("configs/multihosts", "configs/issues/multihosts/as2border1") compute_issue_reachable_nodes("configs/multihosts", "configs/issues/multihosts/as2core1") compute_issue_reachable_nodes("configs/multihosts", "configs/issues/multihosts/as3border2") # def batfish_client(path, snapshot):
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")
def get_layer3_edges(self): result = bfq.layer3Edges().answer().frame() return result