Skip to content

batfish でレイヤー 1 トポロジーを定義する

Batfish は計算処理を行う際、「同じネットワーク (アドレス範囲) に所属していれば、インターフェイスが隣接している」と判定します。

file

しかし、例えば「同じアドレス帯を再利用している」「リンクローカルアドレスを利用している」というケースは「同じアドレスが・異なる箇所で複数回、利用される」ことは十分、有り得ます。 こういった場合は Batfish の Layer-1 topology 機能を利用することが出来ます。 この機能は公式サイトで以下のように説明されています。

Batfish can infer Layer-3 interface adjacencies based on IP address configuration on interfaces. For instance, if there are two interfaces in the network with IP assignments 192.168.1.1/24 and 192.128.1.2/24, Batfish will infer that these interfaces are adjacent.

Such inference does not work if the network re-uses IP address space or has link-local addresses. In those situations, you must provide a Layer-1 topology file that has cabling information. Then, Layer-3 adjacencies will be computed by combining the supplied Layer-1 adjacencies with Layer-2 and Layer-3 configuration to get a more accurate model.

The expected Layer-1 topology file is a JSON file that has a list of edge records, where each edge record has node and interface names of the two ends. See this file for an example.

The name of your Layer-1 topology file must be layer1_topology.json and it must be placed in a folder called batfish right below the top-level snapshot folder.

layer1_topology.json ファイルのフォーマット

レイヤー 1 トポロジーを定義する場合、layer1_topology.json というファイルを用意します。 このファイルは以下のようなルールがあります。

  1. ファイル名は必ず layer1_topology.json にする
  2. 拡張子の通り、JSON 形式で記載する
  3. 「起点と終点」を接続するように定義する (1:1 の関係にする)
  4. 定義名は node1node2 にする (異なる名前は利用出来ない)
  5. 所定の位置に配置する (後述)

以下の 2 点間を接続する場合を考えます。

  • 「router1 の GigabitEthernet0/0」と「router2 の GigabitEthernet0/0」

この場合、layer1_topology.json の定義例は以下の通りです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
 "edges": [
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router2",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

誤った定義例

以下はいずれも誤った定義例です。 定義中、一箇所でも誤った箇所があると「layer1_topology.json 全体が無視される」という動作をするようです。

誤った定義例 1

定義名が (ndoe1node2 では無く) nodeAnodeB の為、誤っています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
 "edges": [
  {
   "nodeA": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "nodeB": {
    "hostname": "router2",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

誤った定義例 2

以下は「1:1」の定義になっていない為、誤っています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
 "edges": [
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

誤った定義例 3

以下は node3 が定義されており、「1:1 の関係になっていない」為、誤っています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
 "edges": [
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node3": {
    "hostname": "router3",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

layer1_topology.json ファイルの配置

layer1_topology.json ファイルは configs と同じフォルダに配置する必要があります。

1
2
3
4
5
6
7
8
├── configs
│   ├── router1.txt
│   ├── router2.txt
│   ├── router3.txt
│   ├── router4.txt
│   ├── router5.txt
│   └── router6.txt
└── layer1_topology.json

検証の前提

以降の検証は以下のアドレス設計で行います。 「router1 〜 4 が全て同じネットワークに所属している」構成です。

ルータ インターフェイス アドレス
router1 GigabitEthernet0/0 10.0.0.1/24
router2 GigabitEthernet0/0 10.0.0.2/24
router3 GigabitEthernet0/0 10.0.0.3/24
router4 GigabitEthernet0/0 10.0.0.4/24
router5 GigabitEthernet0/0 10.0.0.5/24
router6 GigabitEthernet0/0 10.0.0.6/24

検証 1

layer1_topology.json が無ければ、全てのルータは「お互い隣接している」と扱われます。 本来は「中心に L2SW が存在し、各ルータが接続している」構成が考えられますが、今回は Batfish の挙動を理解する為、隣接関係をフルメッシュで記載しています。

file

検証 2

以下が各々、隣接するように定義してみます。

  • router1 と router2
  • router3 と router4
  • router5 と router6
 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
31
32
33
34
{
 "edges": [
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router2",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router3",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router4",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router5",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router6",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

この場合、インターフェイスの隣接関係は以下だと認識されます。 rotuer1 と router3 はアドレス帯は同じですが Batfish が「インターフェイスは隣接していない」と扱う為、ダイナミックルーティングの隣接関係や HSRP グループを構成することはありません。 これは「期待値通り」と言って良いと思います。

file

検証 3

「router1 と router2」「router3 と router4」の隣接関係は定義するものの、「router5 と router6 は何も定義しない」場合を考えてみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
 "edges": [
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router2",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router3",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router4",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

この場合、以下のようになります。 layer1_topology.json で定義されていない router5 と router6 は、他のルータ全てと隣接関係を構築しています。 しかし、layer1_topology.json で隣接関係を定義している「router1 と router3」や「router2 と router4」は隣接関係を構築していません。 「router5 は router1 と隣接している」「router5 は router3 と隣接している」にも関わらず、「router1 と router3 は 隣接していない」という、(ACL などの特殊な制御が無い限り) やや違和感のある構成になっています。

file

検証 4

以下が各々、隣接するように定義してみます。

  • router1 と router2 と router3
  • router4 と router5 と router6

前述の通り、JSON 中の定義は node1node2 しか使えない為、「3 台、各々が隣接」するように定義するには下記のように「2 台ずつ記載」します。

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
{
 "edges": [
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router2",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router1",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router3",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router2",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router3",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router4",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router5",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router4",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router6",
    "interfaceName": "GigabitEthernet0/0"
   }
  },
  {
   "node1": {
    "hostname": "router5",
    "interfaceName": "GigabitEthernet0/0"
   },
   "node2": {
    "hostname": "router6",
    "interfaceName": "GigabitEthernet0/0"
   }
  }
 ]
}

この場合、以下のようになります。期待値通りではありますが、「1:1 の定義を複数、記載する必要がある」為、やや面倒です…

file