<div dir="ltr">Here is a sample output from routedetail.textfsm<div><br></div><div>[<br> {<br> "Route": "<a href="http://12.0.0.0/24">12.0.0.0/24</a>",<br> "Neighbor": "go1",<br> "Age": "2021-05-11 18:03:39",<br> "NeiIP": "192.168.65.1",<br> "OriginAS": "300",<br> "Table": "go1_v4",<br> "BGP_origin": "Incomplete",<br> "BGP_aspath": "57 1 20 300",<br> "BGP_nexthop": "192.168.65.1",<br> "BGP_localpref": "100",<br> "BGP_community": "",<br> "BGP_med": ""<br> },<br> {<br> "Route": "<a href="http://20.0.0.0/24">20.0.0.0/24</a>",<br> "Neighbor": "go2",<br> "Age": "2021-05-11 18:03:39",<br> "NeiIP": "192.168.65.2",<br> "OriginAS": "300",<br> "Table": "go2_v4",<br> "BGP_origin": "Incomplete",<br> "BGP_aspath": "18 1 20 300",<br> "BGP_nexthop": "192.168.65.2",<br> "BGP_localpref": "100",<br> "BGP_community": "",<br> "BGP_med": ""<br> },<br> {<br> "Route": "<a href="http://20.0.0.0/24">20.0.0.0/24</a>",<br> "Neighbor": "go2",<br> "Age": "2021-05-11 18:03:39",<br> "NeiIP": "192.168.65.2",<br> "OriginAS": "300",<br> "Table": "gorr1_v4",<br> "BGP_origin": "Incomplete",<br> "BGP_aspath": "18 1 20 300",<br> "BGP_nexthop": "192.168.65.2",<br> "BGP_localpref": "100",<br> "BGP_community": "(64666,666)",<br> "BGP_med": ""<br> },<br> {<br> "Route": "<a href="http://20.0.0.0/24">20.0.0.0/24</a>",<br> "Neighbor": "gorr2",<br> "Age": "2021-05-11 18:03:38",<br> "NeiIP": "192.168.64.101",<br> "OriginAS": "300",<br> "Table": "gorr2_v4",<br> "BGP_origin": "Incomplete",<br> "BGP_aspath": "18 1 20 300",<br> "BGP_nexthop": "192.168.65.2",<br> "BGP_localpref": "100",<br> "BGP_community": "",<br> "BGP_med": ""<br> },<br> {<br> "Route": "<a href="http://20.0.0.0/24">20.0.0.0/24</a>",<br> "Neighbor": "go2",<br> "Age": "2021-05-11 18:03:39",<br> "NeiIP": "192.168.65.2",<br> "OriginAS": "300",<br> "Table": "test1.lab1_v4",<br> "BGP_origin": "Incomplete",<br> "BGP_aspath": "18 1 20 300",<br> "BGP_nexthop": "192.168.65.2",<br> "BGP_localpref": "100",<br> "BGP_community": "(64666,666)",<br> "BGP_med": ""<br> }<br>]<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, May 11, 2021 at 10:55 AM Logan Rawlins <<a href="mailto:maveric@gotskill.net">maveric@gotskill.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Like many of you on this list i've seen many running into issues needing json output from bird. For now i'm getting through this using textfsm and then adding the headers to the output creating dict lists of routes or other info from bird. This is probably the easiest method for parsing bird output into json hopefully this is of use to some on this list.<div><br></div><div><snip></div><div> def _parse_bird_output(cls, template, text):<br> template='textfsm/' + template<br> with open(template) as f:<br> fsmtemplate = textfsm.TextFSM(f)<br> header = fsmtemplate.header<br> parsedtext = fsmtemplate.ParseText(text)<br> output = []<br><br> for item in parsedtext:<br> output.append(dict(zip(header,item)))<br> return json.dumps(output)<br></div><div></snip></div><div><br></div><div><routedetail.textfsm></div><div><br></div><div>Value Required Route (\d+\.\d+\.\d+\.\d+\/\d+|([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}/\d{1,3})<br>Value Neighbor ((\w|\.)+)<br>Value Age (\d+-\d+-\d+ \d+:\d+:\d+)<br>Value NeiIP (\d+\.\d+\.\d+\.\d+)<br>Value OriginAS (\d+)<br>Value Filldown Table (.+)<br>Value BGP_origin (\w+)<br>Value BGP_aspath (.+)<br>Value BGP_nexthop (\d+\.\d+\.\d+\.\d+)<br>Value BGP_localpref (\d+)<br>Value BGP_community (.+)<br>Value BGP_med (\d+)<br><br>Start<br> ^Table ${Table}:<br> ^${Route}.*\[${Neighbor} ${Age} from ${NeiIP}\].*\[AS${OriginAS}.\]<br> ^\s+BGP.origin: ${BGP_origin}<br> ^\s+BGP.as_path: ${BGP_aspath}<br> ^\s+BGP.next_hop: ${BGP_nexthop}<br> ^\s+BGP.med: ${BGP_med}<br> ^\s+BGP.local_pref: ${BGP_localpref} -> CommCheck<br><br>CommCheck<br> ^\s+BGP.community: ${BGP_community} -> Record Start<br># input buffer line doesn't have BGP.community in it, go on to the next rule(s) but save<br> ^\s*((?!BGP.community).)* -> Continue.Record<br># check for the start of new table or route and move back to initial state<br> ^Table ${Table}: -> Start<br> ^${Route}.*\[${Neighbor} ${Age} from ${NeiIP}\].*\[AS${OriginAS}.\] -> Start<br></div><div></routedetail.textfsm></div><div><br></div><div><routes.textfsm></div><div><br>Value Filldown Table (.+)<br>Value Required Route (\d+\.\d+\.\d+\.\d+\/\d+|([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}/\d{1,3})<br>Value Neighbor ((\w|\.)+)<br>Value NeiIP (\d+\.\d+\.\d+\.\d+)<br>Value Age (\d+-\d+-\d+ \d+:\d+:\d+)<br>Value OriginAS (\d+)<br><br><br>Start<br> ^BIRD \d+\.\d+\.\d+ ready. -> RTable<br><br>RTable<br> ^Table ${Table}: -> Record<br> ^${Route}.*\[${Neighbor} ${Age} from ${NeiIP}\].*\[AS${OriginAS}.\] -> Record<br> ^Table -> Start<br></div><div><br></div><div></routes.textfsm></div><div><br></div><div><routecount.textfsm></div><div><br>Value Table (\S+)<br>Value Routes (\d+)<br>Value Total (\d+)<br>Value Networks (\d+)<br>Value Tables (\d+)<br><br>Start<br> ^${Routes} of ${Total} routes for ${Networks} networks in table ${Table} -> Record<br> ^Total: ${Routes} of ${Total} routes for ${Networks} networks in ${Tables} tables -> Record<br></div><div><br></div><div></routecount.textfsm></div></div>
</blockquote></div>