Create Tables or Views for Complex Use Cases
You can create Tables/Views for complex use cases, such as a multi-path route lookup.
Let's say you need to find a routing path in your network, for example, do a route lookup. You need to find the route next-hop information, such as the next-hop IP address, outbound interface, and so on. In simple routing topologies, this is fairly trivial.
However, if you have complex MPLS environments with multi-path routing, this becomes more of a challenge. When you are troubleshooting or reporting routing paths in such an environment, how would you approach this task using the Junos PyEZ microframework?
Multi-path Route Lookup Example
Let's first take a look at a route lookup for 10.207.64.0/24 as an example to illustrate this process.
Junos OS CLI
01 |
jeremy@mx> show route 10.207.64.0/24 |
03 |
inet.0: 54 destinations, 183 routes (46 active, 0 holddown, 8 hidden) |
04 |
+ = Active Route, - = Last Active, * = Both |
06 |
10.207.64.0/24 *[BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.208 |
08 |
> to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123 |
09 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123 |
10 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123 |
11 |
to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123 |
12 |
[BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.240 |
14 |
> to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123 |
15 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123 |
16 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123 |
17 |
to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123 |
18 |
[BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.208 |
20 |
> to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456 |
21 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456 |
22 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456 |
23 |
to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456 |
24 |
[BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.240 |
26 |
> to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456 |
27 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456 |
28 |
to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456 |
29 |
to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456 |
Junos OS XML
Now let's examine the same data as XML output from the Junos OS API. As you can see, there are four route entries (<rt-entry>
) for the destination. Within each of those route entries there are a number of "next-hop" (<nh>
) items. Which one represents the one you want?
The answer is the first one, but this might not always be the case. Why is the first one the correct answer? You want the current active route, and this is designated by the <current-active>
element, found on line 7. Now which of the four <nh>
items do you want? You want the one that has the <selected-next-hop>
element, found on line 16.
Ok, so now that we know what we want, how do we map this into the Junos PyEZ Table/View mechanisms?
004 |
< rt-destination >10.207.64.0/24</ rt-destination > |
006 |
< active-tag >*</ active-tag > |
009 |
< protocol-name >BGP</ protocol-name > |
010 |
< preference >170</ preference > |
011 |
< age seconds = "5333608" >8w5d 17:33:28</ age > |
012 |
< local-preference >100</ local-preference > |
013 |
< learned-from >10.160.252.208</ learned-from > |
014 |
< as-path >99999 I</ as-path > |
017 |
< to >10.160.248.2</ to > |
018 |
< via >xe-1/3/0.0</ via > |
019 |
< lsp-name >LSP-ABC-123</ lsp-name > |
022 |
< to >10.160.248.6</ to > |
023 |
< via >xe-1/2/0.0</ via > |
024 |
< lsp-name >LSP-ABC-123</ lsp-name > |
027 |
< to >10.160.248.6</ to > |
028 |
< via >xe-1/2/0.0</ via > |
029 |
< lsp-name >LSP-ABC-123</ lsp-name > |
032 |
< to >10.160.248.2</ to > |
033 |
< via >xe-1/3/0.0</ via > |
034 |
< lsp-name >LSP-ABC-123</ lsp-name > |
038 |
< active-tag ></ active-tag > |
039 |
< protocol-name >BGP</ protocol-name > |
040 |
< preference >170</ preference > |
041 |
< age seconds = "5333608" >8w5d 17:33:28</ age > |
042 |
< local-preference >100</ local-preference > |
043 |
< learned-from >10.160.252.240</ learned-from > |
044 |
< as-path >99999 I</ as-path > |
047 |
< to >10.160.248.2</ to > |
048 |
< via >xe-1/3/0.0</ via > |
049 |
< lsp-name >LSP-ABC-123</ lsp-name > |
052 |
< to >10.160.248.6</ to > |
053 |
< via >xe-1/2/0.0</ via > |
054 |
< lsp-name >LSP-ABC-123</ lsp-name > |
057 |
< to >10.160.248.6</ to > |
058 |
< via >xe-1/2/0.0</ via > |
059 |
< lsp-name >LSP-ABC-123</ lsp-name > |
062 |
< to >10.160.248.2</ to > |
063 |
< via >xe-1/3/0.0</ via > |
064 |
< lsp-name >LSP-ABC-123</ lsp-name > |
068 |
< active-tag ></ active-tag > |
069 |
< protocol-name >BGP</ protocol-name > |
070 |
< preference >170</ preference > |
071 |
< age seconds = "5333608" >8w5d 17:33:28</ age > |
072 |
< local-preference >100</ local-preference > |
073 |
< learned-from >10.160.252.208</ learned-from > |
074 |
< as-path >99999 I</ as-path > |
077 |
< to >10.160.248.2</ to > |
078 |
< via >xe-1/3/0.0</ via > |
079 |
< lsp-name >LSP-DEF-456</ lsp-name > |
082 |
< to >10.160.248.6</ to > |
083 |
< via >xe-1/2/0.0</ via > |
084 |
< lsp-name >LSP-DEF-456</ lsp-name > |
087 |
< to >10.160.248.6</ to > |
088 |
< via >xe-1/2/0.0</ via > |
089 |
< lsp-name >LSP-DEF-456</ lsp-name > |
092 |
< to >10.160.248.2</ to > |
093 |
< via >xe-1/3/0.0</ via > |
094 |
< lsp-name >LSP-DEF-456</ lsp-name > |
098 |
< active-tag ></ active-tag > |
099 |
< protocol-name >BGP</ protocol-name > |
100 |
< preference >170</ preference > |
101 |
< age seconds = "5333608" >8w5d 17:33:28</ age > |
102 |
< local-preference >100</ local-preference > |
103 |
< learned-from >10.160.252.240</ learned-from > |
104 |
< as-path >99999 I</ as-path > |
107 |
< to >10.160.248.2</ to > |
108 |
< via >xe-1/3/0.0</ via > |
109 |
< lsp-name >LSP-DEF-456</ lsp-name > |
112 |
< to >10.160.248.6</ to > |
113 |
< via >xe-1/2/0.0</ via > |
114 |
< lsp-name >LSP-DEF-456</ lsp-name > |
117 |
< to >10.160.248.6</ to > |
118 |
< via >xe-1/2/0.0</ via > |
119 |
< lsp-name >LSP-DEF-456</ lsp-name > |
122 |
< to >10.160.248.2</ to > |
123 |
< via >xe-1/3/0.0</ via > |
124 |
< lsp-name >LSP-DEF-456</ lsp-name > |
Tables and Views
You can store your Table and View definitions in a simple YAML file. The definitions of these files are explained on the Junos PyEZ project pages you can find here. Take a look at the YAML below. Line 11 defines the XPath expression to extract what you are looking for.
03 |
rpc: get-route-information |
11 |
nh: 'rt-entry[current-active]/nh[selected-next-hop]' |
Let's examine that XPath expression in more detail. XPath is both powerful and difficult to master. So the whole point of the Junos PyEZ is that for one person to create the XPath magic, while everyone else simply uses the definitions to get what they want; in other words, they don't need to know XPath, Junos, and so on.
1 |
rt - entry[current - active] / nh[selected - next - hop] |
First, why does it start with rt-entry
? Because each table item is a <route-table/rt>
, as defined in line 5 of the YAML file. So every field/group is relative to that XML element. The <rt-entry>
element is a "child" of <route-table/rt>
, so we simply begin with it.
Next, what is [current-active]
? This is an XPath filter that means "only find <rt-entry>
element that has a <current-active>
element as a child element". The result of this filter would be the first <rt-entry>
in the XML output, lines 5 through 36. The cool thing about XPath expressions is that you can continue to chain them together. So we need to continue to filter.
Next is the /nh[selected-next-hop]
part of the XPath expression. This means "find the <nh>
element that has a<selected-next-hop>
child element".
The final result of the complete XPath expression is always the LAST element selected, which in this case is the <nh>
element.
On the Python Shell
Finally, let's see how to use this YAML file in a Python shell (or your program), and see how the Junos PyEZ works in practice for someone who doesn't know Junos/XML/XPath. Assume that you've stored the above YAML in a file called "mydefs.yml", and you have an established Device instance (dev
) to a remote Junos OS device.
05 |
>>> from jnpr.junos.factory import loadyaml |
06 |
>>> globals ().update( loadyaml( 'mydefs.yml' ) ) |
11 |
[ 'CurSelView' , 'RouteTable' , 'loadyaml' , 'dev' , (...other stuff ommitted)] |
15 |
>>> tbl = RouteTable(dev) |
21 |
>>> tbl.get( '10.207.64.0/24' ) |
22 |
RouteTable:your_device_name: 1 items |
28 |
>> find = tbl[ '10.207.64.0/24' ] |
Further Reading
If you are new to XML and XPath, I would recommend the W3schools website as a good primer. I would also very much recommend the XSLT 1.0 Pocket Guide.