03-04-2025 06:25 AM
I'm getting error ('Parser Output is empty',) when the command specifies the address family (ipv4,ipv6, vpnv4, etc)
- show bgp {address-family}
- show bgp vrf {vrf} {address-family}
Below my code:
def get_bgp_routing_table(host, username, password, vrf='', filter='ipv4_unicast'):
global TESTBED_YAML_FILE
testbed = loader.load(TESTBED_YAML_FILE)
if host not in testbed.devices:
raise ValueError(f"Device {host} not found in testbed")
device = testbed.devices[host]
device.credentials['default'] = {
'username': username,
'password': password
}
device.connect(
timeout=60,
init_exec_commands=[], # Prevents exec commands
init_config_commands=[] # Prevents config commands
)
extracted_data = []
filter = filter.replace('_', ' ') # Adjust filter for command syntax
try:
if filter == 'ipv4 unicast':
command = f"show bgp vrf {vrf}" if vrf else "show bgp"
else:
command = f"show bgp vrf {vrf} {filter}" if vrf else f"show bgp {filter}"
raw_output = device.execute(command)
print("Raw output received from the device:\n", raw_output)
output = device.parse(command)
filter = filter.replace(' ', '_')
if 'vrf' in output:
vrf_output = output['vrf']
if vrf in vrf_output:
address_family = vrf_output[vrf]['address_family']
if filter in address_family:
for prefix, details in address_family[filter]['prefix'].items():
for index, info in details['index'].items():
extracted_data.append({
'network': prefix,
'next_hop': info['next_hop'],
'status_codes': info['status_codes'],
'origin_codes': info['origin_codes'],
'locprf': info['locprf'],
'weight': info['weight'],
'path': info.get('path', None) # Safe to use .get() here
})
else:
raise ValueError(f"Address family '{filter}' not found in the VRF '{vrf}' output.")
else:
raise ValueError(f"VRF '{vrf}' not found in the output.")
else:
raise ValueError("VRF information missing in the parsed output")
except Exception as e:
results = {
'status': 400,
'message': str(e)
}
return results, 400
finally:
device.disconnect()
return extracted_data
The exception is raised when execution reaches line "output = device.parse(command)"
When the command has the ipv4 unicast filter, the raw output is:
Tue Mar 4 11:49:15.027 GMT
BGP VRF lab, state: Active
BGP Route Distinguisher: 12345:92
VRF ID: 0x6000013d
BGP router identifier 1.1.1.1, local AS number 12345
Non-stop routing is enabled
BGP table state: Active
Table ID: 0xe000013d RD version: 54879
BGP table nexthop route policy:
BGP main routing table version 54879
BGP NSR Initial initsync version 53406 (Reached)
BGP NSR/ISSU Sync-Group versions 54879/0
Status codes: s suppressed, d damped, h history, * valid, > best
i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 12345:92 (default for vrf lab)
Route Distinguisher Version: 54879
*>i2.122.208.0/24 2.120.0.2 0 100 0 ?
*> 2.216.0.0/13 3.3.3.3.234 0 32768 ?
*>i8.8.8.8/32 76.145.128.249 100 0 ?
*> 10.0.0.0/16 172.16.110.2 0 32768 ?
*> 10.100.0.0/16 3.3.3.3.226 0 32768 ?
*>i3.3.3.3.32/28 76.145.128.41 0 100 0 ?
*>i3.3.3.3.64/28 76.145.128.41 0 100 0 ?
*>i3.3.3.3.128/28 76.145.128.41 0 100 0 ?
*>i3.3.3.3.160/28 76.145.128.41 0 100 0 ?
*> 3.3.3.3.224/30 3.3.3.3.248 0 32768 ?
*> 3.3.3.3.232/30 3.3.3.3.249 0 32768 ?
* 3.3.3.3.248/31 0.0.0.0 0 32768 ?
*> 0.0.0.0 0 32768 ?
*> 3.3.3.3.250/32 0.0.0.0 0 32768 ?
*> 11.0.0.0/16 172.16.110.2 0 32768 ?
*> 192.168.0.0/15 3.3.3.3.234 0 32768 ?
*>i80.238.8.0/23 76.145.128.249 100 0 ?
* i108.207.236.0/23 2.120.0.2 0 100 0 ?
*>i 76.145.128.249 100 0 ?
*>i91.103.34.0/24 2.120.0.99 10000 180 0 ?
*>i94.119.8.0/21 2.120.0.99 10000 180 0 ?
*> 172.16.110.0/30 3.3.3.3.249 0 32768 ?
*> 172.16.111.0/30 172.16.110.2 0 32768 ?
*>i20.6.14.0/24 76.145.128.249 100 0 ?
*>i20.58.18.0/23 76.145.128.249 100 0 ?
Processed 23 prefixes, 25 paths
When the command does not have any filters, the raw output is:
Tue Mar 4 11:50:17.130 GMT
BGP VRF lab, state: Active
BGP Route Distinguisher: 12345:92
VRF ID: 0x6000013d
BGP router identifier 1.1.1.1, local AS number 12345
Non-stop routing is enabled
BGP table state: Active
Table ID: 0xe000013d RD version: 54879
BGP table nexthop route policy:
BGP main routing table version 54879
BGP NSR Initial initsync version 53406 (Reached)
BGP NSR/ISSU Sync-Group versions 54879/0
Status codes: s suppressed, d damped, h history, * valid, > best
i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 12345:92 (default for vrf lab)
Route Distinguisher Version: 54879
*>i2.122.208.0/24 2.120.0.2 0 100 0 ?
*> 2.216.0.0/13 3.3.3.3.234 0 32768 ?
*>i8.8.8.8/32 76.145.128.249 100 0 ?
*> 10.0.0.0/16 172.16.110.2 0 32768 ?
*> 10.100.0.0/16 3.3.3.3.226 0 32768 ?
*>i3.3.3.3.32/28 76.145.128.41 0 100 0 ?
*>i3.3.3.3.64/28 76.145.128.41 0 100 0 ?
*>i3.3.3.3.128/28 76.145.128.41 0 100 0 ?
*>i3.3.3.3.160/28 76.145.128.41 0 100 0 ?
*> 3.3.3.3.224/30 3.3.3.3.248 0 32768 ?
*> 3.3.3.3.232/30 3.3.3.3.249 0 32768 ?
* 3.3.3.3.248/31 0.0.0.0 0 32768 ?
*> 0.0.0.0 0 32768 ?
*> 3.3.3.3.250/32 0.0.0.0 0 32768 ?
*> 11.0.0.0/16 172.16.110.2 0 32768 ?
*> 192.168.0.0/15 3.3.3.3.234 0 32768 ?
*>i80.238.8.0/23 76.145.128.249 100 0 ?
* i108.207.236.0/23 2.120.0.2 0 100 0 ?
*>i 76.145.128.249 100 0 ?
*>i91.103.34.0/24 2.120.0.99 10000 180 0 ?
*>i94.119.8.0/21 2.120.0.99 10000 180 0 ?
*> 172.16.110.0/30 3.3.3.3.249 0 32768 ?
*> 172.16.111.0/30 172.16.110.2 0 32768 ?
*>i20.6.14.0/24 76.145.128.249 100 0 ?
*>i20.58.18.0/23 76.145.128.249 100 0 ?
Processed 23 prefixes, 25 paths
So the output is the same.
Solved! Go to Solution.
03-05-2025 09:03 AM
Nice, so i guess this confirms the parsing issue specifically happens when an address family (like ipv6 unicast) is added to the command here. I guess to get deeper into this, you could update the code to print more, some more debugging outputs, or/and a print statement for your full output structure if no matching family is found ...
You could ask directly to the team over at pyats-support-ext@cisco.com if they are aware of known issues on versions etc..
03-04-2025 08:19 AM
@Manu05 your error ('Parser Output is empty',)
indicates that the parser is unable to interpret the raw output from your device, this i think the parser is unable to recognize the command structure when specific address family filters are used.
What device is this for?
03-04-2025 08:32 AM
It's an IOS XR NCS5500 device.
When the command is "show bgp vrf {vrf} ipv4 unicast" the parsing fails. It's the same for other address families. When it's omitted like for "show bgp vrf {vrf}" the parsing is successful. Although the two commands give the same output from the device.
03-05-2025 02:00 AM
Please test this, it might be a bit rough, its using some command variations, some error handling, and i am attemting to handle the different address family key formats
def get_bgp_routing_table(host, username, password, vrf='', filter='ipv4_unicast'):
global TESTBED_YAML_FILE
testbed = loader.load(TESTBED_YAML_FILE)
if host not in testbed.devices:
raise ValueError(f"Device {host} not found in testbed")
device = testbed.devices[host]
device.credentials['default'] = {
'username': username,
'password': password
}
device.connect(
timeout=60,
init_exec_commands=[],
init_config_commands=[]
)
extracted_data = []
filter = filter.replace('_', ' ') # Adjust filter for command syntax
try:
# First, try parsing without address family if it fails
commands_to_try = []
if vrf:
if filter == 'ipv4 unicast':
commands_to_try = [
f"show bgp vrf {vrf}",
f"show bgp vrf {vrf} ipv4 unicast"
]
else:
commands_to_try = [
f"show bgp vrf {vrf} {filter}",
f"show bgp vrf {vrf}"
]
else:
commands_to_try = [
f"show bgp {filter}" if filter != 'ipv4 unicast' else "show bgp",
f"show bgp ipv4 unicast"
]
# Try multiple command variations
output = None
for command in commands_to_try:
try:
raw_output = device.execute(command)
print(f"Attempting to parse command: {command}")
output = device.parse(command)
if output:
break
except Exception as cmd_error:
print(f"Parsing failed for command {command}: {cmd_error}")
if not output:
raise ValueError("Could not parse BGP output with any command variation")
filter = filter.replace(' ', '_')
# Flexible parsing approach
if 'vrf' in output:
vrf_output = output['vrf']
# Determine the VRF to use
current_vrf = vrf if vrf and vrf in vrf_output else list(vrf_output.keys())[0]
if current_vrf in vrf_output:
address_family = vrf_output[current_vrf].get('address_family', {})
# Try multiple address family keys
possible_af_keys = [
filter,
filter.replace(' ', '_'),
'ipv4_unicast', # Default fallback
]
found_af = None
for af_key in possible_af_keys:
if af_key in address_family:
found_af = af_key
break
if found_af:
for prefix, details in address_family[found_af].get('prefix', {}).items():
for index, info in details.get('index', {}).items():
extracted_data.append({
'network': prefix,
'next_hop': info.get('next_hop', ''),
'status_codes': info.get('status_codes', ''),
'origin_codes': info.get('origin_codes', ''),
'locprf': info.get('locprf', ''),
'weight': info.get('weight', ''),
'path': info.get('path', [])
})
else:
print(f"No matching address family found. Available families: {list(address_family.keys())}")
else:
print(f"VRF {current_vrf} not found in output")
else:
print("No VRF information in output")
except Exception as e:
print(f"Error occurred: {e}")
results = {
'status': 400,
'message': str(e)
}
return results, 400
finally:
device.disconnect()
return extracted_data
03-05-2025 08:46 AM - edited 03-05-2025 08:47 AM
Thank you!
I just added a small adjustment on your code:
if output:
print(f"Parsing successful for command {command}")
break
Then I tried with two input commands:
1) show bgp vrf lab
Results:
Attempting to parse command: show bgp vrf lab
Parsing successful for command show bgp vrf lab
2) show bgp vrf lab ipv6 unicast
Results:
Attempting to parse command: show bgp lab ipv6 unicast
Parsing failed for command show bgp vrf lab ipv6 unicast: Parser Output is empty
Attempting to parse command: show bgp vrf lab
Parsing successful for command show bgp vrf lab
03-05-2025 09:03 AM
Nice, so i guess this confirms the parsing issue specifically happens when an address family (like ipv6 unicast) is added to the command here. I guess to get deeper into this, you could update the code to print more, some more debugging outputs, or/and a print statement for your full output structure if no matching family is found ...
You could ask directly to the team over at pyats-support-ext@cisco.com if they are aware of known issues on versions etc..
03-10-2025 08:39 AM
Yes. It's clear that whenever an address family is added to the command, the parser fails. After digging further a little bit, I found a more specific Genie parser function can be used for IOS XR: ShowBgpVrf
it's in genieparser module in src/genie/libs/parser/iosxr/show_bgp.py. The address family issue disappeared but the parser fails reading metric, local preference, weight and as path parameters. With IPv6 some prefixes are not parsed at all. I think I'm going to message the team directly to pyats-support-ext@cisco.com and ask for advice.
Thanks!
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide