Skip to content

Instantly share code, notes, and snippets.

@akira6592
Last active October 26, 2018 03:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akira6592/64465d3cbc73d7f6d0164b2073bdfa65 to your computer and use it in GitHub Desktop.
Save akira6592/64465d3cbc73d7f6d0164b2073bdfa65 to your computer and use it in GitHub Desktop.
Getting started with Batfish (Japanese) https://tekunabe.hatenablog.jp/entry/2018/10/25/batfish
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Getting started with Batfish.ipynb](https://github.com/batfish/pybatfish/blob/master/jupyter_notebooks/Getting%20started%20with%20Batfish.ipynb) の見出しの翻訳と\n",
"注釈(※)追加"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Getting Started with Batfish\n",
"\n",
"This notebook uses pybatfish, a Python-based SDK for Batfish, to analyze a sample network. It shows how to submit your configurations and other network data for analysis and how to query its vendor-neutral network model. [Other notebooks](https://github.com/batfish/pybatfish/tree/master/jupyter_notebooks) show how to use Batfish for different types of network validation tasks. \n",
"\n",
"Check out a video demo of this notebook [here](https://www.youtube.com/watch?v=Ca7kPAtfFqo).\n",
"\n",
"### ネットワークの初期化とスナップショットの作成\n",
"\n",
"A *network* is a logical group of routers and links. It can be your entire network or a subset of it. A *snapshot* is a collection of information (configuration files, routing data, up/down status of nodes and links) that represent the network state. Snapshots can contain the actual state of the network or candidate states (e.g, those corresponding to a planned change) that you want to analyze.\n",
"\n",
"![Analytics](https://ga-beacon.appspot.com/UA-100596389-3/open-source/pybatfish/jupyter_notebooks/getting-started?pixel&useReferer)**\\*\\*Make sure that the Batfish service is running locally before running the cells below.\\*\\***"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/usr/local/lib/python3.5/dist-packages/pybatfish/client/commands.py:49: UserWarning: Pybatfish public API is being updated, note that API names and parameters will soon change.\n",
" \"Pybatfish public API is being updated, note that API names and parameters will soon change.\")\n"
]
}
],
"source": [
"# Import pybatfish and other needed packages\n",
"%run startup.py"
]
},
{
"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.<br>\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": 4,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/plain": [
"'example_snapshot'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Assign a friendly name to your network and snapshot\n",
"NETWORK_NAME = \"example_network\"\n",
"SNAPSHOT_NAME = \"example_snapshot\"\n",
"\n",
"SNAPSHOT_PATH = \"networks/example\" # ※このディレクトリ配下のネットワーク機器のコンフィグやホスト定義ファイルを読み込む\n",
"\n",
"# Now create the network and initialize the snapshot\n",
"bf_set_network(NETWORK_NAME)\n",
"bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you used the example we provided, the network you 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)\n",
"\n",
"***"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ネットワークモデルのクエリ\n",
"\n",
"Batfish creates a comprehensive vendor-neutral device and network model which can be queried for information about devices, interfaces, VRFs, routes, etc. It offers a set of *questions* to query this model."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Load questions from Batfish\n",
"load_questions()\n",
"\n",
"# To see available questions, you can use\n",
"# list_questions()\n",
"\n",
"# You can also use tab-completion on the Batfish question module - bfq. -> press TAB key,\n",
"# uncomment and try on the following line\n",
"# bfq.\n",
"\n",
"# In IPython and Jupyter you can use the \"?\" shorthand to get help on a question\n",
"?bfq.nodeProperties\n",
"\n",
"# help(bfq.nodeProperties) # in standard Python console"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"\n",
"### パースされたファイルの状態の取得\n",
"\n",
"Batfish may ignore certain lines in the configuration. To retrieve the parsing status of snapshot files, use the `fileParseStatus()` question."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"parse_status = bfq.fileParseStatus().answer().frame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`answer()` runs the question and returns the answer in a JSON format. \n",
"\n",
"`frame()` wraps the answer as [pandas dataframe](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html)."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>File_Name</th>\n",
" <th>Status</th>\n",
" <th>Nodes</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>configs/as1border1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as1border1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>configs/as1border2.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as1border2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>configs/as1core1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as1core1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>configs/as2border1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2border1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>configs/as2border2.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2border2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>configs/as2core1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2core1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>configs/as2core2.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2core2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>configs/as2dept1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2dept1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>configs/as2dist1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2dist1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>configs/as2dist2.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as2dist2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>configs/as3border1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as3border1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>configs/as3border2.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as3border2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>configs/as3core1.cfg</td>\n",
" <td>PASSED</td>\n",
" <td>[as3core1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>hosts/host1.json</td>\n",
" <td>PASSED</td>\n",
" <td>[host1]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>hosts/host2.json</td>\n",
" <td>PASSED</td>\n",
" <td>[host2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>iptables/host1.iptables</td>\n",
" <td>PASSED</td>\n",
" <td>[iptables/host1.iptables]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>iptables/host2.iptables</td>\n",
" <td>PASSED</td>\n",
" <td>[iptables/host2.iptables]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" File_Name Status Nodes\n",
"0 configs/as1border1.cfg PASSED [as1border1]\n",
"1 configs/as1border2.cfg PASSED [as1border2]\n",
"2 configs/as1core1.cfg PASSED [as1core1]\n",
"3 configs/as2border1.cfg PASSED [as2border1]\n",
"4 configs/as2border2.cfg PASSED [as2border2]\n",
"5 configs/as2core1.cfg PASSED [as2core1]\n",
"6 configs/as2core2.cfg PASSED [as2core2]\n",
"7 configs/as2dept1.cfg PASSED [as2dept1]\n",
"8 configs/as2dist1.cfg PASSED [as2dist1]\n",
"9 configs/as2dist2.cfg PASSED [as2dist2]\n",
"10 configs/as3border1.cfg PASSED [as3border1]\n",
"11 configs/as3border2.cfg PASSED [as3border2]\n",
"12 configs/as3core1.cfg PASSED [as3core1]\n",
"13 hosts/host1.json PASSED [host1]\n",
"14 hosts/host2.json PASSED [host2]\n",
"15 iptables/host1.iptables PASSED [iptables/host1.iptables]\n",
"16 iptables/host2.iptables PASSED [iptables/host2.iptables]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# View the parse status results\n",
"parse_status # ※ パースされたファイルの状態を表示。Status が PASSED なら正常"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Additional post-processing can be done on this data, like filtering for values in one or multiple columns, reducing the number of columns, etc. using pandas. A tutorial on pandas-based filtering is [here](http://nbviewer.jupyter.org/github/jvns/pandas-cookbook/blob/v0.2/cookbook/Chapter%203%20-%20Which%20borough%20has%20the%20most%20noise%20complaints%20%28or%2C%20more%20selecting%20data%29.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>File_Name</th>\n",
" <th>Status</th>\n",
" <th>Nodes</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"Empty DataFrame\n",
"Columns: [File_Name, Status, Nodes]\n",
"Index: []"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example: use a filter on the returned dataframe to see which files failed to parse completely\n",
"parse_status[parse_status['Status'] != 'PASSED'] # change '!=' to '==' to get the files which passed # ※ 失敗したファイルを確認(無いので正常)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Filename</th>\n",
" <th>Text</th>\n",
" <th>Line</th>\n",
" <th>Parser_Context</th>\n",
" <th>Comment</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"Empty DataFrame\n",
"Columns: [Filename, Text, Line, Parser_Context, Comment]\n",
"Index: []"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# View details if some of the files were not parsed completely\n",
"parse_warning = bfq.parseWarning().answer().frame()\n",
"\n",
"parse_warning"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"### ネットワークエンティティのプロパティの抽出\n",
"Entities in the network refer to things like nodes, interfaces, routing processes, and VRFs. Batfish makes it trivial to extract configured properties of such entities in a vendor neutral manner. \n",
"\n",
"##### ノートプロパティ\n",
"The nodeProperties question extracts information on nodes in the snapshot."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# Extract the properties of all nodes whose names match the regular expression '.*border.*'\n",
"node_properties = bfq.nodeProperties(nodes=\".*border.*\").answer().frame() # ※名前に border が含まれるノードが持つプロパティを取得"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Node', 'IKE_Policies', 'VRFs', 'Logging_Source_Interface',\n",
" 'NTP_Servers', 'Zones', 'IP_Access_Lists', 'Vendor_Family',\n",
" 'Authentication_Key_Chains', 'TACACS_Source_Interface',\n",
" 'AS_Path_Access_Lists', 'IPSec_Proposals', 'IP6_Access_Lists',\n",
" 'Logging_Servers', 'Route6_Filter_Lists', 'DNS_Servers',\n",
" 'TACACS_Servers', 'Device_Type', 'IPSec_Policies', 'Hostname',\n",
" 'Domain_Name', 'IKE_Gateways', 'IPSec_Vpns', 'IP_Spaces', 'Interfaces',\n",
" 'Default_Cross_Zone_Action', 'Route_Filter_Lists',\n",
" 'Default_Inbound_Action', 'SNMP_Source_Interface', 'Routing_Policies',\n",
" 'Canonical_IP', 'NTP_Source_Interface', 'SNMP_Trap_Servers',\n",
" 'Configuration_Format', 'DNS_Source_Interface', 'Community_Lists'],\n",
" dtype='object')"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# View what columns (properties) are present in the answer\n",
"node_properties.columns # ※ NTPサーバーやインターフェースのプロパティがあることが確認できる"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Node</th>\n",
" <th>Interfaces</th>\n",
" <th>Domain_Name</th>\n",
" <th>NTP_Servers</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>as1border1</td>\n",
" <td>[GigabitEthernet0/0, GigabitEthernet1/0, Ethernet0/0, Loopback0]</td>\n",
" <td>lab.local</td>\n",
" <td>[]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>as2border1</td>\n",
" <td>[GigabitEthernet0/0, GigabitEthernet1/0, GigabitEthernet2/0, Ethernet0/0, Loopback0]</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>as1border2</td>\n",
" <td>[GigabitEthernet0/0, GigabitEthernet1/0, GigabitEthernet2/0, Ethernet0/0, Loopback0]</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>as3border2</td>\n",
" <td>[GigabitEthernet0/0, GigabitEthernet1/0, Ethernet0/0, Loopback0]</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>as2border2</td>\n",
" <td>[GigabitEthernet0/0, GigabitEthernet1/0, GigabitEthernet2/0, Ethernet0/0, Loopback0]</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>as3border1</td>\n",
" <td>[GigabitEthernet0/0, GigabitEthernet1/0, Ethernet0/0, Loopback0]</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Node \\\n",
"0 as1border1 \n",
"1 as2border1 \n",
"2 as1border2 \n",
"3 as3border2 \n",
"4 as2border2 \n",
"5 as3border1 \n",
"\n",
" Interfaces \\\n",
"0 [GigabitEthernet0/0, GigabitEthernet1/0, Ethernet0/0, Loopback0] \n",
"1 [GigabitEthernet0/0, GigabitEthernet1/0, GigabitEthernet2/0, Ethernet0/0, Loopback0] \n",
"2 [GigabitEthernet0/0, GigabitEthernet1/0, GigabitEthernet2/0, Ethernet0/0, Loopback0] \n",
"3 [GigabitEthernet0/0, GigabitEthernet1/0, Ethernet0/0, Loopback0] \n",
"4 [GigabitEthernet0/0, GigabitEthernet1/0, GigabitEthernet2/0, Ethernet0/0, Loopback0] \n",
"5 [GigabitEthernet0/0, GigabitEthernet1/0, Ethernet0/0, Loopback0] \n",
"\n",
" Domain_Name NTP_Servers \n",
"0 lab.local [] \n",
"1 lab.local [18.18.18.18, 23.23.23.23] \n",
"2 lab.local [18.18.18.18, 23.23.23.23] \n",
"3 lab.local [18.18.18.18, 23.23.23.23] \n",
"4 lab.local [18.18.18.18] \n",
"5 lab.local [18.18.18.18, 23.23.23.23] "
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# To extract only a subset of properties, use the properties parameter\n",
"# ※ 名前に border が含まれるノードのドイメイン名、NTPサーバー、インターフェースのプロパティを取得して表示する。コンフィグがパースされていることが分かる。\n",
"node_properties_trunc = bfq.nodeProperties(nodes=\".*border.*\", properties=\"Domain_Name|NTP_Servers|Interfaces\").answer().frame()\n",
"\n",
"node_properties_trunc"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An alternative (client-side) way to restrict the list of columns displayed is to use pandas-based column filtering ([pandas tutorial](http://nbviewer.jupyter.org/github/jvns/pandas-cookbook/blob/v0.2/cookbook/Chapter%202%20-%20Selecting%20data%20%26%20finding%20the%20most%20common%20complaint%20type.ipynb))."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Node</th>\n",
" <th>Domain_Name</th>\n",
" <th>NTP_Servers</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>as1border1</td>\n",
" <td>lab.local</td>\n",
" <td>[]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>as2border1</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>as1border2</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>as3border2</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>as2border2</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>as3border1</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Node Domain_Name NTP_Servers\n",
"0 as1border1 lab.local []\n",
"1 as2border1 lab.local [18.18.18.18, 23.23.23.23]\n",
"2 as1border2 lab.local [18.18.18.18, 23.23.23.23]\n",
"3 as3border2 lab.local [18.18.18.18, 23.23.23.23]\n",
"4 as2border2 lab.local [18.18.18.18]\n",
"5 as3border1 lab.local [18.18.18.18, 23.23.23.23]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Let's remove the interfaces column from our result\n",
"node_properties_trunc = node_properties_trunc[[\"Node\", \"Domain_Name\", \"NTP_Servers\"]]\n",
"\n",
"node_properties_trunc"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can add additional filters to restrict entries based on values of columns."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Node</th>\n",
" <th>Domain_Name</th>\n",
" <th>NTP_Servers</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>as2border1</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>as1border2</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>as3border2</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>as3border1</td>\n",
" <td>lab.local</td>\n",
" <td>[18.18.18.18, 23.23.23.23]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Node Domain_Name NTP_Servers\n",
"1 as2border1 lab.local [18.18.18.18, 23.23.23.23]\n",
"2 as1border2 lab.local [18.18.18.18, 23.23.23.23]\n",
"3 as3border2 lab.local [18.18.18.18, 23.23.23.23]\n",
"5 as3border1 lab.local [18.18.18.18, 23.23.23.23]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# View only nodes with **23.23.23.23** as one of the configured ntp-servers\n",
"node_properties_trunc[node_properties_trunc['NTP_Servers'].apply(lambda x:'23.23.23.23' in x)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### インターフェースプロパティ\n",
"To retrieve information about interfaces present and the properties of them, use the **interfaceProperties** question"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"interface_properties = bfq.interfaceProperties(nodes=\".*border.*\", properties=\"Interface_Type|Bandwidth|VRF|Primary_Address\").answer().frame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you wanted to just find interfaces with the primary ip address in <b>10.12.0.0/16</b>, you can filter the results as shown below.\n",
"\n",
"**na=False** is required in order to ignore interfaces without any configured IP addresses, such as ethernet switchports.\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Interface</th>\n",
" <th>Interface_Type</th>\n",
" <th>Bandwidth</th>\n",
" <th>VRF</th>\n",
" <th>Primary_Address</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>as2border1:GigabitEthernet0/0</td>\n",
" <td>PHYSICAL</td>\n",
" <td>1.000000e+09</td>\n",
" <td>default</td>\n",
" <td>10.12.11.2/24</td>\n",
" </tr>\n",
" <tr>\n",
" <th>26</th>\n",
" <td>as1border1:GigabitEthernet1/0</td>\n",
" <td>PHYSICAL</td>\n",
" <td>1.000000e+09</td>\n",
" <td>default</td>\n",
" <td>10.12.11.1/24</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Interface Interface_Type Bandwidth VRF \\\n",
"22 as2border1:GigabitEthernet0/0 PHYSICAL 1.000000e+09 default \n",
"26 as1border1:GigabitEthernet1/0 PHYSICAL 1.000000e+09 default \n",
"\n",
" Primary_Address \n",
"22 10.12.11.2/24 \n",
"26 10.12.11.1/24 "
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"interface_properties[interface_properties['Primary_Address'].str.match(\"10.12\", na=False)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similar questions extract properties of other entities (e.g., `bgpProcessConfiguration()` extracts properties of BGP processes)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"### コンフィグの構造と参照整合性の検査\n",
"Network configuratons define and reference named structures like route maps, access control lists (ACLs), prefix lists, etc. Two common indicators of buggy configurations include references to structures that are not defined anywhere (which can lead to disastrous consequences on some platforms) or defined structures that are not referenced anywhere. Batfish makes it easy to flag such instances because it understand the underlying semantics of configuration."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>File_Name</th>\n",
" <th>Struct_Type</th>\n",
" <th>Ref_Name</th>\n",
" <th>Context</th>\n",
" <th>Lines</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>configs/as2core2.cfg</td>\n",
" <td>route-map</td>\n",
" <td>filter-bogons</td>\n",
" <td>bgp inbound route-map</td>\n",
" <td>configs/as2core2.cfg:[109]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" File_Name Struct_Type Ref_Name Context \\\n",
"0 configs/as2core2.cfg route-map filter-bogons bgp inbound route-map \n",
"\n",
" Lines \n",
"0 configs/as2core2.cfg:[109] "
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# List references to undefined structures\n",
"bfq.undefinedReferences().answer().frame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The question for listing any unused structures is `unusedStructures()`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"### Inspecting physical and logical topologies\n",
"Nodes in a network form multiple types of topologies that are defined by edges at layer 1 or layer 3 (IP layer) or by different types of routing protocols such as BGP or OSPF. The `edges()` question in Batfish returns these different types of edges. Its `edgeType` parameter specifies the type of edges to retrieve, and the `nodes` and `remoteNodes` parameters can be used to limit the returned edges to a subset of the nodes."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Interface</th>\n",
" <th>IPs</th>\n",
" <th>Remote_Interface</th>\n",
" <th>Remote_IPs</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>as1border1:GigabitEthernet0/0</td>\n",
" <td>[1.0.1.1]</td>\n",
" <td>as1core1:GigabitEthernet1/0</td>\n",
" <td>[1.0.1.2]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>as1border1:GigabitEthernet1/0</td>\n",
" <td>[10.12.11.1]</td>\n",
" <td>as2border1:GigabitEthernet0/0</td>\n",
" <td>[10.12.11.2]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Interface IPs Remote_Interface \\\n",
"0 as1border1:GigabitEthernet0/0 [1.0.1.1] as1core1:GigabitEthernet1/0 \n",
"1 as1border1:GigabitEthernet1/0 [10.12.11.1] as2border1:GigabitEthernet0/0 \n",
"\n",
" Remote_IPs \n",
"0 [1.0.1.2] \n",
"1 [10.12.11.2] "
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Get edges of type layer 3 (IP layer)\n",
"bfq.edges(nodes=\"as1border1\", edgeType=\"layer3\").answer().frame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"### ルーティングとフォワーディングの確認\n",
"Batfish computes routing and forwarding tables (aka RIBs and FIBs) of the network from snapshot data itself. These tables can be examined to understand the routing and forwarding behavior of the network. \n",
"\n",
"One way to examine this behavior is using a virtual traceroute. Unlike the live-network traceroute, Batfish shows all possible flow paths in the network and identifies routing entries that cause each hop to be taken."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\" >\n",
" #T_1f1fb358_d816_11e8_ab70_0242ac110002row0_col0 {\n",
" text-align: left;\n",
" vertical-align: top;\n",
" } #T_1f1fb358_d816_11e8_ab70_0242ac110002row0_col1 {\n",
" text-align: left;\n",
" vertical-align: top;\n",
" }</style> \n",
"<table id=\"T_1f1fb358_d816_11e8_ab70_0242ac110002\" > \n",
"<thead> <tr> \n",
" <th class=\"blank level0\" ></th> \n",
" <th class=\"col_heading level0 col0\" >Flow</th> \n",
" <th class=\"col_heading level0 col1\" >Traces</th> \n",
" </tr></thead> \n",
"<tbody> <tr> \n",
" <th id=\"T_1f1fb358_d816_11e8_ab70_0242ac110002level0_row0\" class=\"row_heading level0 row0\" >0</th> \n",
" <td id=\"T_1f1fb358_d816_11e8_ab70_0242ac110002row0_col0\" class=\"data row0 col0\" >2.128.0.101:49152 &rarr; 1.0.2.2:33434<br>start=host1</td> \n",
" <td id=\"T_1f1fb358_d816_11e8_ab70_0242ac110002row0_col1\" class=\"data row0 col1\" ><span style=\"color:#019612; text-weight:bold;\">ACCEPTED</span><br><strong>1</strong> host1:eth0 &rarr; as2dept1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;StaticRoute&lt;0.0.0.0/0,nhip:2.128.0.1,nhint:eth0&gt;_fnhip:2.128.0.1<br><br><strong>2</strong> as2dept1:GigabitEthernet0/0 &rarr; as2dist1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:2.34.101.3,nhint:dynamic&gt;_fnhip:2.34.101.3<br><br><strong>3</strong> as2dist1:GigabitEthernet0/0 &rarr; as2core1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.23.11.2<br><br><strong>4</strong> as2core1:GigabitEthernet0/0 &rarr; as2border1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.12.11.1<br><br><strong>5</strong> as2border1:GigabitEthernet0/0 &rarr; as1border1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:10.12.11.1<br><br><strong>6</strong> as1border1:GigabitEthernet0/0 &rarr; as1core1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;OspfIntraAreaRoute&lt;1.0.2.0/24,nhip:1.0.1.2,nhint:dynamic&gt;_fnhip:1.0.1.2<br><br><span style=\"color:#019612; text-weight:bold;\">ACCEPTED</span><br><strong>1</strong> host1:eth0 &rarr; as2dept1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;StaticRoute&lt;0.0.0.0/0,nhip:2.128.0.1,nhint:eth0&gt;_fnhip:2.128.0.1<br><br><strong>2</strong> as2dept1:GigabitEthernet0/0 &rarr; as2dist1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:2.34.101.3,nhint:dynamic&gt;_fnhip:2.34.101.3<br><br><strong>3</strong> as2dist1:GigabitEthernet1/0 &rarr; as2core2:GigabitEthernet3/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.23.21.2<br><br><strong>4</strong> as2core2:GigabitEthernet1/0 &rarr; as2border1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.12.12.1<br><br><strong>5</strong> as2border1:GigabitEthernet0/0 &rarr; as1border1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:10.12.11.1<br><br><strong>6</strong> as1border1:GigabitEthernet0/0 &rarr; as1core1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;OspfIntraAreaRoute&lt;1.0.2.0/24,nhip:1.0.1.2,nhint:dynamic&gt;_fnhip:1.0.1.2<br><br><span style=\"color:#019612; text-weight:bold;\">ACCEPTED</span><br><strong>1</strong> host1:eth0 &rarr; as2dept1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;StaticRoute&lt;0.0.0.0/0,nhip:2.128.0.1,nhint:eth0&gt;_fnhip:2.128.0.1<br><br><strong>2</strong> as2dept1:GigabitEthernet1/0 &rarr; as2dist2:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:2.34.201.3,nhint:dynamic&gt;_fnhip:2.34.201.3<br><br><strong>3</strong> as2dist2:GigabitEthernet0/0 &rarr; as2core2:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.23.22.2<br><br><strong>4</strong> as2core2:GigabitEthernet1/0 &rarr; as2border1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.12.12.1<br><br><strong>5</strong> as2border1:GigabitEthernet0/0 &rarr; as1border1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:10.12.11.1<br><br><strong>6</strong> as1border1:GigabitEthernet0/0 &rarr; as1core1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;OspfIntraAreaRoute&lt;1.0.2.0/24,nhip:1.0.1.2,nhint:dynamic&gt;_fnhip:1.0.1.2<br><br><span style=\"color:#019612; text-weight:bold;\">ACCEPTED</span><br><strong>1</strong> host1:eth0 &rarr; as2dept1:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;StaticRoute&lt;0.0.0.0/0,nhip:2.128.0.1,nhint:eth0&gt;_fnhip:2.128.0.1<br><br><strong>2</strong> as2dept1:GigabitEthernet1/0 &rarr; as2dist2:GigabitEthernet2/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:2.34.201.3,nhint:dynamic&gt;_fnhip:2.34.201.3<br><br><strong>3</strong> as2dist2:GigabitEthernet1/0 &rarr; as2core1:GigabitEthernet3/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.23.12.2<br><br><strong>4</strong> as2core1:GigabitEthernet0/0 &rarr; as2border1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:2.12.11.1<br><br><strong>5</strong> as2border1:GigabitEthernet0/0 &rarr; as1border1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;BgpRoute&lt;1.0.2.0/24,nhip:10.12.11.1,nhint:dynamic&gt;_fnhip:10.12.11.1<br><br><strong>6</strong> as1border1:GigabitEthernet0/0 &rarr; as1core1:GigabitEthernet1/0<br>Route(s):<br>&nbsp;&nbsp;&nbsp;&nbsp;OspfIntraAreaRoute&lt;1.0.2.0/24,nhip:1.0.1.2,nhint:dynamic&gt;_fnhip:1.0.1.2</td> \n",
" </tr></tbody> \n",
"</table> "
],
"text/plain": [
"<pandas.io.formats.style.Styler at 0x7fcd0d998208>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Do a traceroute from host1 to 1.0.2.2\n",
"# ※ batfish の traceroute は実際の traceroute とは異なり、片方向のみ確認する\n",
"tr_frame = bfq.traceroute(startLocation=\"host1\", headers=HeaderConstraints(dstIps=\"1.0.2.2\")).answer().frame()\n",
"\n",
"# Display results using customizations to handle large string values\n",
"display_html(tr_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Another way to understand the routing behavior in detail is to examine the routing tables directly. "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"# Fetch the routing table of all VRFs on all nodes in the snapshot\n",
"routes_df = bfq.routes().answer().frame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(For a large network, the first time you run a question that needs the dataplane, fetching the answer can take a few minutes. Subsequent questions are quick as the generated dataplane is saved by Batfish.)\n",
"\n",
"As used above, the routes() question can generate a lot of results. You may restrict the output using parameters to the question---to restrict the results to **border** routers, use **nodes = \"\\.\\*border\\.\\*\"**. Or, you can use pandas for client-side filtering as below."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Node</th>\n",
" <th>VRF</th>\n",
" <th>Network</th>\n",
" <th>Protocol</th>\n",
" <th>Next_Hop_IP</th>\n",
" <th>Next_Hop</th>\n",
" <th>Admin_Distance</th>\n",
" <th>Metric</th>\n",
" <th>Tag</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>101</th>\n",
" <td>as3core1</td>\n",
" <td>default</td>\n",
" <td>90.90.90.0/24</td>\n",
" <td>connected</td>\n",
" <td>AUTO/NONE(-1l)</td>\n",
" <td>None</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>102</th>\n",
" <td>as3core1</td>\n",
" <td>default</td>\n",
" <td>90.90.90.0/24</td>\n",
" <td>connected</td>\n",
" <td>AUTO/NONE(-1l)</td>\n",
" <td>None</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>None</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Node VRF Network Protocol Next_Hop_IP Next_Hop \\\n",
"101 as3core1 default 90.90.90.0/24 connected AUTO/NONE(-1l) None \n",
"102 as3core1 default 90.90.90.0/24 connected AUTO/NONE(-1l) None \n",
"\n",
" Admin_Distance Metric Tag \n",
"101 0 0 None \n",
"102 0 0 None "
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# View all routes for the network 90.90.90.0/24 with an AdminDistance of 0\n",
"routes_df[(routes_df['Network'] == \"90.90.90.0/24\") & (routes_df[\"Admin_Distance\"] == 0)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"That's it for now! Feel free to explore further by adding cells and running other questions, or play with [other notebooks](https://github.com/batfish/pybatfish/tree/master/jupyter_notebooks)."
]
}
],
"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.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment