networktocode / ntc-ansible

Multi-vendor network modules
Other
278 stars 112 forks source link

show ip route on cisco ios #31

Closed ktbyers closed 8 years ago

ktbyers commented 8 years ago

'show ip route' template was not parsing correctly when I tested it on Cisco IOS.

Here is the output that it was failing to parse:

pynet-rtr1#show ip route
Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area 
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
       a - application route
       + - replicated route, % - next hop override

Gateway of last resort is 10.220.88.1 to network 0.0.0.0

S*    0.0.0.0/0 [1/0] via 10.220.88.1
      10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        10.220.88.0/24 is directly connected, FastEthernet4
L        10.220.88.20/32 is directly connected, FastEthernet4

I haven't looked at the template much. I wanted to submit this so I didn't forget about it later.

jedelman8 commented 8 years ago

Just to be safe can you post it in a markdown code block so spacing is correct?

ktbyers commented 8 years ago

Okay, updated above.

ubajze commented 8 years ago

Hey

I forgot to include local routes (L). I have created the new pull request with the fix. I thing this should be ok now. Please check.

jedelman8 commented 8 years ago

Thanks, I found that too. But I also found something else.

Can you check these statements out?

  # Match directly connected routes
  ^${Protocol}\s${Type}\s+${Network}\sis\sdirectly\sconnected,\s${NexthopIf} -> Record
  ^${Protocol}(\*){0,1}\s${Type}\s+${Network}${Mask}\sis\sdirectly\sconnected,\s${NexthopIf} -> Record
  #

Because the spacing is different in Kirk's output, notice only 1 space after Protocol and not several, the route still wasn't being matched. I started looking at a fix and think Type may not be required for directly connected routes simplifying these regex's a little bit. If we need it, we'll need to get creative.

You can see what I'm saying if you use regxr.com and slowly add your regex's. Example: C 10.220.88.0/24 is directly connected, FastEthernet4 ---- 10 in the prefix was being stored as the type.

What I was testing with:

  # Match directly connected routes
  ^${Protocol}\s+${Network}\sis\sdirectly\sconnected,\s${NexthopIf} -> Record
  ^${Protocol}(\*){0,1}\s*${Network}${Mask}\sis\sdirectly\sconnected,\s${NexthopIf} -> Record

Even with mine, it still seems to be storing the last route twice from Kirk's (when the hostname / router prompt is removed from the raw text). When it is there, it's fine, but the template shouldn't care.

Would you mind updating the PR ensuring the raw text below works- would be great if you can update the raw text file and template in the PR? BTW, should we add any more "protocols" besides "L"?

S* 0.0.0.0/0 [1/0] via 10.220.88.1
10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C 10.220.88.0/24 is directly connected, FastEthernet4
L 10.220.88.20/32 is directly connected, FastEthernet4
     1.0.0.0/32 is subnetted, 1 subnets
S       1.1.1.1 [1/0] via 212.0.0.1
                [1/0] via 192.168.0.1
     2.0.0.0/24 is subnetted, 1 subnets
S       2.2.2.0 is directly connected, FastEthernet0/0
     4.0.0.0/16 is subnetted, 1 subnets
O E2    4.4.0.0 [110/20] via 194.0.0.2, 00:02:00, FastEthernet0/0
     5.0.0.0/24 is subnetted, 1 subnets
D EX    5.5.5.0 [170/2297856] via 10.0.1.2, 00:12:01, Serial0/0
     6.0.0.0/16 is subnetted, 1 subnets
B       6.6.0.0 [200/0] via 195.0.0.1, 00:00:04
     172.16.0.0/26 is subnetted, 1 subnets
i L2    172.16.1.0 [115/10] via 10.0.1.2, Serial0/0
     172.20.0.0/32 is subnetted, 3 subnets
O       172.20.1.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
O       172.20.3.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
O       172.20.2.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
     10.0.0.0/8 is variably subnetted, 5 subnets, 3 masks
C       10.0.1.0/24 is directly connected, Serial0/0
D       10.0.5.0/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
D       10.0.5.64/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
D       10.0.5.128/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
D       10.0.5.192/27 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
     192.168.0.0/32 is subnetted, 1 subnets
D       192.168.0.1 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
O IA 195.0.0.0/24 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
O*E2 0.0.0.0/0 [110/1] via 194.0.0.2, 00:05:35, FastEthernet0/0
O E2 212.0.0.0/8 [110/20] via 194.0.0.2, 00:05:35, FastEthernet0/0
C    194.0.0.0/16 is directly connected, FastEthernet0/0

THANK YOU

ubajze commented 8 years ago

Hello

  1. I have done some tests and find out, that the solution for one space could be to add Type as an optional element:
\s${Type}  -->>  (\s${Type}){0,1}
  1. I am not really sure, why template perform another Record, after the final line. Do you have any idea? :) I will try to troubleshoot a little bit more.
  2. Do you think, that we should support any other protocols? Do you miss anything? From the codes in "show ip route" command the missing codes are: M-mobile, U-per-user static route, o-ODR, and P-periodic downloaded static route. Anyone using these "protocols"?

BR,

Uros

jedelman8 commented 8 years ago

The only thing failing right now is show_ip_route.

here is the template I'm testing:

Value Filldown Protocol (C|S|R|B|D|O|i)
Value Filldown Type (\w{0,2})
Value Required,Filldown Network ([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})
Value Filldown Mask (\/\d{1,2})
Value Distance (\d+)
Value Metric (\d+)
Value NexthopIP ([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})
Value NexthopIf ([\w\/]*)
Value Uptime ([0-9]{2}:[0-9]{2}:[0-9]{2})

Start
  ^Gateway.* -> Routes

Routes
  #
  # Match regular routes with all data in same line
  ^${Protocol}(\s|\*)${Type}\s+${Network}${Mask}\s\[${Distance}\/${Metric}\]\svia\s${NexthopIP}(,\s${Uptime}){0,1}(,\s${NexthopIf}){0,1} -> Record
  #
  # Clear all non Filldown variables when line started with network that is variably subnetted
  ^\s+[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}${Mask} -> Clear
  ^${Protocol}(\s|\*)${Type}\s+${Network}\s\[${Distance}\/${Metric}\]\svia\s${NexthopIP}(,\s${Uptime}){0,1}(,\s${NexthopIf}){0,1} -> Record
  #
  # Match load-balanced routes
  ^\s+\[${Distance}\/${Metric}\]\svia\s${NexthopIP} -> Record
  #
  # Match directly connected routes
  ^${Protocol}\s+${Network}\sis\sdirectly\sconnected,\s${NexthopIf} -> Record
  ^${Protocol}(\*){0,1}\s*${Network}${Mask}\sis\sdirectly\sconnected,\s${NexthopIf} -> Record
  #
  # Clear all variables on empty lines
  ^\s* -> Clearall

And here is raw file I'm testing (combines the original file with @ktbyers 's routes - notice spacing is diff on platforms).

Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP
D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
ia - IS-IS inter area, * - candidate default, U - per-user static route
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override

Gateway of last resort is 10.220.88.1 to network 0.0.0.0

S* 0.0.0.0/0 [1/0] via 10.220.88.1
10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C 10.220.88.0/24 is directly connected, FastEthernet4
L 10.220.88.20/32 is directly connected, FastEthernet4
     1.0.0.0/32 is subnetted, 1 subnets
S       1.1.1.1 [1/0] via 212.0.0.1
                [1/0] via 192.168.0.1
     2.0.0.0/24 is subnetted, 1 subnets
S       2.2.2.0 is directly connected, FastEthernet0/0
     4.0.0.0/16 is subnetted, 1 subnets
O E2    4.4.0.0 [110/20] via 194.0.0.2, 00:02:00, FastEthernet0/0
     5.0.0.0/24 is subnetted, 1 subnets
D EX    5.5.5.0 [170/2297856] via 10.0.1.2, 00:12:01, Serial0/0
     6.0.0.0/16 is subnetted, 1 subnets
B       6.6.0.0 [200/0] via 195.0.0.1, 00:00:04
     172.16.0.0/26 is subnetted, 1 subnets
i L2    172.16.1.0 [115/10] via 10.0.1.2, Serial0/0
     172.20.0.0/32 is subnetted, 3 subnets
O       172.20.1.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
O       172.20.3.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
O       172.20.2.1 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
     10.0.0.0/8 is variably subnetted, 5 subnets, 3 masks
C       10.0.1.0/24 is directly connected, Serial0/0
D       10.0.5.0/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
D       10.0.5.64/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
D       10.0.5.128/26 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
D       10.0.5.192/27 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
     192.168.0.0/32 is subnetted, 1 subnets
D       192.168.0.1 [90/2297856] via 10.0.1.2, 00:12:03, Serial0/0
O IA 195.0.0.0/24 [110/11] via 194.0.0.2, 00:05:45, FastEthernet0/0
O*E2 0.0.0.0/0 [110/1] via 194.0.0.2, 00:05:35, FastEthernet0/0
O E2 212.0.0.0/8 [110/20] via 194.0.0.2, 00:05:35, FastEthernet0/0
C    194.0.0.0/16 is directly connected, FastEthernet0/0

Native testing with textfsm is producing this:

FSM Table:
['Protocol', 'Type', 'Network', 'Mask', 'Distance', 'Metric', 'NexthopIP', 'NexthopIf', 'Uptime']
['S', '', '0.0.0.0', '/0', '1', '0', '10.220.88.1', '', '']
['C', '', '10.220.88.0', '/24', '', '', '', 'FastEthernet4', '']
['S', '', '1.1.1.1', '/32', '1', '0', '212.0.0.1', '', '']
['S', '', '1.1.1.1', '/32', '1', '0', '192.168.0.1', '', '']
['S', '', '2.2.2.0', '/24', '', '', '', 'FastEthernet0/0', '']
['O', 'E2', '4.4.0.0', '/16', '110', '20', '194.0.0.2', 'FastEthernet0/0', '00:02:00']
['D', 'EX', '5.5.5.0', '/24', '170', '2297856', '10.0.1.2', 'Serial0/0', '00:12:01']
['B', '', '6.6.0.0', '/16', '200', '0', '195.0.0.1', '', '00:00:04']
['i', 'L2', '172.16.1.0', '/26', '115', '10', '10.0.1.2', 'Serial0/0', '']
['O', '', '172.20.1.1', '/32', '110', '11', '194.0.0.2', 'FastEthernet0/0', '00:05:45']
['O', '', '172.20.3.1', '/32', '110', '11', '194.0.0.2', 'FastEthernet0/0', '00:05:45']
['O', '', '172.20.2.1', '/32', '110', '11', '194.0.0.2', 'FastEthernet0/0', '00:05:45']
['C', '', '10.0.1.0', '/24', '', '', '', 'Serial0/0', '']
['D', '', '10.0.5.0', '/26', '90', '2297856', '10.0.1.2', 'Serial0/0', '00:12:03']
['D', '', '10.0.5.64', '/26', '90', '2297856', '10.0.1.2', 'Serial0/0', '00:12:03']
['D', '', '10.0.5.128', '/26', '90', '2297856', '10.0.1.2', 'Serial0/0', '00:12:03']
['D', '', '10.0.5.192', '/27', '90', '2297856', '10.0.1.2', 'Serial0/0', '00:12:03']
['D', '', '192.168.0.1', '/32', '90', '2297856', '10.0.1.2', 'Serial0/0', '00:12:03']
['O', 'IA', '195.0.0.0', '/24', '110', '11', '194.0.0.2', 'FastEthernet0/0', '00:05:45']
['O', 'E2', '0.0.0.0', '/0', '110', '1', '194.0.0.2', 'FastEthernet0/0', '00:05:35']
['O', 'E2', '212.0.0.0', '/8', '110', '20', '194.0.0.2', 'FastEthernet0/0', '00:05:35']
['C', 'E2', '194.0.0.0', '/16', '', '', '', 'FastEthernet0/0', '']
['C', 'E2', '194.0.0.0', '/16', '', '', '', '', '']

Which is good minus the "extra" and almost duplicate route as the last entry. The odd thing is this extra route only happens when the hostname is not in the file (as the last line as such ROUTER#). I don't think we have that when using the actual module anyway, but would be nice to get this working as-is here too.

Note: I have removed Type from directly connected routes. But per @ubajze's previous comment, feel free to add it in... not sure it's needed since this is for directly connected routes.

BTW, if anyone submits a PR on this today, don't forget to update the parsed file :)

mzbenami commented 8 years ago

Fixed by #35

The main thing with the extra route at the end is solved by adding an explicit "EOF" to the bottom of the template. There is an implicit state that is entered called "EOF" and implicit action (Record) that is executed, when the end-of-file is reached. This records (outputs to the table) all the stored, but not yet recorded values. So if you're using Filldown, some columns may have values ready to be stored, but a "Record" statement hasn't been executed yet. In this case the implicit EOF state essentially flushes the buffer, even if it's not a complete row of a table.

From the TextFSM wiki (https://code.google.com/p/textfsm/wiki/TextFSMHowto):

If EOF was reached on the input then the EOF state is executed. This is an implicit state that looks like:

EOF
  ^.* -> Record
EOF records the current row before returning. To override this behavior - explicitly define an empty EOF state. like so:

EOF

The other issue on the test .parsed file is that values in the dictionary that are empty strings and numbers need quotes around them so they are correctly typed.

ubajze commented 8 years ago

@mzbenami Nice solution. Wasn't aware of that :)