{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Introduction to Route Computation and Analysis using Batfish"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Network engineers routinely need to validate routing and forwarding in the network. They often do that by connecting to multiple network devices and executing a series of `show route` commands. This distributed debugging is highly complex even in a moderately-sized network. Batfish makes this task extremely simple by providing an easy-to-query, centralized view of routing tables in the network. \n",
"\n",
"In this notebook, we will look at how you can extract routing information from Batfish.\n",
"\n",
"Check out a video demo of this notebook [here](https://www.youtube.com/watch?v=AutkFa0xUxg)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Import packages\n",
"%run startup.py\n",
"bf = Session(host=\"localhost\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initializing the Network and Snapshot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`SNAPSHOT_PATH` below can be updated to point to a custom snapshot directory, see the [Batfish instructions](https://github.com/batfish/batfish/wiki/Packaging-snapshots-for-analysis) for how to package data for analysis.
\n",
"More example networks are available in the [networks](https://github.com/batfish/batfish/tree/master/networks) folder of the Batfish repository."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'example_snapshot'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Initialize a network and snapshot\n",
"NETWORK_NAME = \"example_network\"\n",
"SNAPSHOT_NAME = \"example_snapshot\"\n",
"\n",
"SNAPSHOT_PATH = \"networks/example\"\n",
"\n",
"bf.set_network(NETWORK_NAME)\n",
"bf.init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The network snapshot that we initialized above is illustrated below. You can download/view devices' configuration files [here](https://github.com/batfish/pybatfish/tree/master/jupyter_notebooks/networks/example).\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All of the information we will show you in this notebook is dynamically computed by Batfish based on the configuration files for the network devices."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### View Routing Tables for ALL devices and ALL VRFs\n",
"Batfish makes **all** routing tables in the network easily accessible. Let's take a look at how you can retrieve the specific information you want."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Get routing tables for all nodes and VRFs\n",
"routes_all = bf.q.routes().answer().frame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are not going to print this table as it has a large number of entries. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### View Routing Tables for default VRF on AS1 border routers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are 2 ways that we can get the desired subset of data: "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Option 1) Only request that information from Batfish by passing in parameters into the `routes()` question. This is useful to do when you need to reduce the amount of data being returned, but is limited to regex filtering based on VRF, Node, Protocol and Network."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Option 2) Filter the output of the `routes()` question using the Pandas [APIs](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.filter.html)."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"?bf.q.routes"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Get the routing table for the 'default' VRF on border routers of as1\n",
"# using BF parameters\n",
"routes_as1border = bf.q.routes(nodes=\"/as1border/\", vrfs=\"default\").answer().frame()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Node | \n",
" VRF | \n",
" Network | \n",
" Next_Hop | \n",
" Protocol | \n",
" Metric | \n",
" Admin_Distance | \n",
" Tag | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" as1border1 | \n",
" default | \n",
" 1.0.1.0/24 | \n",
" interface GigabitEthernet0/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 1 | \n",
" as1border1 | \n",
" default | \n",
" 1.0.1.1/32 | \n",
" interface GigabitEthernet0/0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 2 | \n",
" as1border1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" interface GigabitEthernet0/0 ip 1.0.1.2 | \n",
" ospf | \n",
" 2 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 3 | \n",
" as1border1 | \n",
" default | \n",
" 1.1.1.1/32 | \n",
" interface Loopback0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 4 | \n",
" as1border1 | \n",
" default | \n",
" 1.2.2.2/32 | \n",
" interface GigabitEthernet0/0 ip 1.0.1.2 | \n",
" ospf | \n",
" 3 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 5 | \n",
" as1border1 | \n",
" default | \n",
" 1.10.1.1/32 | \n",
" interface GigabitEthernet0/0 ip 1.0.1.2 | \n",
" ospf | \n",
" 2 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 6 | \n",
" as1border1 | \n",
" default | \n",
" 2.128.0.0/16 | \n",
" ip 10.12.11.2 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 7 | \n",
" as1border1 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 10.13.22.3 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 8 | \n",
" as1border1 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 10.13.22.3 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 9 | \n",
" as1border1 | \n",
" default | \n",
" 10.12.11.0/24 | \n",
" interface GigabitEthernet1/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 10 | \n",
" as1border1 | \n",
" default | \n",
" 10.12.11.1/32 | \n",
" interface GigabitEthernet1/0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 11 | \n",
" as1border1 | \n",
" default | \n",
" 10.13.22.0/24 | \n",
" interface GigabitEthernet0/0 ip 1.0.1.2 | \n",
" ospfE2 | \n",
" 20 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 12 | \n",
" as1border1 | \n",
" default | \n",
" 10.14.22.0/24 | \n",
" interface GigabitEthernet0/0 ip 1.0.1.2 | \n",
" ospfE2 | \n",
" 20 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 13 | \n",
" as1border2 | \n",
" default | \n",
" 1.0.1.0/24 | \n",
" interface GigabitEthernet1/0 ip 1.0.2.2 | \n",
" ospf | \n",
" 2 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 14 | \n",
" as1border2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" interface GigabitEthernet1/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 15 | \n",
" as1border2 | \n",
" default | \n",
" 1.0.2.1/32 | \n",
" interface GigabitEthernet1/0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 16 | \n",
" as1border2 | \n",
" default | \n",
" 1.1.1.1/32 | \n",
" interface GigabitEthernet1/0 ip 1.0.2.2 | \n",
" ospf | \n",
" 3 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 17 | \n",
" as1border2 | \n",
" default | \n",
" 1.2.2.2/32 | \n",
" interface Loopback0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 18 | \n",
" as1border2 | \n",
" default | \n",
" 1.10.1.1/32 | \n",
" interface GigabitEthernet1/0 ip 1.0.2.2 | \n",
" ospf | \n",
" 2 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 19 | \n",
" as1border2 | \n",
" default | \n",
" 2.128.0.0/16 | \n",
" ip 10.12.11.2 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 20 | \n",
" as1border2 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 10.13.22.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 21 | \n",
" as1border2 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 10.13.22.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 22 | \n",
" as1border2 | \n",
" default | \n",
" 10.12.11.0/24 | \n",
" interface GigabitEthernet1/0 ip 1.0.2.2 | \n",
" ospfE2 | \n",
" 20 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 23 | \n",
" as1border2 | \n",
" default | \n",
" 10.13.22.0/24 | \n",
" interface GigabitEthernet0/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 24 | \n",
" as1border2 | \n",
" default | \n",
" 10.13.22.1/32 | \n",
" interface GigabitEthernet0/0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 25 | \n",
" as1border2 | \n",
" default | \n",
" 10.14.22.0/24 | \n",
" interface GigabitEthernet2/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 26 | \n",
" as1border2 | \n",
" default | \n",
" 10.14.22.1/32 | \n",
" interface GigabitEthernet2/0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Node VRF Network \\\n",
"0 as1border1 default 1.0.1.0/24 \n",
"1 as1border1 default 1.0.1.1/32 \n",
"2 as1border1 default 1.0.2.0/24 \n",
"3 as1border1 default 1.1.1.1/32 \n",
"4 as1border1 default 1.2.2.2/32 \n",
"5 as1border1 default 1.10.1.1/32 \n",
"6 as1border1 default 2.128.0.0/16 \n",
"7 as1border1 default 3.0.1.0/24 \n",
"8 as1border1 default 3.0.2.0/24 \n",
"9 as1border1 default 10.12.11.0/24 \n",
"10 as1border1 default 10.12.11.1/32 \n",
"11 as1border1 default 10.13.22.0/24 \n",
"12 as1border1 default 10.14.22.0/24 \n",
"13 as1border2 default 1.0.1.0/24 \n",
"14 as1border2 default 1.0.2.0/24 \n",
"15 as1border2 default 1.0.2.1/32 \n",
"16 as1border2 default 1.1.1.1/32 \n",
"17 as1border2 default 1.2.2.2/32 \n",
"18 as1border2 default 1.10.1.1/32 \n",
"19 as1border2 default 2.128.0.0/16 \n",
"20 as1border2 default 3.0.1.0/24 \n",
"21 as1border2 default 3.0.2.0/24 \n",
"22 as1border2 default 10.12.11.0/24 \n",
"23 as1border2 default 10.13.22.0/24 \n",
"24 as1border2 default 10.13.22.1/32 \n",
"25 as1border2 default 10.14.22.0/24 \n",
"26 as1border2 default 10.14.22.1/32 \n",
"\n",
" Next_Hop Protocol Metric Admin_Distance \\\n",
"0 interface GigabitEthernet0/0 connected 0 0 \n",
"1 interface GigabitEthernet0/0 local 0 0 \n",
"2 interface GigabitEthernet0/0 ip 1.0.1.2 ospf 2 110 \n",
"3 interface Loopback0 connected 0 0 \n",
"4 interface GigabitEthernet0/0 ip 1.0.1.2 ospf 3 110 \n",
"5 interface GigabitEthernet0/0 ip 1.0.1.2 ospf 2 110 \n",
"6 ip 10.12.11.2 bgp 50 20 \n",
"7 ip 10.13.22.3 ibgp 50 200 \n",
"8 ip 10.13.22.3 ibgp 50 200 \n",
"9 interface GigabitEthernet1/0 connected 0 0 \n",
"10 interface GigabitEthernet1/0 local 0 0 \n",
"11 interface GigabitEthernet0/0 ip 1.0.1.2 ospfE2 20 110 \n",
"12 interface GigabitEthernet0/0 ip 1.0.1.2 ospfE2 20 110 \n",
"13 interface GigabitEthernet1/0 ip 1.0.2.2 ospf 2 110 \n",
"14 interface GigabitEthernet1/0 connected 0 0 \n",
"15 interface GigabitEthernet1/0 local 0 0 \n",
"16 interface GigabitEthernet1/0 ip 1.0.2.2 ospf 3 110 \n",
"17 interface Loopback0 connected 0 0 \n",
"18 interface GigabitEthernet1/0 ip 1.0.2.2 ospf 2 110 \n",
"19 ip 10.12.11.2 ibgp 50 200 \n",
"20 ip 10.13.22.3 bgp 50 20 \n",
"21 ip 10.13.22.3 bgp 50 20 \n",
"22 interface GigabitEthernet1/0 ip 1.0.2.2 ospfE2 20 110 \n",
"23 interface GigabitEthernet0/0 connected 0 0 \n",
"24 interface GigabitEthernet0/0 local 0 0 \n",
"25 interface GigabitEthernet2/0 connected 0 0 \n",
"26 interface GigabitEthernet2/0 local 0 0 \n",
"\n",
" Tag \n",
"0 None \n",
"1 None \n",
"2 None \n",
"3 None \n",
"4 None \n",
"5 None \n",
"6 None \n",
"7 None \n",
"8 None \n",
"9 None \n",
"10 None \n",
"11 None \n",
"12 None \n",
"13 None \n",
"14 None \n",
"15 None \n",
"16 None \n",
"17 None \n",
"18 None \n",
"19 None \n",
"20 None \n",
"21 None \n",
"22 None \n",
"23 None \n",
"24 None \n",
"25 None \n",
"26 None "
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Get the routing table for the 'default' VRF on border routers of as1\n",
"# using Pandas filtering\n",
"routes_as1border = routes_all[(routes_all['Node'].str.contains('as1border')) & (routes_all['VRF'] == 'default')]\n",
"routes_as1border"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### View BGP learnt routes for default VRF on AS1 border routers"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Getting BGP routes in the routing table for the 'default' VRF on border routers of as1\n",
"# using BF parameters\n",
"routes_as1border_bgp = bf.q.routes(nodes=\"/as1border/\", vrfs=\"default\", protocols=\"bgp\").answer().frame()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Node | \n",
" VRF | \n",
" Network | \n",
" Next_Hop | \n",
" Protocol | \n",
" Metric | \n",
" Admin_Distance | \n",
" Tag | \n",
"
\n",
" \n",
" \n",
" \n",
" | 6 | \n",
" as1border1 | \n",
" default | \n",
" 2.128.0.0/16 | \n",
" ip 10.12.11.2 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 20 | \n",
" as1border2 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 10.13.22.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 21 | \n",
" as1border2 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 10.13.22.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Node VRF Network Next_Hop Protocol Metric \\\n",
"6 as1border1 default 2.128.0.0/16 ip 10.12.11.2 bgp 50 \n",
"20 as1border2 default 3.0.1.0/24 ip 10.13.22.3 bgp 50 \n",
"21 as1border2 default 3.0.2.0/24 ip 10.13.22.3 bgp 50 \n",
"\n",
" Admin_Distance Tag \n",
"6 20 None \n",
"20 20 None \n",
"21 20 None "
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Geting BGP routes in the routing table for the 'default' VRF on border routers of as1\n",
"# using Pandas filtering\n",
"routes_as1border_bgp = routes_all[(routes_all['Node'].str.contains('as1border')) & (routes_all['VRF'] == 'default') & (routes_all['Protocol'] == 'bgp')]\n",
"routes_as1border_bgp"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### View BGP learnt routes for ALL VRFs on ALL routers with Metric >=50\n",
"We cannot pass in `metric` as a parameter to Batfish, so this task is best handled with the Pandas API."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Node | \n",
" VRF | \n",
" Network | \n",
" Next_Hop | \n",
" Protocol | \n",
" Metric | \n",
" Admin_Distance | \n",
" Tag | \n",
"
\n",
" \n",
" \n",
" \n",
" | 6 | \n",
" as1border1 | \n",
" default | \n",
" 2.128.0.0/16 | \n",
" ip 10.12.11.2 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 20 | \n",
" as1border2 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 10.13.22.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 21 | \n",
" as1border2 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 10.13.22.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 40 | \n",
" as2border1 | \n",
" default | \n",
" 1.0.1.0/24 | \n",
" ip 10.12.11.1 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 41 | \n",
" as2border1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 106 | \n",
" as2border2 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 10.23.21.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 107 | \n",
" as2border2 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 10.23.21.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 182 | \n",
" as2dept1 | \n",
" default | \n",
" 1.0.1.0/24 | \n",
" ip 2.34.101.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 183 | \n",
" as2dept1 | \n",
" default | \n",
" 1.0.1.0/24 | \n",
" ip 2.34.201.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 184 | \n",
" as2dept1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 2.34.101.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 185 | \n",
" as2dept1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 2.34.201.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 195 | \n",
" as2dept1 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 2.34.101.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 196 | \n",
" as2dept1 | \n",
" default | \n",
" 3.0.1.0/24 | \n",
" ip 2.34.201.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 197 | \n",
" as2dept1 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 2.34.101.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 198 | \n",
" as2dept1 | \n",
" default | \n",
" 3.0.2.0/24 | \n",
" ip 2.34.201.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 226 | \n",
" as2dist1 | \n",
" default | \n",
" 2.128.0.0/24 | \n",
" ip 2.34.101.4 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 227 | \n",
" as2dist1 | \n",
" default | \n",
" 2.128.1.0/24 | \n",
" ip 2.34.101.4 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 261 | \n",
" as2dist2 | \n",
" default | \n",
" 2.128.0.0/24 | \n",
" ip 2.34.201.4 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 262 | \n",
" as2dist2 | \n",
" default | \n",
" 2.128.1.0/24 | \n",
" ip 2.34.201.4 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 271 | \n",
" as3border1 | \n",
" default | \n",
" 2.128.0.0/16 | \n",
" ip 10.23.21.2 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 281 | \n",
" as3border2 | \n",
" default | \n",
" 1.0.1.0/24 | \n",
" ip 10.13.22.1 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 282 | \n",
" as3border2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.13.22.1 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Node VRF Network Next_Hop Protocol Metric \\\n",
"6 as1border1 default 2.128.0.0/16 ip 10.12.11.2 bgp 50 \n",
"20 as1border2 default 3.0.1.0/24 ip 10.13.22.3 bgp 50 \n",
"21 as1border2 default 3.0.2.0/24 ip 10.13.22.3 bgp 50 \n",
"40 as2border1 default 1.0.1.0/24 ip 10.12.11.1 bgp 50 \n",
"41 as2border1 default 1.0.2.0/24 ip 10.12.11.1 bgp 50 \n",
"106 as2border2 default 3.0.1.0/24 ip 10.23.21.3 bgp 50 \n",
"107 as2border2 default 3.0.2.0/24 ip 10.23.21.3 bgp 50 \n",
"182 as2dept1 default 1.0.1.0/24 ip 2.34.101.3 bgp 50 \n",
"183 as2dept1 default 1.0.1.0/24 ip 2.34.201.3 bgp 50 \n",
"184 as2dept1 default 1.0.2.0/24 ip 2.34.101.3 bgp 50 \n",
"185 as2dept1 default 1.0.2.0/24 ip 2.34.201.3 bgp 50 \n",
"195 as2dept1 default 3.0.1.0/24 ip 2.34.101.3 bgp 50 \n",
"196 as2dept1 default 3.0.1.0/24 ip 2.34.201.3 bgp 50 \n",
"197 as2dept1 default 3.0.2.0/24 ip 2.34.101.3 bgp 50 \n",
"198 as2dept1 default 3.0.2.0/24 ip 2.34.201.3 bgp 50 \n",
"226 as2dist1 default 2.128.0.0/24 ip 2.34.101.4 bgp 50 \n",
"227 as2dist1 default 2.128.1.0/24 ip 2.34.101.4 bgp 50 \n",
"261 as2dist2 default 2.128.0.0/24 ip 2.34.201.4 bgp 50 \n",
"262 as2dist2 default 2.128.1.0/24 ip 2.34.201.4 bgp 50 \n",
"271 as3border1 default 2.128.0.0/16 ip 10.23.21.2 bgp 50 \n",
"281 as3border2 default 1.0.1.0/24 ip 10.13.22.1 bgp 50 \n",
"282 as3border2 default 1.0.2.0/24 ip 10.13.22.1 bgp 50 \n",
"\n",
" Admin_Distance Tag \n",
"6 20 None \n",
"20 20 None \n",
"21 20 None \n",
"40 20 None \n",
"41 20 None \n",
"106 20 None \n",
"107 20 None \n",
"182 20 None \n",
"183 20 None \n",
"184 20 None \n",
"185 20 None \n",
"195 20 None \n",
"196 20 None \n",
"197 20 None \n",
"198 20 None \n",
"226 20 None \n",
"227 20 None \n",
"261 20 None \n",
"262 20 None \n",
"271 20 None \n",
"281 20 None \n",
"282 20 None "
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"routes_filtered = routes_all[(routes_all['Protocol'] == 'bgp') & (routes_all['Metric'] >= 50)]\n",
"routes_filtered"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### View the routing entries for network 1.0.2.0/24 on ALL routers in ALL VRFs"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# grab the route table entry for network 1.0.2.0/24 from all routers in all VRFs\n",
"# using BF parameters\n",
"routes_filtered = bf.q.routes(network=\"1.0.2.0/24\").answer().frame()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Node | \n",
" VRF | \n",
" Network | \n",
" Next_Hop | \n",
" Protocol | \n",
" Metric | \n",
" Admin_Distance | \n",
" Tag | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2 | \n",
" as1border1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" interface GigabitEthernet0/0 ip 1.0.1.2 | \n",
" ospf | \n",
" 2 | \n",
" 110 | \n",
" None | \n",
"
\n",
" \n",
" | 14 | \n",
" as1border2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" interface GigabitEthernet1/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 29 | \n",
" as1core1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" interface GigabitEthernet0/0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 41 | \n",
" as2border1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 77 | \n",
" as2border2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 113 | \n",
" as2core1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 148 | \n",
" as2core2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 184 | \n",
" as2dept1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 2.34.101.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 185 | \n",
" as2dept1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 2.34.201.3 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 200 | \n",
" as2dist1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 235 | \n",
" as2dist2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.12.11.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 270 | \n",
" as3border1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.13.22.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
" | 282 | \n",
" as3border2 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.13.22.1 | \n",
" bgp | \n",
" 50 | \n",
" 20 | \n",
" None | \n",
"
\n",
" \n",
" | 294 | \n",
" as3core1 | \n",
" default | \n",
" 1.0.2.0/24 | \n",
" ip 10.13.22.1 | \n",
" ibgp | \n",
" 50 | \n",
" 200 | \n",
" None | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Node VRF Network Next_Hop \\\n",
"2 as1border1 default 1.0.2.0/24 interface GigabitEthernet0/0 ip 1.0.1.2 \n",
"14 as1border2 default 1.0.2.0/24 interface GigabitEthernet1/0 \n",
"29 as1core1 default 1.0.2.0/24 interface GigabitEthernet0/0 \n",
"41 as2border1 default 1.0.2.0/24 ip 10.12.11.1 \n",
"77 as2border2 default 1.0.2.0/24 ip 10.12.11.1 \n",
"113 as2core1 default 1.0.2.0/24 ip 10.12.11.1 \n",
"148 as2core2 default 1.0.2.0/24 ip 10.12.11.1 \n",
"184 as2dept1 default 1.0.2.0/24 ip 2.34.101.3 \n",
"185 as2dept1 default 1.0.2.0/24 ip 2.34.201.3 \n",
"200 as2dist1 default 1.0.2.0/24 ip 10.12.11.1 \n",
"235 as2dist2 default 1.0.2.0/24 ip 10.12.11.1 \n",
"270 as3border1 default 1.0.2.0/24 ip 10.13.22.1 \n",
"282 as3border2 default 1.0.2.0/24 ip 10.13.22.1 \n",
"294 as3core1 default 1.0.2.0/24 ip 10.13.22.1 \n",
"\n",
" Protocol Metric Admin_Distance Tag \n",
"2 ospf 2 110 None \n",
"14 connected 0 0 None \n",
"29 connected 0 0 None \n",
"41 bgp 50 20 None \n",
"77 ibgp 50 200 None \n",
"113 ibgp 50 200 None \n",
"148 ibgp 50 200 None \n",
"184 bgp 50 20 None \n",
"185 bgp 50 20 None \n",
"200 ibgp 50 200 None \n",
"235 ibgp 50 200 None \n",
"270 ibgp 50 200 None \n",
"282 bgp 50 20 None \n",
"294 ibgp 50 200 None "
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# grab the route table entry for network 1.0.2.0/24 from all routers in all VRFs\n",
"# using Pandas filtering\n",
"routes_filtered = routes_all[routes_all['Network'] == \"1.0.2.0/24\"]\n",
"routes_filtered"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using Panda's filtering it is easy to retrieve the list of nodes which have the network in the routing table for at least 1 VRF. This type of processing should always be done using the Pandas APIs."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['as1border1', 'as1border2', 'as1core1', 'as2border1', 'as2border2', 'as2core1', 'as2core2', 'as2dept1', 'as2dist1', 'as2dist2', 'as3border1', 'as3border2', 'as3core1']\n"
]
}
],
"source": [
"# Get the list of nodes that have the network 1.0.2.0/24 in at least 1 VRF\n",
"# the .unique function removes duplicate entries that would have been returned if the network was in multiple VRFs on a node or there were\n",
"# multiple route entries for the network (ECMP)\n",
"print(sorted(routes_filtered[\"Node\"].unique()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we will retrieve the list of nodes that do NOT have this prefix in their routing table. This is easy to do with the Pandas [groupby](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html) and [filter](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.core.groupby.DataFrameGroupBy.filter.html) functions."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['host1', 'host2']\n"
]
}
],
"source": [
"# Group all routes by Node and filter for those that don't have '1.0.2.0/24'\n",
"routes_filtered = routes_all.groupby('Node').filter(lambda x: all(x['Network'] != '1.0.2.0/24'))\n",
"\n",
"# Get the unique node names and sort the list\n",
"print(sorted(routes_filtered[\"Node\"].unique()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The only devices that do not have a route to **1.0.2.0/24** are the 2 hosts in the snapshot. This is expected, as they should just have a default route. Let's verify that."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Node | \n",
" VRF | \n",
" Network | \n",
" Next_Hop | \n",
" Protocol | \n",
" Metric | \n",
" Admin_Distance | \n",
" Tag | \n",
"
\n",
" \n",
" \n",
" \n",
" | 309 | \n",
" host1 | \n",
" default | \n",
" 0.0.0.0/0 | \n",
" interface eth0 ip 2.128.0.1 | \n",
" static | \n",
" 0 | \n",
" 1 | \n",
" None | \n",
"
\n",
" \n",
" | 310 | \n",
" host1 | \n",
" default | \n",
" 2.128.0.0/24 | \n",
" interface eth0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 311 | \n",
" host1 | \n",
" default | \n",
" 2.128.0.101/32 | \n",
" interface eth0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 312 | \n",
" host2 | \n",
" default | \n",
" 0.0.0.0/0 | \n",
" interface eth0 ip 2.128.1.1 | \n",
" static | \n",
" 0 | \n",
" 1 | \n",
" None | \n",
"
\n",
" \n",
" | 313 | \n",
" host2 | \n",
" default | \n",
" 2.128.1.0/24 | \n",
" interface eth0 | \n",
" connected | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
" | 314 | \n",
" host2 | \n",
" default | \n",
" 2.128.1.101/32 | \n",
" interface eth0 | \n",
" local | \n",
" 0 | \n",
" 0 | \n",
" None | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Node VRF Network Next_Hop Protocol \\\n",
"309 host1 default 0.0.0.0/0 interface eth0 ip 2.128.0.1 static \n",
"310 host1 default 2.128.0.0/24 interface eth0 connected \n",
"311 host1 default 2.128.0.101/32 interface eth0 local \n",
"312 host2 default 0.0.0.0/0 interface eth0 ip 2.128.1.1 static \n",
"313 host2 default 2.128.1.0/24 interface eth0 connected \n",
"314 host2 default 2.128.1.101/32 interface eth0 local \n",
"\n",
" Metric Admin_Distance Tag \n",
"309 0 1 None \n",
"310 0 0 None \n",
"311 0 0 None \n",
"312 0 1 None \n",
"313 0 0 None \n",
"314 0 0 None "
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"routes_all[routes_all['Node'].str.contains('host')]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With Batfish and Pandas you can easily retrieve the exact information you are looking for from the routing tables on ANY or ALL network devices for ANY or ALL VRFs."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This concludes the notebook. To recap, in this notebook we covered the foundational tasks for route analysis:\n",
"\n",
"1. How to get routes at all nodes in the network or only at a subset of them\n",
"2. How to retrieve routing entries that match a specific protocol or metric\n",
"3. How to find which nodes have an entry for a prefix or which ones do not\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We hope you found this notebook useful and informative. Future notebooks will dive into more advanced topics like path analysis, debugging ACLs and firewall rules, validating routing policy, etc.. so stay tuned! "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Want to know more? "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Reach out to us through [Slack](https://join.slack.com/t/batfish-org/shared_invite/enQtMzA0Nzg2OTAzNzQ1LTcyYzY3M2Q0NWUyYTRhYjdlM2IzYzRhZGU1NWFlNGU2MzlhNDY3OTJmMDIyMjQzYmRlNjhkMTRjNWIwNTUwNTQ`) or [GitHub](https://github.com/batfish/batfish) to learn more, or send feedback."
]
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}