Skip to content

Batfish をインストールしてコンフィグを分析する

Batfish を Linux にインストールする手順をメモしておきます。 公式のインストール手順は Getting Started with Batfish にあります。 今回は Ubuntu 21.0.4 へインストールしました。 Batfish は Docker イメージで起動する為、Ubuntu21 に docker / docker-compose をインストールする などを参考に docker をインストールしておきます。

尚、Jupyter Notebook を含む batfish/allinone Docker イメージの起動手順もメモしておきますが、今回のメモでは Jupyter Notebook は利用しません (その為、batfish/allinone イメージを使う必要はありません)。

Batfish のインストール

Batfish は Docker イメージ として提供されています。 以下の 3 種類があります。

  1. batfish/allinone
    • Jupyter Notebook やサンプルコンフィグを含む
  2. batfish/batfish
    • Jupyter Notebook やサンプルコンフィグを含まない
  3. batfish/ci-base
    • CI 用イメージ

allinone イメージの起動

batfish/allinone イメージを利用する場合は、例えば以下のように起動します。 Jupyter Notebook 用に TCP/8888 をコンテナへ転送します。 また、ホストマシンとコンテナ間で永続ストレージでネットワーク機器のコンフィグなどを共有出来た方が便利なので、-v でホストのディレクトリをコンテナにマウントします。

1
2
3
4
5
6
7
8
9
docker pull batfish/allinone
docker run \
  -d \
  -p 8888:8888 \
  -p 9996:9996 \
  -p 9997:9997 \
  -v ~/mynetworks:/notebooks/mynetworks \
  --name batfish \
  batfish/allinone

Jupyter Notebook へログインする際の Token はコンテナを起動した際に表示されます。 しかし -d オプションを指定してバックグラウンド起動した場合は起動メッセージが表示されず、Token が分からない為、docker exec -it batfish bash -c "jupyter notebook list" を実行して Token を確認します。 実行例は以下の通りです。 下記の場合、Token は 0123456789abcdef0123456789abcdef0123456789abcdef ですので、Jupyter Notebook のログイン画面でこの Token を入力します。

1
2
3
# docker exec -it batfish bash -c "jupyter notebook list"
Currently running servers:
http://0.0.0.0:8888/?token=0123456789abcdef0123456789abcdef0123456789abcdef :: /notebooks

batfish イメージの起動

batfish/batfish イメージを利用する場合は、例えば以下のように起動します。

1
2
3
4
5
6
7
docker pull batfish/batfish
docker run \
  -d \
  -p 9996:9996 \
  -p 9997:9997 \
  --name batfish \
  batfish/batfish

pybatfish のインストール

Python から Batfish を利用するには pybatfish をインストールします。

1
python3 -m pip install --upgrade pybatfish

コンフィグの用意

ネットワーク機器のコンフィグを保存するディレクトリを作成します。

1
mkdir -p ~/mynetwork1/configs

configs ディレクトリへ Batfish の処理対象にするネットワーク機器のコンフィグをアップロードしておきます。 この時点のディレクトリ構造は以下となりました。

1
2
3
4
5
6
# tree ~/mynetwork1/
/root/mynetwork1/
└── configs
    ├── R1.cfg
    ├── R2.cfg
    └── R3.cfg

サンプルスクリプト

サンプルスクリプトは以下の通りです。 こだわりだすときりがありませんが、ip_node_properties として定義している DataFrame の結果は順序性が不明だった為 (何某か、ロジックがあるのだと思います…)、sort_valuesNode, VRF, Interface をキーにソートしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env python3

from pybatfish.client.commands import *
from pybatfish.question.question import load_questions, list_questions
from pybatfish.question import bfq

import pandas
import pprint

pandas.set_option('display.max_rows', None)
pandas.set_option('display.max_columns', None)
pandas.set_option('display.width', None)
pandas.set_option('display.max_colwidth', -1)

NETWORK_NAME = "mynetwork1_network"
SNAPSHOT_NAME = "mynetwork1_snapshot"
SNAPSHOT_PATH = "mynetwork1"

bf_set_network(NETWORK_NAME)
bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)

load_questions()

ip_node_properties = bfq.ipOwners().answer().frame()
print(ip_node_properties.sort_values(by=["Node", "VRF", "Interface"]))

サンプルスクリプトの実行例は以下の通りです。 上述の通り、ソート処理を行っている影響で結果表示のうち、左側の数字が順序通りでは無くなっています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# ./sample.py
/root/./sample.py:13: FutureWarning: Passing a negative integer is deprecated in version 1.0 and will not be supported in future version. Instead, use None to not limit the column width.
  pandas.set_option('display.max_colwidth', -1)
status: TRYINGTOASSIGN
.... no task information
status: CHECKINGSTATUS
.... no task information
status: TERMINATEDNORMALLY
.... 2021-08-28 16:06:12.908000+00:00 Deserializing objects of type 'org.batfish.datamodel.Configuration' from files 3 / 3.
Default snapshot is now set to mynetwork1_snapshot
status: TRYINGTOASSIGN
.... no task information
status: ASSIGNED
.... 2021-08-28 16:06:13.180000+00:00 Parse environment BGP tables.
status: TERMINATEDNORMALLY
.... 2021-08-28 16:06:13.180000+00:00 Parse environment BGP tables.
Successfully loaded 67 questions from remote
Successfully loaded 67 questions from remote
status: TRYINGTOASSIGN
.... no task information
status: TERMINATEDNORMALLY
.... 2021-08-28 16:06:13.603000+00:00 Begin job.
  Node      VRF           Interface         IP Mask Active
1  r1   default  GigabitEthernet0/0  10.0.12.1  24   True
2  r1   default  Loopback0           10.0.99.1  32   True
3  r2   default  GigabitEthernet0/0  10.0.23.2  24   True
4  r2   default  GigabitEthernet0/1  10.0.12.2  24   True
0  r2   default  Loopback0           10.0.99.2  32   True
6  r3   default  GigabitEthernet0/1  10.0.23.3  24   True
5  r3   default  Loopback0           10.0.99.3  32   True

参考

今回利用したネットワーク機器のコンフィグは以下です。

R1.cfg

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
hostname R1
!
interface Loopback0
 ip address 10.0.99.1 255.255.255.255
 ip ospf network point-to-point
 ip ospf 65000 area 0.0.0.0
!
interface GigabitEthernet0/0
 ip address 10.0.12.1 255.255.255.0
 ip ospf network broadcast
 ip ospf 65000 area 0.0.0.0
 no shutdown
!
router ospf 65000
 router-id 10.0.99.1
!
end

R2.cfg

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
hostname R2
!
interface Loopback0
 ip address 10.0.99.2 255.255.255.255
 ip ospf network point-to-point
 ip ospf 65000 area 0.0.0.0
!
interface GigabitEthernet0/0
 ip address 10.0.23.2 255.255.255.0
 ip ospf network broadcast
 ip ospf 65000 area 0.0.0.0
 no shutdown
!
interface GigabitEthernet0/1
 ip address 10.0.12.2 255.255.255.0
 ip ospf network broadcast
 ip ospf 65000 area 0.0.0.0
 no shutdown
!
router ospf 65000
 router-id 10.0.99.2
!
end

R3.cfg

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
hostname R3
!
interface Loopback0
 ip address 10.0.99.3 255.255.255.255
 ip ospf network point-to-point
 ip ospf 65000 area 0.0.0.0
!
interface GigabitEthernet0/1
 ip address 10.0.23.3 255.255.255.0
 ip ospf network broadcast
 ip ospf 65000 area 0.0.0.0
 no shutdown
!
router ospf 65000
 router-id 10.0.99.3
!
end