diff --git a/modules/visual_route.py b/modules/visual_route.py index 611b55f..cc9a2f3 100644 --- a/modules/visual_route.py +++ b/modules/visual_route.py @@ -67,11 +67,10 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict: for line in lines[paths_header_index + 1:]: stripped_line = line.strip() if not stripped_line: continue - is_new_path_line = False if line.startswith(' ') and not line.startswith(' '): - first_word = stripped_line.split(' ')[0].replace(',', '') - if first_word.isdigit(): + first_word = stripped_line.split(' ')[0] + if first_word.isdigit() or stripped_line == "Local": is_new_path_line = True if is_new_path_line: @@ -84,10 +83,9 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict: except StopIteration: return {"nodes": [], "edges": []} - all_paths_info = [] - best_path_info = None + all_paths_info, best_path_info = [], None for block in path_blocks: - block_text = "\n".join(block) + block_text_full = "\n".join(block) clean_lines = [line for line in block if not line.strip().startswith("AddPath ID:")] block_text_for_check = "\n".join(clean_lines) is_best = bool(re.search(r'\bbest\b', block_text_for_check, re.IGNORECASE)) @@ -95,19 +93,21 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict: path_line = block[0].strip() path_asns_raw = [] - for part in path_line.split(' '): - clean_part = part.replace(',', '').strip() - if clean_part.isdigit(): - path_asns_raw.append(clean_part) - else: - break - path_asns = list(dict.fromkeys(path_asns_raw)) - - local_pref_match = re.search(r'localpref (\d+)', block_text) + if path_line != "Local": + for part in path_line.split(' '): + clean_part = part.replace(',', '').strip() + if clean_part.isdigit(): + path_asns_raw.append(clean_part) + else: + break + + path_asns = path_asns_raw + + local_pref_match = re.search(r'localpref (\d+)', block_text_full) local_pref = int(local_pref_match.group(1)) if local_pref_match else None - next_hop_match = re.search(r'^\s*([\da-fA-F:.]+)\s+from', block_text, re.MULTILINE) + next_hop_match = re.search(r'^\s*([\da-fA-F:.]+)\s+from', block_text_full, re.MULTILINE) next_hop = next_hop_match.group(1) if next_hop_match else None - community_match = re.search(r'Large Community: ([\d:]+)', block_text) + community_match = re.search(r'Large Community: ([\d:]+)', block_text_full) community = community_match.group(1) if community_match else None category = 'other' if community: @@ -148,7 +148,7 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict: path_node_ids = [] for j, asn in enumerate(path_info['asns']): - unique_node_id = f"AS{asn}-{i}" + unique_node_id = f"AS{asn}-{i}-{j}" path_node_ids.append(unique_node_id) as_name = AS_NAME_CACHE.get(asn, ""); wrapped_name = '\n'.join(textwrap.wrap(as_name, width=AS_NAME_WRAP_WIDTH)) if as_name else "" base_label = f"AS{asn}" @@ -164,6 +164,7 @@ def _parse_bgp_paths_to_graph(bgp_data: str) -> dict: return {"nodes": nodes, "edges": edges, "path_count": len(ordered_paths)} + def generate_visual_route_graph(ip_address_str: str) -> dict: if not ip_address_str: return {"error": "IP address is required."}