def get_reachable_interfaces(snapshot: str, switches: Set[str]) -> Set[str]: # bf_init_snapshot(str(snapshot), "reachable", overwrite=True) nodes = [] results = bfq.nodeProperties().answer().frame() for _, result in results.iterrows(): nodes.append(result.Node) reachable = set() for switch in switches: for node in nodes: results = bfq.reachability( pathConstraints=PathConstraints(startLocation=switch, endLocation=node)) \ .answer(snapshot=snapshot) results = results.frame() for _, result in results.iterrows(): for trace in result.Traces: for hop in trace.hops: for step in hop.steps: if hasattr(step.detail, "outputInterface"): reachable.add( f"{hop.node}:{step.detail.outputInterface}" ) if hasattr(step.detail, "inputInterface"): reachable.add( f"{hop.node}:{step.detail.inputInterface}") return reachable
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 generate_graph_rep_and_augment(): # Config files -> batfish -> emulation # first, let's get the networkx graph G = nx.Graph() G_layer_2 = nx.Graph() G_layer_3 = nx.Graph() color_map = [] device_dataframe = bfq.nodeProperties().answer().frame() add_devices_to_graphs(device_dataframe, G, G_layer_2, G_layer_3, color_map) interface_dataframe = bfq.interfaceProperties().answer().frame() add_interfaces_to_graphs(interface_dataframe, G, G_layer_2, G_layer_3, color_map) edge_dataframe = bfq.edges().answer().frame() edges_layer1_dataframe = bfq.layer1Edges().answer().frame() edge_interfaces = set() connected_interfaces = add_edges_to_graphs( edge_dataframe, G, G_layer_2, G_layer_3, color_map, edge_interfaces, edges_layer1_dataframe, ) for connected_interface in connected_interfaces: if str(connected_interface) in G_layer_2.nodes(): G_layer_2.remove_node(str(connected_interface)) return G, G_layer_2, G_layer_3, color_map
def resolve(self) -> Dict[str, Set[str]]: data = {} result = bfq.nodeProperties( nodes=self.node_spec, properties=self.node_property).answer().frame() for node in result.Node.values: data[node] = self.commands return data
def resolve(node_spec: str, node_property: str, snapshot: str): data = set() load_questions() result = bfq.nodeProperties(nodes=node_spec, properties=node_property)\ .answer(snapshot=snapshot).frame() for node in result.Node.values: data.add(node) return data
def init_bf(): bf_session.host = bf_host bf_set_network("nova_candidate") snapshots = bf_list_snapshots() pprint(snapshots) bf_init_snapshot(SNAPSHOT_DIR, name=SNAPSHOT_NAME, overwrite=True) bf_set_snapshot(SNAPSHOT_NAME) load_questions() print(bfq.initIssues().answer()) print( bfq.nodeProperties(properties="Configuration_Format").answer().frame())
def deactivate_nodes(bf_snapshot_base, bf_snapshot_fail): nodes = bfq.nodeProperties(nodes=NODE_SCOPE).answer().frame() for node_index in range(len(nodes)): print( "[*] Deactivating node: [magenta bold]{}[/magenta bold]".format( nodes.loc[node_index].Node), end=" ", ) bf_fork_snapshot( base_name=bf_snapshot_base, name=bf_snapshot_fail, deactivate_nodes=[nodes.loc[node_index].Node], overwrite=True, ) pprint_results( get_differential_reachability(bf_snapshot_base, bf_snapshot_fail))
def get_reachable_nodes_intersect(snapshot: str, switches: Set[str]) -> Set[str]: nodes = [] results = bfq.nodeProperties().answer().frame() for _, result in results.iterrows(): nodes.append(result.Node) reachable = {} for switch in switches: for node in nodes: results = bfq.reachability( pathConstraints=PathConstraints(startLocation=switch, endLocation=node)) \ .answer(snapshot=snapshot) results = results.frame() if results.size > 0: if node not in reachable: reachable[node] = 0 reachable[node] += 1 return set( map( lambda it: it[0], filter(lambda elem: elem[1] >= len(switches) // 3, reachable.items())))
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 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")
# Now create the network and initialize the snapshot bf_session.host = BF_HOST load_questions() # bf_set_network(NETWORK_NAME) # bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True) print(acl_text) acl_snapshot = bf_session.init_snapshot_from_text(acl_text, platform="arista", snapshot_name="original", overwrite=True) # node_name = "DMZ-LF18" # The router to change # filter_name = "demo" # Name of the ACL to change result = bfq.nodeProperties().answer().frame() # permiturl = 'http://dmz-gitlab.sjc.aristanetworks.com/network/cloudvision/-/raw/master/permit.json' permit_url = GITLAB_API_URL + "/projects/" + GITLAB_PROJECT_ID + \ "/repository/files" + "/permit.json" + "/raw?ref=" + GITLAB_BRANCH resp = requests.get(permit_url, headers=tokenheader) permits = resp.json() print(f"ACL SNAPSHOT: {acl_snapshot}") for p in permits['permit']: headers = HeaderConstraints(dstIps=p["dstIps"], ipProtocols=p["ipProtocols"], dstPorts=p["dstPorts"]) # print(headers) # answer = bfq.searchFilters(headers=headers, # action="permit").answer(snapshot=SNAPSHOT_NAME) answer2 = bfq.searchFilters(headers=headers, action="permit").answer(snapshot=acl_snapshot)