Make bgp_route hand-only for divergent IN/OUT CLI layouts.

Skip TextFSM for neighbor route tables (status vs plain, From, RD+VRF, heavy wraps); parse via callback and cover with live RR/VRF fixtures.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-23 15:36:25 +08:00
parent ac53af4a5d
commit c18c9afa2e
6 changed files with 354 additions and 194 deletions

View file

@ -1,7 +1,12 @@
# ARCHIVE — not registered in index. bgp_route uses hand-only normalize
# (IN/OUT / status / From / RD+VRF / wraps diverge too much for one template).
Value Filldown RD (\S+)
Value STATUS ((?:\*[<>isd]*(?:\s+[isd]+)?|[<>isd]+)?)
Value Filldown VRF (\S+)
Value STATUS (\*(?:\s*[<>isd]+)?|[<>isd]+)
Value NETWORK (\d{1,3}(?:\.\d{1,3}){3}/\d{1,2}|[0-9A-Fa-f:]+/\d{1,3})
Value NEXT_HOP (\d{1,3}(?:\.\d{1,3}){3}|[0-9A-Fa-f:]+)
# IPv4, IPv6, or IPv4-mapped (::FFFF:a.b.c.d)
Value NEXT_HOP (\d{1,3}(?:\.\d{1,3}){3}|::[Ff]{4}:\d{1,3}(?:\.\d{1,3}){3}|[0-9A-Fa-f:]+)
Value FROM (\d{1,3}(?:\.\d{1,3}){3}|::[Ff]{4}:\d{1,3}(?:\.\d{1,3}){3}|[0-9A-Fa-f:]+)
Value METRIC (\S*)
Value LOC_PRF (\S*)
Value TAG (\S*)
@ -12,13 +17,12 @@ Start
^\s*\*?\s*Network\s+Next -> Routes
^Network\s+Next -> Routes
^\s*Dest\s+Next -> Routes
# RD may appear before header on some snippets; keep Filldown ready
^Route\s+Distinguisher\s*:?\s*${RD}
^Route\s+Distinguisher\s*:?\s*${RD}(?:\s*\(\s*default\s+for\s+vrf\s+${VRF}\s*\))?
^\s*$$
^.* -> Start
Routes
^Route\s+Distinguisher\s*:?\s*${RD}
^Route\s+Distinguisher\s*:?\s*${RD}(?:\s*\(\s*default\s+for\s+vrf\s+${VRF}\s*\))?
^Status\s+codes
^Origin\s+codes
^Current\s+AS
@ -30,11 +34,28 @@ Routes
^\s*\*?\s*Network\s+Next
^Network\s+Next
^\s*Dest\s+Next
# One-line IPv4 / RR "* i prefix nh …"
# IN one-line with status: * i prefix nh metric loc tag path
^\s*${STATUS}\s+${NETWORK}\s+${NEXT_HOP}\s+${METRIC}\s+${LOC_PRF}\s+${TAG}\s+${PATH}\s*$$ -> Record
^\s*${STATUS}\s+${NETWORK}\s+${NEXT_HOP}\s+${METRIC}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
^\s*${STATUS}\s+${NETWORK}\s+${NEXT_HOP}\s+${PATH}\s*$$ -> Record
# IPv6 wrap: network alone, then next-hop (+ optional metric/path) lines
# OUT one-line without status: net nh [from] metric locprf [tag] path
^\s*${NETWORK}\s+${NEXT_HOP}\s+${FROM}\s+${METRIC}\s+${LOC_PRF}\s+${TAG}\s+${PATH}\s*$$ -> Record
^\s*${NETWORK}\s+${NEXT_HOP}\s+${FROM}\s+${METRIC}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
^\s*${NETWORK}\s+${NEXT_HOP}\s+${FROM}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
^\s*${NETWORK}\s+${NEXT_HOP}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
# IN wrap: status+net+nh then indented metrics
^\s*${STATUS}\s+${NETWORK}\s+${NEXT_HOP}\s*$$
^\s+${METRIC}\s+${LOC_PRF}\s+${TAG}\s+${PATH}\s*$$ -> Record
^\s+${METRIC}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
^\s+${PATH}\s*$$ -> Record
# OUT wrap: net+nh+from then indented metrics (From may be long IPv6)
^\s*${NETWORK}\s+${NEXT_HOP}\s+${FROM}\s*$$
^\s+${METRIC}\s+${LOC_PRF}\s+${TAG}\s+${PATH}\s*$$ -> Record
^\s+${METRIC}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
^\s+${PATH}\s*$$ -> Record
# Classic wrap: network alone, then next-hop (+ optional metric/path)
^\s*${STATUS}\s+${NETWORK}\s*$$
^\s*${NETWORK}\s*$$
^\s+${NEXT_HOP}\s+${METRIC}\s+${LOC_PRF}\s+${TAG}\s+${PATH}\s*$$ -> Record
^\s+${NEXT_HOP}\s+${METRIC}\s+${LOC_PRF}\s+${PATH}\s*$$ -> Record
^\s+${NEXT_HOP}\s+${PATH}\s*$$ -> Record