【初心者向け】FRR を使って OSPF を動かしてみる

## はじめに
この記事は前回の続きです。前回はこちら：

https://qiita.com/hana-chan/items/d86b3aa1ede039e4826a

前回は、FRR のセットアップを行いました。ここではついにOSPFに触れていきます。
まずはOSPFを触ってみたい初心者の方向けの内容になっています。

## FRRとは？
[FRRouting](https://frrouting.org/) とは、Linuxなどで稼働するルーティングプロトコルスイート（≒セット）であり、オープンソースで提供されているものです。
要するに、OSPF とか BGP がフリーで手っ取り早く試せます。

## 前提
- FRR の OSPFが有効化されていること
- 下記の図のように構成されていること

![Untitled Diagram.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613783/cd4ab024-f31b-0c51-89b6-5bf5ef8ab791.png)

上記は[前回の記事](https://qiita.com/hana-chan/items/d86b3aa1ede039e4826a)でセットアップを行っています。

## FRR の操作

入る時は `vtysh` を使います。

```bash: Ubuntu1
sudo vtysh  # FRRに入る
exit  # 出る
```

## OSPF のセットアップ

### 状態確認

まず、FRRに入り、今の状態を確認しておきます。

```bash:設定の確認
Ubuntu1# sh running-config

Building configuration...
Current configuration:
!
frr version 10.2
frr defaults traditional
hostname Ubuntu1
log syslog informational
no ip forwarding
no ipv6 forwarding
service integrated-vtysh-config
!
end
```

```bash:ルーティングテーブルの確認
Ubunt1# sh ip route
Codes: K - kernel route, C - connected, L - local, S - static,
       R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric, t - Table-Direct,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

K>* 0.0.0.0/0 [0/100] via 10.0.2.2, enp0s8, src 10.0.2.15, weight 1, 02:16:57
L * 10.0.0.100/32 is directly connected, lo, weight 1, 01:16:51
C>* 10.0.0.100/32 is directly connected, lo, weight 1, 01:16:51
C>* 10.0.2.0/24 [0/100] is directly connected, enp0s8, weight 1, 02:16:57
K>* 10.0.2.2/32 [0/100] is directly connected, enp0s8, weight 1, 02:16:57
K>* 10.0.2.3/32 [0/100] is directly connected, enp0s8, weight 1, 02:16:57
L>* 10.0.2.15/32 is directly connected, enp0s8, weight 1, 02:16:57
C>* 172.16.0.0/24 is directly connected, enp0s9, weight 1, 01:14:55
L>* 172.16.0.1/32 is directly connected, enp0s9, weight 1, 01:14:55
```

めちゃくちゃCiscoっぽい！

この状態で、Ubuntu1 から 2 の lo に向けてpingを飛ばしても、通信できません。ルーティングテーブルに`10.0.0.200`が無いからです。

```
Ubuntu1# ping 10.0.0.200
PING 10.0.0.200 (10.0.0.200) 56(84) bytes of data.
^C
--- 10.0.0.200 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3065ms
```

:::note info
<details><summary>なぜ相手の lo アドレスが無い？（クリックで開く）</summary>

ルーターは直接見える範囲しか分かりません。イメージで説明します。

- 直接見えるもの
    - 自分のインターフェース
    - 自分と直接繋がっている線
    - 「自分と繋がっている線」に繋がっている相手のインターフェース部分
- 直接見えないもの
    - 自分と繋がっている相手だが、自分と直接繋がっていない相手のインターフェース部分
    - 自分と直接繋がっていない第三者

繋がる、とは握手をイメージしてください。
右手同士で握手すれば、直接繋がっている相手の右手のことはよく分かります。

しかし、相手の左手はどうなっているか（もしかすると4本あるかもしれない）とか、相手の左手が、さらに他人と繋がっているかどうかは、直接繋がっていないので分かりません。

分からない、つまり通信できない　です。
一応それが原則なのですが、それだとインターネットの通信ができませんね。（家とGoogleが直接繋がっていればそれでもGoogleを開けますが、そうでない家庭の方が多いでしょう）

そこで、以下のようにすれば分かるので通信可能です。
1. ルーター同士が「隣にはこの人がいるよ or あの人に会うにはこっちに行けばいいよ」という伝言ゲーム（OSPFやBGP）をすれば分かる
1. 神様（管理者）が「あの人はあっちにいる」とお告げ（Static Route）を言えばわかる

</details>
:::

### OSPF 設定の投入

![ospf.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613783/1b5359b4-f24f-bdce-eebe-b789fcf21687.png)

上記のように設定しましょう。わかりづらいですが lo も area0 に入れちゃいます。

```bash
Ubuntu1 # configure terminal
Ubuntu1(config)# ip forwarding
Ubuntu1(config)# router ospf
Ubuntu1(config-router)# network 172.16.0.0/24 area 0
Ubuntu1(config-router)# network 10.0.0.100/32 area 0
Ubuntu1(config-router)# end
```
ospf の network コマンドは、ospfを有効化するインターフェースを指定します。
極論、`0.0.0.0/0`を指定すると全てのインターフェースを包含します。

`sh run` すると正しく反映されています。
```bash: sh run（一部）
router ospf
 network 10.0.0.100/32 area 0
 network 172.16.0.0/24 area 0
 ```

`sh ip ospf neighbor`コマンドを実行すると、OSPFで繋がっている**相手**を一覧表示することができます。
```
Ubuntu1# sh ip ospf neighbor

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
``` 

何もありませんね！　当然です。これは相手の一覧を表示するコマンドで、しかも自分しか設定していないので...

では 2 の方でも投入します。
```bash
Ubuntu2 # conf t
Ubuntu2(config)# ip forwarding
Ubuntu2(config)# router ospf
Ubuntu2(config-router)# network 172.16.0.0/24 area 0
Ubuntu2(config-router)# network 10.0.0.200/32 area 0
Ubuntu2(config-router)# end
```

1 に戻り、再び `sh ip ospf neighbor` コマンドを実行しましょう。

```
Ubuntu1# sh ip ospf neighbor

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.0.200        1 Full/Backup     6m25s             39.369s 172.16.0.2      enp0s9:172.16.0.1                    0     0     0
``` 

先ほどまでなかった相手がリストにいます。つまりOSPFの相手として認識しています。
`sh ip route` もしてみましょう。

```bash:ルーティングテーブルの確認
Ubunt1# sh ip route

K>* 0.0.0.0/0 [0/100] via 10.0.2.2, enp0s8, src 10.0.2.15, weight 1, 02:43:30
O   10.0.0.100/32 [110/0] is directly connected, lo, weight 1, 00:19:03
L * 10.0.0.100/32 is directly connected, lo, weight 1, 01:43:24
C>* 10.0.0.100/32 is directly connected, lo, weight 1, 01:43:24
O>* 10.0.0.200/32 [110/100] via 172.16.0.2, enp0s9, weight 1, 00:08:19
C>* 10.0.2.0/24 [0/100] is directly connected, enp0s8, weight 1, 02:43:30
K>* 10.0.2.2/32 [0/100] is directly connected, enp0s8, weight 1, 02:43:30
K>* 10.0.2.3/32 [0/100] is directly connected, enp0s8, weight 1, 02:43:30
L>* 10.0.2.15/32 is directly connected, enp0s8, weight 1, 02:43:30
O   172.16.0.0/24 [110/100] is directly connected, enp0s9, weight 1, 00:19:24
C>* 172.16.0.0/24 is directly connected, enp0s9, weight 1, 01:41:28
L>* 172.16.0.1/32 is directly connected, enp0s9, weight 1, 01:41:28
```

```bash: 追加されたもの
O   10.0.0.100/32 [110/0] is directly connected, lo, weight 1, 00:19:03
O>* 10.0.0.200/32 [110/100] via 172.16.0.2, enp0s9, weight 1, 00:08:19
O   172.16.0.0/24 [110/100] is directly connected, enp0s9, weight 1, 00:19:24
```

O はOSPFのことです。OSPFを有効にしたので新しいルーティングができているということですね。

よくみると、`10.0.0.200/32` つまり Ubuntu2 の lo も確認できます。
直接見えなかったルートが OSPF によって認識できたことがわかります。

ping を送っても
```
Ubuntu1# ping 10.0.0.200
PING 10.0.0.200 (10.0.0.200) 56(84) bytes of data.
64 bytes from 10.0.0.200: icmp_seq=1 ttl=64 time=1.06 ms
64 bytes from 10.0.0.200: icmp_seq=2 ttl=64 time=1.41 ms
^C
--- 10.0.0.200 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 1.055/1.230/1.406/0.175 ms
```

ちゃんと通信できていることがわかりますね！

最後に`write memory`をして設定を保存しておきます。
```bash
Ubuntu1# write memory

Note: this version of vtysh never writes vtysh.conf
Building Configuration...
Integrated configuration saved to /etc/frr/frr.conf
[OK]

# 2 もやる
```

## そのほか

### passive interface

#### 入れる背景

Ubuntu1 はNAT用のインターフェースがありました。
せっかくなのでネットワークコマンドで追加します。

追加後はこちらです。

```bash: sh run
router ospf
 network 10.0.0.100/32 area 0
 network 10.0.2.0/24 area 1
 network 172.16.0.0/24 area 0
```

構成は下記のようになります。

![ospf2.drawio-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613783/6832900b-ccf2-6d07-f010-f28d6f1d9cbf.png)

ここで、vtysh を`exit`で抜けてパケットを観測してみましょう。
`-i enp0s8`は観測するインターフェースを指定しています。

```bash
user@ubuntu1:~$ sudo tcpdump -i enp0s8 -n "ip[9] == 89"

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), snapshot length 262144 bytes
05:50:30.677368 IP 10.0.2.15 > 224.0.0.5: OSPFv2, Hello, length 44
05:50:40.678331 IP 10.0.2.15 > 224.0.0.5: OSPFv2, Hello, length 44
05:50:50.678250 IP 10.0.2.15 > 224.0.0.5: OSPFv2, Hello, length 44
```

すると、`10.0.2.15`（ubuntu1の左手）から`244.0.0.5`（同一線（リンク）上の全てのOSPFルーター）へパケットが投げられていることが分かります。

「左手から繋がっている線」にいる「全てのOSPFルーター」にパケットを投げる...

これは無駄ですね！:relaxed:
なぜなら、左側の線上にはVirtual Box（ホストNAT）しかなく、OSPFを話す機械はいないことが分かっているからです。
実際にパケットを観測しても、同一方向しか観測できず、返事がないですね。

このインターフェースではOSPFは不要、それを明示するのがパッシブインターフェースです。

#### 設定
では入れましょう。
入れ方ですが、2つあります。

1. 全てのインターフェースをパッシブにしてから、必要なものだけ除外する方法
1. 1つずつ不要なインターフェースをパッシブにする方法

1の方で実施したいと思います。

```bash: ubuntu1
# conf t
(config)# router ospf
(config-router)# passive-interface default  # とりあえず全部入れる
(config-router)# exit
(config)# int enp0s9
(config-if)# no ip ospf passive
(config-if)# end
```

パケット観測しても、全く観測されなくなりました。
```
user@ubuntu1:~$ sudo tcpdump -i enp0s8 -n "ip[9] == 89"

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), snapshot length 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel
```
ちなみに、パッシブを設定しなかった方のインターフェースでは、
```
user@ubuntu1:~$ sudo tcpdump -v -i enp0s9 -n "ip[9] == 89"

03:22:57.269083 IP (tos 0xc0, ttl 1, id 58263, offset 0, flags [none], proto OSPF (89), length 68)
    172.16.0.2 > 224.0.0.5: OSPFv2, Hello, length 48
	Router-ID 10.0.0.200, Backbone Area, Authentication Type: none (0)
	Options [External]
	  Hello Timer 10s, Dead Timer 40s, Mask 255.255.255.0, Priority 1
	  Neighbor List:
	    10.0.0.100
03:22:57.737301 IP (tos 0xc0, ttl 1, id 58247, offset 0, flags [none], proto OSPF (89), length 52)
    172.16.0.1 > 172.16.0.2: OSPFv2, Database Description, length 32
	Router-ID 10.0.0.100, Backbone Area, Authentication Type: none (0)
	Options [External], DD Flags [Init, More, Master], MTU: 1500, Sequence: 0x2fdcb5c9
```
`172.16.0.2 > 224.0.0.5` にHelloパケットが、
`172.16.0.1 > 172.16.0.2`に返事としてDatabase Descriptionが返ってきているのが分かります。


### Database
`sh ip ospf database`を実行すると、OSPFでやり取りされている情報を確認することができます。
```
sh ip ospf database

       OSPF Router with ID (10.0.0.100)

                Router Link States (Area 0.0.0.0)

Link ID         ADV Router      Age  Seq#       CkSum  Link count
10.0.0.100     10.0.0.100        54 0x80000008 0xe828 2
10.0.0.200     10.0.0.200       499 0x80000007 0x5094 2

                Net Link States (Area 0.0.0.0)

Link ID         ADV Router      Age  Seq#       CkSum
172.16.0.1     10.0.0.100       544 0x80000004 0xd217

                Summary Link States (Area 0.0.0.0)

Link ID         ADV Router      Age  Seq#       CkSum  Route
10.0.2.0       10.0.0.100        74 0x80000002 0x0875 10.0.2.0/24

                Router Link States (Area 0.0.0.1)

Link ID         ADV Router      Age  Seq#       CkSum  Link count
10.0.0.100     10.0.0.100        64 0x80000004 0x0cf5 1

                Summary Link States (Area 0.0.0.1)

Link ID         ADV Router      Age  Seq#       CkSum  Route
10.0.0.100     10.0.0.100        54 0x80000002 0x4639 10.0.0.100/32
10.0.0.200     10.0.0.100        64 0x80000002 0x4670 10.0.0.200/32
172.16.0.0     10.0.0.100        94 0x80000002 0x1bb1 172.16.0.0/24
```

この辺りは OSPF の LSA タイプの学習を進めたら理解できるようになると思います。

### それ以外
また追記します....

次回は BGP を予定しています。

## 参考
- [How to capture OSPF traffic using tcpdump](https://slmeng.medium.com/how-to-capture-ospf-traffic-using-tcpdump-3d518d7f8704)