解析Cisco路由表时跳过空行写入CSV的优化需求
Got it, let's tackle this problem head-on. You're parsing massive Cisco routing tables to pull only BGP entries, but running into annoying empty rows (where you end up writing a network paired with 0.0.0.0 as the mask) because some lines throw off your split[8:10] indexing. Plus, you want to avoid redundant loops since the files are huge—totally reasonable, no one wants to waste cycles loading entire giant files into memory.
Core Fixes & Optimizations
First, let's ditch the fixed-index split[8:10] approach—it's fragile because Cisco routing table lines can vary in whitespace and format. Instead, we'll:
- Identify BGP entries reliably: Cisco marks BGP routes with a leading
B(this covers all variants likeB*for default routes,B ifor iBGP, etc.) - Extract network/mask safely: Parse the network and prefix length directly from the standard route field, then convert to a subnet mask if needed.
- Filter invalid entries on the fly: Skip any lines where we can't properly extract a valid network/mask pair, avoiding those unwanted
0.0.0.0rows. - Process in a single pass: Read lines one at a time, filter, and write to CSV immediately—no loading the entire file into memory, perfect for large datasets.
Example Routing Table Lines
Let's use these sample lines to test:
B 10.1.1.0/24 [20/0] via 192.168.1.1, 00:05:12
B* 0.0.0.0/0 [20/0] via 192.168.1.2, 00:10:30
B 10.2.2.0 [20/0] via 192.168.1.3, 00:02:45 # Malformed line (no prefix/mask)
O 192.168.3.0/24 [110/10] via 192.168.1.4, 00:15:00 # OSPF line (we skip this)
Optimized Python Code
Here's a script that handles all this in one loop, with no redundant processing:
import csv def prefix_to_subnet_mask(prefix_length): """Convert a CIDR prefix length to a dotted-decimal subnet mask.""" try: prefix = int(prefix_length) if not 0 <= prefix <= 32: return None mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF return f"{(mask >> 24) & 0xFF}.{(mask >> 16) & 0xFF}.{(mask >> 8) & 0xFF}.{mask & 0xFF}" except ValueError: return None def extract_bgp_to_csv(input_routing_table, output_csv): with open(input_routing_table, 'r') as infile, open(output_csv, 'w', newline='') as outfile: csv_writer = csv.writer(outfile) csv_writer.writerow(['Network', 'Subnet_Mask']) # Write header for line in infile: stripped_line = line.strip() if not stripped_line: continue # Skip blank lines in the input file # Only process lines that start with 'B' (BGP routes) if stripped_line.startswith('B'): # Split line by any whitespace (handles variable spacing in Cisco output) line_parts = stripped_line.split() # The network/mask is always the second element in valid BGP lines if len(line_parts) < 2: continue # Skip malformed lines with insufficient data network_cidr = line_parts[1] if '/' not in network_cidr: continue # Skip lines where we can't find a CIDR prefix network, prefix = network_cidr.split('/', 1) subnet_mask = prefix_to_subnet_mask(prefix) # Only write valid entries (skip if mask conversion fails or network is invalid) if subnet_mask and network.count('.') == 3: csv_writer.writerow([network, subnet_mask]) # Usage example extract_bgp_to_csv('cisco_routes.txt', 'bgp_routes.csv')
Key Details About the Code
- Single-pass processing: We read one line at a time, process it, and write valid entries immediately—no storing the entire file in memory, which is critical for large files.
- Robust BGP detection: Using
startswith('B')catches all BGP route variants (eBGP, iBGP, default routes marked with*). - Safe mask extraction: We rely on the standard CIDR format (
x.x.x.x/y) that Cisco uses for routes, so we avoid fragile fixed-index splits. - Validation checks: We skip lines that don't have a valid CIDR format, can't convert the prefix to a mask, or have an invalid IP network.
Optional Adjustments
- If you prefer to keep the prefix length instead of converting to a dotted mask, just remove the
prefix_to_subnet_maskfunction and writeprefixdirectly to the CSV. - To log skipped lines for debugging, add a
print(f"Skipping malformed BGP line: {stripped_line}")inside thecontinueblocks.
内容的提问来源于stack exchange,提问作者Seth

