{ "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", "![example-network](https://raw.githubusercontent.com/batfish/pybatfish/master/jupyter_notebooks/networks/example/example-network.png)" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NodeVRFNetworkNext_HopNext_Hop_IPNext_Hop_InterfaceProtocolMetricAdmin_DistanceTag
0as1border1default1.0.1.0/24interface GigabitEthernet0/0AUTO/NONE(-1l)GigabitEthernet0/0connected00None
1as1border1default1.0.1.1/32interface GigabitEthernet0/0AUTO/NONE(-1l)GigabitEthernet0/0local00None
2as1border1default1.0.2.0/24interface GigabitEthernet0/0 ip 1.0.1.21.0.1.2GigabitEthernet0/0ospf2110None
3as1border1default1.1.1.1/32interface Loopback0AUTO/NONE(-1l)Loopback0connected00None
4as1border1default1.2.2.2/32interface GigabitEthernet0/0 ip 1.0.1.21.0.1.2GigabitEthernet0/0ospf3110None
5as1border1default1.10.1.1/32interface GigabitEthernet0/0 ip 1.0.1.21.0.1.2GigabitEthernet0/0ospf2110None
6as1border1default2.128.0.0/16ip 10.12.11.210.12.11.2dynamicbgp5020None
7as1border1default3.0.1.0/24ip 10.13.22.310.13.22.3dynamicibgp50200None
8as1border1default3.0.2.0/24ip 10.13.22.310.13.22.3dynamicibgp50200None
9as1border1default10.12.11.0/24interface GigabitEthernet1/0AUTO/NONE(-1l)GigabitEthernet1/0connected00None
10as1border1default10.12.11.1/32interface GigabitEthernet1/0AUTO/NONE(-1l)GigabitEthernet1/0local00None
11as1border1default10.13.22.0/24interface GigabitEthernet0/0 ip 1.0.1.21.0.1.2GigabitEthernet0/0ospfE220110None
12as1border1default10.14.22.0/24interface GigabitEthernet0/0 ip 1.0.1.21.0.1.2GigabitEthernet0/0ospfE220110None
13as1border2default1.0.1.0/24interface GigabitEthernet1/0 ip 1.0.2.21.0.2.2GigabitEthernet1/0ospf2110None
14as1border2default1.0.2.0/24interface GigabitEthernet1/0AUTO/NONE(-1l)GigabitEthernet1/0connected00None
15as1border2default1.0.2.1/32interface GigabitEthernet1/0AUTO/NONE(-1l)GigabitEthernet1/0local00None
16as1border2default1.1.1.1/32interface GigabitEthernet1/0 ip 1.0.2.21.0.2.2GigabitEthernet1/0ospf3110None
17as1border2default1.2.2.2/32interface Loopback0AUTO/NONE(-1l)Loopback0connected00None
18as1border2default1.10.1.1/32interface GigabitEthernet1/0 ip 1.0.2.21.0.2.2GigabitEthernet1/0ospf2110None
19as1border2default2.128.0.0/16ip 10.12.11.210.12.11.2dynamicibgp50200None
20as1border2default3.0.1.0/24ip 10.13.22.310.13.22.3dynamicbgp5020None
21as1border2default3.0.2.0/24ip 10.13.22.310.13.22.3dynamicbgp5020None
22as1border2default10.12.11.0/24interface GigabitEthernet1/0 ip 1.0.2.21.0.2.2GigabitEthernet1/0ospfE220110None
23as1border2default10.13.22.0/24interface GigabitEthernet0/0AUTO/NONE(-1l)GigabitEthernet0/0connected00None
24as1border2default10.13.22.1/32interface GigabitEthernet0/0AUTO/NONE(-1l)GigabitEthernet0/0local00None
25as1border2default10.14.22.0/24interface GigabitEthernet2/0AUTO/NONE(-1l)GigabitEthernet2/0connected00None
26as1border2default10.14.22.1/32interface GigabitEthernet2/0AUTO/NONE(-1l)GigabitEthernet2/0local00None
\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 Next_Hop_IP \\\n", "0 interface GigabitEthernet0/0 AUTO/NONE(-1l) \n", "1 interface GigabitEthernet0/0 AUTO/NONE(-1l) \n", "2 interface GigabitEthernet0/0 ip 1.0.1.2 1.0.1.2 \n", "3 interface Loopback0 AUTO/NONE(-1l) \n", "4 interface GigabitEthernet0/0 ip 1.0.1.2 1.0.1.2 \n", "5 interface GigabitEthernet0/0 ip 1.0.1.2 1.0.1.2 \n", "6 ip 10.12.11.2 10.12.11.2 \n", "7 ip 10.13.22.3 10.13.22.3 \n", "8 ip 10.13.22.3 10.13.22.3 \n", "9 interface GigabitEthernet1/0 AUTO/NONE(-1l) \n", "10 interface GigabitEthernet1/0 AUTO/NONE(-1l) \n", "11 interface GigabitEthernet0/0 ip 1.0.1.2 1.0.1.2 \n", "12 interface GigabitEthernet0/0 ip 1.0.1.2 1.0.1.2 \n", "13 interface GigabitEthernet1/0 ip 1.0.2.2 1.0.2.2 \n", "14 interface GigabitEthernet1/0 AUTO/NONE(-1l) \n", "15 interface GigabitEthernet1/0 AUTO/NONE(-1l) \n", "16 interface GigabitEthernet1/0 ip 1.0.2.2 1.0.2.2 \n", "17 interface Loopback0 AUTO/NONE(-1l) \n", "18 interface GigabitEthernet1/0 ip 1.0.2.2 1.0.2.2 \n", "19 ip 10.12.11.2 10.12.11.2 \n", "20 ip 10.13.22.3 10.13.22.3 \n", "21 ip 10.13.22.3 10.13.22.3 \n", "22 interface GigabitEthernet1/0 ip 1.0.2.2 1.0.2.2 \n", "23 interface GigabitEthernet0/0 AUTO/NONE(-1l) \n", "24 interface GigabitEthernet0/0 AUTO/NONE(-1l) \n", "25 interface GigabitEthernet2/0 AUTO/NONE(-1l) \n", "26 interface GigabitEthernet2/0 AUTO/NONE(-1l) \n", "\n", " Next_Hop_Interface Protocol Metric Admin_Distance Tag \n", "0 GigabitEthernet0/0 connected 0 0 None \n", "1 GigabitEthernet0/0 local 0 0 None \n", "2 GigabitEthernet0/0 ospf 2 110 None \n", "3 Loopback0 connected 0 0 None \n", "4 GigabitEthernet0/0 ospf 3 110 None \n", "5 GigabitEthernet0/0 ospf 2 110 None \n", "6 dynamic bgp 50 20 None \n", "7 dynamic ibgp 50 200 None \n", "8 dynamic ibgp 50 200 None \n", "9 GigabitEthernet1/0 connected 0 0 None \n", "10 GigabitEthernet1/0 local 0 0 None \n", "11 GigabitEthernet0/0 ospfE2 20 110 None \n", "12 GigabitEthernet0/0 ospfE2 20 110 None \n", "13 GigabitEthernet1/0 ospf 2 110 None \n", "14 GigabitEthernet1/0 connected 0 0 None \n", "15 GigabitEthernet1/0 local 0 0 None \n", "16 GigabitEthernet1/0 ospf 3 110 None \n", "17 Loopback0 connected 0 0 None \n", "18 GigabitEthernet1/0 ospf 2 110 None \n", "19 dynamic ibgp 50 200 None \n", "20 dynamic bgp 50 20 None \n", "21 dynamic bgp 50 20 None \n", "22 GigabitEthernet1/0 ospfE2 20 110 None \n", "23 GigabitEthernet0/0 connected 0 0 None \n", "24 GigabitEthernet0/0 local 0 0 None \n", "25 GigabitEthernet2/0 connected 0 0 None \n", "26 GigabitEthernet2/0 local 0 0 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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NodeVRFNetworkNext_HopNext_Hop_IPNext_Hop_InterfaceProtocolMetricAdmin_DistanceTag
6as1border1default2.128.0.0/16ip 10.12.11.210.12.11.2dynamicbgp5020None
20as1border2default3.0.1.0/24ip 10.13.22.310.13.22.3dynamicbgp5020None
21as1border2default3.0.2.0/24ip 10.13.22.310.13.22.3dynamicbgp5020None
\n", "
" ], "text/plain": [ " Node VRF Network Next_Hop Next_Hop_IP \\\n", "6 as1border1 default 2.128.0.0/16 ip 10.12.11.2 10.12.11.2 \n", "20 as1border2 default 3.0.1.0/24 ip 10.13.22.3 10.13.22.3 \n", "21 as1border2 default 3.0.2.0/24 ip 10.13.22.3 10.13.22.3 \n", "\n", " Next_Hop_Interface Protocol Metric Admin_Distance Tag \n", "6 dynamic bgp 50 20 None \n", "20 dynamic bgp 50 20 None \n", "21 dynamic bgp 50 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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NodeVRFNetworkNext_HopNext_Hop_IPNext_Hop_InterfaceProtocolMetricAdmin_DistanceTag
6as1border1default2.128.0.0/16ip 10.12.11.210.12.11.2dynamicbgp5020None
20as1border2default3.0.1.0/24ip 10.13.22.310.13.22.3dynamicbgp5020None
21as1border2default3.0.2.0/24ip 10.13.22.310.13.22.3dynamicbgp5020None
40as2border1default1.0.1.0/24ip 10.12.11.110.12.11.1dynamicbgp5020None
41as2border1default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicbgp5020None
106as2border2default3.0.1.0/24ip 10.23.21.310.23.21.3dynamicbgp5020None
107as2border2default3.0.2.0/24ip 10.23.21.310.23.21.3dynamicbgp5020None
182as2dept1default1.0.1.0/24ip 2.34.101.32.34.101.3dynamicbgp5020None
183as2dept1default1.0.1.0/24ip 2.34.201.32.34.201.3dynamicbgp5020None
184as2dept1default1.0.2.0/24ip 2.34.101.32.34.101.3dynamicbgp5020None
185as2dept1default1.0.2.0/24ip 2.34.201.32.34.201.3dynamicbgp5020None
195as2dept1default3.0.1.0/24ip 2.34.101.32.34.101.3dynamicbgp5020None
196as2dept1default3.0.1.0/24ip 2.34.201.32.34.201.3dynamicbgp5020None
197as2dept1default3.0.2.0/24ip 2.34.101.32.34.101.3dynamicbgp5020None
198as2dept1default3.0.2.0/24ip 2.34.201.32.34.201.3dynamicbgp5020None
226as2dist1default2.128.0.0/24ip 2.34.101.42.34.101.4dynamicbgp5020None
227as2dist1default2.128.1.0/24ip 2.34.101.42.34.101.4dynamicbgp5020None
261as2dist2default2.128.0.0/24ip 2.34.201.42.34.201.4dynamicbgp5020None
262as2dist2default2.128.1.0/24ip 2.34.201.42.34.201.4dynamicbgp5020None
271as3border1default2.128.0.0/16ip 10.23.21.210.23.21.2dynamicbgp5020None
281as3border2default1.0.1.0/24ip 10.13.22.110.13.22.1dynamicbgp5020None
282as3border2default1.0.2.0/24ip 10.13.22.110.13.22.1dynamicbgp5020None
\n", "
" ], "text/plain": [ " Node VRF Network Next_Hop Next_Hop_IP \\\n", "6 as1border1 default 2.128.0.0/16 ip 10.12.11.2 10.12.11.2 \n", "20 as1border2 default 3.0.1.0/24 ip 10.13.22.3 10.13.22.3 \n", "21 as1border2 default 3.0.2.0/24 ip 10.13.22.3 10.13.22.3 \n", "40 as2border1 default 1.0.1.0/24 ip 10.12.11.1 10.12.11.1 \n", "41 as2border1 default 1.0.2.0/24 ip 10.12.11.1 10.12.11.1 \n", "106 as2border2 default 3.0.1.0/24 ip 10.23.21.3 10.23.21.3 \n", "107 as2border2 default 3.0.2.0/24 ip 10.23.21.3 10.23.21.3 \n", "182 as2dept1 default 1.0.1.0/24 ip 2.34.101.3 2.34.101.3 \n", "183 as2dept1 default 1.0.1.0/24 ip 2.34.201.3 2.34.201.3 \n", "184 as2dept1 default 1.0.2.0/24 ip 2.34.101.3 2.34.101.3 \n", "185 as2dept1 default 1.0.2.0/24 ip 2.34.201.3 2.34.201.3 \n", "195 as2dept1 default 3.0.1.0/24 ip 2.34.101.3 2.34.101.3 \n", "196 as2dept1 default 3.0.1.0/24 ip 2.34.201.3 2.34.201.3 \n", "197 as2dept1 default 3.0.2.0/24 ip 2.34.101.3 2.34.101.3 \n", "198 as2dept1 default 3.0.2.0/24 ip 2.34.201.3 2.34.201.3 \n", "226 as2dist1 default 2.128.0.0/24 ip 2.34.101.4 2.34.101.4 \n", "227 as2dist1 default 2.128.1.0/24 ip 2.34.101.4 2.34.101.4 \n", "261 as2dist2 default 2.128.0.0/24 ip 2.34.201.4 2.34.201.4 \n", "262 as2dist2 default 2.128.1.0/24 ip 2.34.201.4 2.34.201.4 \n", "271 as3border1 default 2.128.0.0/16 ip 10.23.21.2 10.23.21.2 \n", "281 as3border2 default 1.0.1.0/24 ip 10.13.22.1 10.13.22.1 \n", "282 as3border2 default 1.0.2.0/24 ip 10.13.22.1 10.13.22.1 \n", "\n", " Next_Hop_Interface Protocol Metric Admin_Distance Tag \n", "6 dynamic bgp 50 20 None \n", "20 dynamic bgp 50 20 None \n", "21 dynamic bgp 50 20 None \n", "40 dynamic bgp 50 20 None \n", "41 dynamic bgp 50 20 None \n", "106 dynamic bgp 50 20 None \n", "107 dynamic bgp 50 20 None \n", "182 dynamic bgp 50 20 None \n", "183 dynamic bgp 50 20 None \n", "184 dynamic bgp 50 20 None \n", "185 dynamic bgp 50 20 None \n", "195 dynamic bgp 50 20 None \n", "196 dynamic bgp 50 20 None \n", "197 dynamic bgp 50 20 None \n", "198 dynamic bgp 50 20 None \n", "226 dynamic bgp 50 20 None \n", "227 dynamic bgp 50 20 None \n", "261 dynamic bgp 50 20 None \n", "262 dynamic bgp 50 20 None \n", "271 dynamic bgp 50 20 None \n", "281 dynamic bgp 50 20 None \n", "282 dynamic bgp 50 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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NodeVRFNetworkNext_HopNext_Hop_IPNext_Hop_InterfaceProtocolMetricAdmin_DistanceTag
2as1border1default1.0.2.0/24interface GigabitEthernet0/0 ip 1.0.1.21.0.1.2GigabitEthernet0/0ospf2110None
14as1border2default1.0.2.0/24interface GigabitEthernet1/0AUTO/NONE(-1l)GigabitEthernet1/0connected00None
29as1core1default1.0.2.0/24interface GigabitEthernet0/0AUTO/NONE(-1l)GigabitEthernet0/0connected00None
41as2border1default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicbgp5020None
77as2border2default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicibgp50200None
113as2core1default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicibgp50200None
148as2core2default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicibgp50200None
184as2dept1default1.0.2.0/24ip 2.34.101.32.34.101.3dynamicbgp5020None
185as2dept1default1.0.2.0/24ip 2.34.201.32.34.201.3dynamicbgp5020None
200as2dist1default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicibgp50200None
235as2dist2default1.0.2.0/24ip 10.12.11.110.12.11.1dynamicibgp50200None
270as3border1default1.0.2.0/24ip 10.13.22.110.13.22.1dynamicibgp50200None
282as3border2default1.0.2.0/24ip 10.13.22.110.13.22.1dynamicbgp5020None
294as3core1default1.0.2.0/24ip 10.13.22.110.13.22.1dynamicibgp50200None
\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", " Next_Hop_IP Next_Hop_Interface Protocol Metric Admin_Distance Tag \n", "2 1.0.1.2 GigabitEthernet0/0 ospf 2 110 None \n", "14 AUTO/NONE(-1l) GigabitEthernet1/0 connected 0 0 None \n", "29 AUTO/NONE(-1l) GigabitEthernet0/0 connected 0 0 None \n", "41 10.12.11.1 dynamic bgp 50 20 None \n", "77 10.12.11.1 dynamic ibgp 50 200 None \n", "113 10.12.11.1 dynamic ibgp 50 200 None \n", "148 10.12.11.1 dynamic ibgp 50 200 None \n", "184 2.34.101.3 dynamic bgp 50 20 None \n", "185 2.34.201.3 dynamic bgp 50 20 None \n", "200 10.12.11.1 dynamic ibgp 50 200 None \n", "235 10.12.11.1 dynamic ibgp 50 200 None \n", "270 10.13.22.1 dynamic ibgp 50 200 None \n", "282 10.13.22.1 dynamic bgp 50 20 None \n", "294 10.13.22.1 dynamic 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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NodeVRFNetworkNext_HopNext_Hop_IPNext_Hop_InterfaceProtocolMetricAdmin_DistanceTag
309host1default0.0.0.0/0interface eth0 ip 2.128.0.12.128.0.1eth0static01None
310host1default2.128.0.0/24interface eth0AUTO/NONE(-1l)eth0connected00None
311host1default2.128.0.101/32interface eth0AUTO/NONE(-1l)eth0local00None
312host2default0.0.0.0/0interface eth0 ip 2.128.1.12.128.1.1eth0static01None
313host2default2.128.1.0/24interface eth0AUTO/NONE(-1l)eth0connected00None
314host2default2.128.1.101/32interface eth0AUTO/NONE(-1l)eth0local00None
\n", "
" ], "text/plain": [ " Node VRF Network Next_Hop \\\n", "309 host1 default 0.0.0.0/0 interface eth0 ip 2.128.0.1 \n", "310 host1 default 2.128.0.0/24 interface eth0 \n", "311 host1 default 2.128.0.101/32 interface eth0 \n", "312 host2 default 0.0.0.0/0 interface eth0 ip 2.128.1.1 \n", "313 host2 default 2.128.1.0/24 interface eth0 \n", "314 host2 default 2.128.1.101/32 interface eth0 \n", "\n", " Next_Hop_IP Next_Hop_Interface Protocol Metric Admin_Distance Tag \n", "309 2.128.0.1 eth0 static 0 1 None \n", "310 AUTO/NONE(-1l) eth0 connected 0 0 None \n", "311 AUTO/NONE(-1l) eth0 local 0 0 None \n", "312 2.128.1.1 eth0 static 0 1 None \n", "313 AUTO/NONE(-1l) eth0 connected 0 0 None \n", "314 AUTO/NONE(-1l) eth0 local 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.7.11" } }, "nbformat": 4, "nbformat_minor": 2 }