OSPFの基本を理解する(実験編)

#はじめに
こんにちは。
こちらは[前回の記事](https://qiita.com/flatbit/items/af48e65d884d60dc457c)に続きまして実験編です。
OSPFの基本動作について実験結果をまとめていきたいと思います。
OSPFはコストを用いた経路算定や差分アップデート、エリアを用いたネットワークの分割と大規模なネットワークには欠かせないルーティングプロトコルです。RIPのようなディスタンスベクタ型のルーティングプロトコルとの違いやOSPFならではの効率的な機能について実機を用いて学習していきます。
なお、OSPFに用いられている「エリア」の概念ですが未だに理解しきれていない部分があるため今回は省いています。

#実験
###使用機器
・Cisco 892ルーター　4台
・Cisco 2960スイッチ 1台（スイッチとして用いるほかにミラーポートによるルーター間のパケットキャプチャに使用）
・PC(WIN/Ubuntu)   　若干台(疎通確認やパケットキャプチャ、ルーターの管理に使用)
・各種ケーブル（コンソール、RJ45LAN、電源）

###実験項目

<dl>
  <dt>1.OSPFの設定</dt>
  <dd>各種コマンドを用いてルーターに対してOSPFの設定を行います。</dd>
  <dt>2.3台のルーター間でやり取りされるパケットの確認</dt>
  <dd>ルーターを3台直列につなげ、ルーター同士でやり取りされるパケットの確認、両端のネットワークでの疎通確認を行います。</dd>
  <dt>3.DR/BDRの選出</dt>
  <dd>同じNW内に4つのルーターを接続し、DRとBDRの選出と2.と比べたその後のやり取りの変化を確認します。</dd>
  <dd>代表ルーターが決まることで実現する差分アップデートについても確認します。</dd>
</dl>

####1.OSPFの設定
まずは下の図のように機器を接続します。
少しわかりにくいIPアドレスを振ってしまったなと自分でも後悔していますが/24のNWのため4つすべてのNWが異なるNWであることがわかるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/633eda2b-b9e1-fd30-d68e-689dd578c435.png)

それではコマンドを打ってOSPFの設定をしていきます。
さすがにインターフェースへのIPアドレスの設定は省略します。

```[]:(OSPF設定)
　　(config-router)# router-id <router-id>
    (config)#router ospf 1
    (config)#version 2
    (config-router)#network <network address> <subnet> area 1 　//ネットワーク公布
```
はい、これだけです。
最初のrouter-idはルーターに名前を付けているようなもので一般にはそのルータのIPアドレスがそのまま割り振られます。
DR/BDR時に用いられるのですが今回は特に関係はないので設定しなくても大丈夫です。
バージョンは現在では主に2(IPv4)か3(IPv6)しか用いられていません。また、多くのルーターでOSPFを有効化した際にはOSPFv2を指すのでわざわざ打たなくても大丈夫です。

そのため、OSPFの設定は実質機能の有効化と公布するNW情報の2つのみで行えてしまいます。
同様の設定を3台のルーターに行います。

OSPFを有効化した途端からHelloパケットが送出され始め、どんどんデータの交換へと進んでいってしまうのでOSPFの有効化を行う前にパケットキャプチャが行えるようにしましょう。
両端のＰＣではHelloパケットこそ確認できますが、経路情報の交換はキャプチャできません。ルーター間のパケットキャプチャの方法として今回用いたのはCatalyst 2960といったマネジメントスイッチを挟み、ミラーポートを用いたリピーター運用を行う方法です。
この実験中に何回か用いることになったので下にコマンドを置いておきます。

```[]:(Switch)
    (config)# monitor session 1 source interface <インターフェース1>　　　　//ミラー元ポート
    (config)# monitor session 1 destination interface <インターフェース2>　//ミラー先ポート
```

####2. 3台のルーター間でやり取りされるパケットの確認
それでは1.で用意したルーター間でOSPFを有効化した際にやり取りされるパケットを確認していきましょう。
今回は左側のルーターから順に設定を行っていきました。

#####2.1 Router1でOSPFを有効化する。
　　Router1(ここからR1)でOSPFを有効化します。
　　下は黄色のNWをWireSharkでキャプチャした時の画像です。有効化した瞬間からちょうど10秒に一回「192.168.12.1(R1)」からマルチキャストにてHelloパケットが送出されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/e2f2c36e-87a7-a7be-ae1b-f99da1470468.png)
　　まだR2でOSPFが有効化されていないため、ネイバー確立やDDの交換などは行われていません。

#####2.2 Router2で有効化する。
　　Router2(同R2)でOSPFを有効化します。
　　3秒間で20個程度のパケットが交換されます。見逃さないように気をつけましょう。
　　下はやり取りされる全体の様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/9f74d88b-484d-25a5-55ed-9e028183b4b3.png)
　　もう少し細かく見ていきましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/3c36c284-fc09-9d3d-5591-c171dc3bdf83.png)
　　まずは、R2(192.168.12.2)でOSPFが有効化され、R2がHelloパケットの送出を始めます。先にOSPFが有効化されていたR1(192.168.12.1)はR2のHelloパケットを聞きつけ、すかさずユニキャスト通信を行うためにARP（相手のMAC）を送出します。
    ARPが正常に完了し、一対一のユニキャストが行えるようになりました。ここからネイバーの確立とLSDBの交換が始まります。

#####2.3 DD(Database Description)を送り合う。
　　互いに必要なLSAを確定させるために自身のLSDBを紹介するDD(Database Description)を送り合います。
　　先程、R1はR2の存在を認知し、ユニキャストでネイバーの確立をするためにARPを飛ばしていました。本来であればこのARPで用いられた情報を元にNo.186のようなユニキャストのHelloパケットを行い、相手にも自分がいることを知らせるのですが、実験ではNo.186が送出される前にR1のHelloパケットが送信されるタイミング(No.183)が来てしまい、R2が先にDDを送り始めてしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/a8abdfa2-9ad9-6966-2a69-a7a01992b6b8.png)
　　さて、DDパケットの中身を見てみましょう。(画像はNo.187)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/01b62a10-c06a-df42-c755-6959cc6b39b2.png)
　　あまり、わかりやすいものでは無いですね。ピンとくる重要な情報としては、DDの始まりを表し、互いのDBと同期をとるための「Init(Initial)」、まだ紹介してないパケットがあること（DDが追加で送られてくる）を示す「More」、基本とするDBか否かを表す「Master」(今回はR2が先に交換を始めたのでR2がマスター)、そしてデータの本命であるLSA（軽量化のためヘッダーのみ）となります。
　　DDによって自分の持っているLSA（ヘッダー）を見せあうことで「自分それ知らないから教えて！」とLSRでLSA全体を要求することができるようになります。

#####2.4 LSR（リクエスト）の送信
　　さて、DDの交換によって自分のLSDBに足りないLSAがわかりました。LSRを作成してLSAの全体を要求します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/d753b033-cddf-ac4b-ad87-45b1504b7f5f.png)
　　画像はNo.191のものです。R1がR2に対してLSAを要求しています。今回はお互い何も知らないので細かい要求はせずにルーターの持つ全ての情報を要求しています。
　　LSAはLSIDと呼ばれるIDで管理しており、ルーターIDとも呼ばれます。特に設定しなければそのルーターの持つインターフェースに割り振られたIPアドレスの中で最大の値になります。

#####2.5 LSUでのLSDBアップデート
　　
　　さて、LSRを受け、リクエストされたLSAをLSU（アップデート）にまとめて（一つのLSRに25個まで格納可能）送信します。
　　LSUはルーター自身がつながっているNW情報を表す「ルーターLSA」と特定のNWとそのNWに到達するための中継点（デフォルトゲートウェイのようなもの）を示す「ネットワークLSA」の2つに分けられるため2台のルーターでそれぞれ2回ずつLSUが送出されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/9a14758e-dbe2-c886-c787-febb34495ba8.png)
　　それではLSUの中身を見てみましょう。画像はNo.195のものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/553ca64d-787f-b766-e529-a9702f4157f1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/d82aaf85-4ee3-3082-9fe8-7de81774ec17.png)
　　R1の持つネットワークの情報がサブネットやコストを含む詳細なデータで送られていることがわかります。
　　なお、コストに関してですが、どちらも同じ100BASEで接続されているのでコストは10になるはずなのですが、なぜか192.168.1.0宛のコストが1になってしまいました。

#####2.6 Ackによる受信確認
　　LSUを受け、正常にLSUが受信できたことを返すAckを送信します。
　　これはTCPなどのコネクション型のプロトコルでよく見られるものですね。送られてきたデータを正常に受信したことを示すためにチェックサムを用いて受信の確認とロスが無いかを確かめています。

以上で初期経路が収束し、以降は平常時はHelloパケットでネイバー維持（キープアライブ）、NW変更時にはLSUを送出して変更をネイバーへ伝えます。
#####2.7 LSDBの更新
1～6までで行われたものと同じやり取りがR2とR3の間でも行われます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/8ae0ebe1-7883-75be-687c-f3b5a8dbdfb6.png)
ここで重要なことがR3とのデータのやり取りがすべてR2を通してのみ行われていることです。
RIPでは経由したルーターの台数分メトリックが加算されていく仕組みのため、経路情報を含んだパケットはNWを端から端まで駆け巡ります。一方でOSPFはLSDBを用いることで異なるNW間でHelloパケットの転送は行わず、同一NW内でのみ経路情報を交換することによって帯域の圧迫を抑えています。

一方でR2のLSDBにR3のNW情報が加わったことで、R2は黄色のNWにLSUを送出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/fccfc45a-3be4-107d-8ed9-3e79fa4a9ae6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/867e8412-1000-3af3-ff59-95dfd8127c0f.png)
画像はNo.1748のもので、「NW：192.168.3.0には192.168.23.2を中継(Transit)してね～」という情報がR1に通知されています。
R1はAckを返しNW全体の構成図（SPFツリー）が各ルーター内で完成します。

さて、ここまでの一連のやり取りで上の画像の端から端までの経路情報がすべてのルーターに格納されたはずです。
実際に両端のPC間でPINGを打って確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/b781678c-4a5d-7cba-f432-fd897ce6019e.png)
正常にルーティングが行われていることが確認できました。

####3.DR/BDRの選出

ここまではルーターが一対一で繋がれている場合のNWでLSDBを作成する一連の流れを見てきました。
では、同一NW内に複数のルーターが接続されていた場合はどうなるのでしょうか。2.7でNW外にはHelloパケットを流さないというようなことを書きましたが、NW内であればすべての端末が見れるマルチキャストで送信されています。NWに変更が加えられるごとにすべてのルーター間で2.のようなやり取りが発生していては明らかに帯域を圧迫しますし、同じようなデータを交換されるためはっきり言って無駄が多いです。ここで[DR/BDR](https://qiita.com/flatbit/items/af48e65d884d60dc457c#%E4%BB%A3%E8%A1%A8%E3%83%AB%E3%83%BC%E3%82%BF%E3%83%BC%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E4%BB%A3%E8%A1%A8%E3%83%AB%E3%83%BC%E3%82%BF%E3%83%BCdrbdr "DR/BDR")が登場します。
DR/BDRの説明は上のリンクに任せて実際の動きを見ていきましょう。

使う構成図はこちらです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/9480b951-a4ce-e055-9507-c6e297f415de.png)
今回はしっかりルーターIDを「10.0.0.(ルーター番号)」に設定するようにします。

```[]:(OSPF設定)
　　(config-router)# router-id <router-id>
    (config)#router ospf 1
    (config)#version 2
    (config-router)#network <network address> <subnet> area 1 　//ネットワーク公布

```

OSPFのDR/BDRの選出方法には優先順位があります。各値の最も大きいルーターがDR、二番目に大きいルーターがBDRとして機能します。

1. ルータープライオリティ値の大きいルーター
1. ルーターIDの値の大きいルーター

ルーターのプライオリティ値はすべてのルーターでデフォルトの値が1になっています。そのため、今回の実験開始時ではR4が最もルーターIDの大きいルーターとしてDRになっているはずです。
DR/BDRの確認方法は2種類あります。
WireSharkを用いたHelloパケットで確認する方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/073b13bb-e558-50fa-49e7-142a61b523fe.png)
以下のコマンドを実行する方法

```[]:(DR/BDRの確認)
    #sh ip ospf int 　
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/a3e092cb-00fa-bb94-b1f5-8d401db5a2af.png)

ルーターのプライオリティ値は下記のコマンドによって人為的に変えることができます。

```
プライオリティ値の設定
    (config-int)#ip ospf priority <0~255> 　
    (config-int)#ip ospf priority 0        //0が設定されたルーターはDR/BDRにならない　
```

それではDR/BDRについて以下のことを実験してみます。

* R1のプライオリティ値を100に設定（R1がDRになるはず）
* R1がDRの状態でR1を切断　（R2がDRに、R3がBDRになるはず）
* R1を再接続する　（**DR粘着性**が働いてDRは変わらない）

実験を始める前にDR粘着性のことを説明しておきます。
DR粘着性とはDRが頻繁に変わり通信が途切れることを防止するために「一度DRになったルーターは操作が加わるかそのルーターがダウンするまでDRを維持し続ける」というものです。そのため、実験項目の最後で本来であればプライオリティ値が最も高いR1が復帰した場合、優先度的にはR1がDRになりますが一度ダウンしているためR2がDRに、R3がBDRとして残り続けます。

それではやっていきましょう。
#####DR/BDRの実験
######3.1 R1のプライオリティ値を100に設定
まずは先程紹介したコマンドでプライオリティ値を100にして設定を保存し、すべてのルーターを再起動します。ここでタイミングをピッタリあわせないとDR/BDRの選出に間に合わなくなり、DR粘着性によって違うルーターがDRになってしまう可能性があります。
各機器の個体差等もあり実機ではなかなか難しい実験です。本番では何回か失敗しました。
ルーターの一斉再起動が行える「Packet tracer」や「GNS3」等でシュミレートすると確実に成功すると思います。

一斉に再起動を行いました。一斉にHelloパケットが流れ、各々がネイバーとして認識していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/b5ccf06f-0010-af8b-42fd-2510dc8f9810.png)
なお、Helloパケットの中にプライオリティ値の情報が含まれており、同じメンバーからHelloパケット2回受信した（新規ネイバーはいない）タイミングでDRを決定します。画像はNo.25のものです。まだDRが決まっていないことが確認できます。No.20の時点でこれと全く同じパケットが送出されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/146d7cff-fa07-c802-f54c-42ebaf9971fa.png)
2回同じメンバーから同じパケットを受信したルーターからDRを確定していきます。画像はNo.28です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/18013596-896d-ed1e-f4f5-92b333286da9.png)
DRとしてR1が選出されたことが確認できます。実験をしてみてわかったのですが、初回のネイバー確立時にはDRのみを決めて経路交換の際にDRがBDRを伝える仕様になっているようです。そのため、上の画像ではBDRもR1になっています。

次のHelloパケット時にはきちんとBDRが決まっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/74f61e58-010b-5b05-5261-3a0887c414fe.png)


######3.2 R1がDRの状態でR1を切断
それではR1がDRになったことが確認できたのでR1を切断してみます。
実機ではLANケーブルを抜くもよし、電源を落とすのもよしです。実機ならではの現実で起こり得る障害（断線、停電）を体感してみましょう。

LANケーブルを抜いてから約30秒、Helloパケットが3週ほどしたタイミングで各ルーターが「あれ？うちのDRダウンしてない？」ということに気づきます。ここで見てほしいのがNWが変更された場合のパケットの少なさです。今回ではBDRであるR4がいち早くダウンに気付いたため、R4がLSUを出し、他のルーターがAckを出したのみ。たった3行でLSDBの更新と同期が完了してしまいました。これが**差分アップデート** （後述）です。
もしR1のダウンに他のルーターが気付くなどタイミングがずれてしまった場合は最初のようなユニキャストのパケットが流れてしまいますが、差分アップデートはダウンの場合においても条件が揃えば有効に機能します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/d789bdbf-bda1-9bb3-b016-b497436ecaee.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/b730c3e0-af87-5128-8990-bb00d1ab31c1.png)
画像は経路収束後のHelloパケットです。BDRであったR4がDRに、暫定で最もルーターIDの大きいR3がBDRになっていることが確認できます。

######3.3 R1を再接続する
それでは先程切断したR1を再接続してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/6874dc19-ce74-a90c-0718-e87e4af06ed3.png)
ここでも差分アップデートが確認できます。赤線部分はDRであるR4と新入りのR1のユニキャスト通信となっておりLSDBの同期が終了したあとはマルチキャストにてアップデートを実施、BDR、DROtherはAckのみで終了。と無駄なパケットを極力減らせていることが確認できます。
また、更新終了後のパケットを覗いてみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/f0f198a7-528d-6ce8-0e0f-3ff0c2b27f3d.png)
DR粘着性が働き、DR/BDRは維持され、R1はDROtherとして登録されていることが確認できました。


###### 差分アップデート
　差分アップデートとは同一NW内において同じようなパケットをやり取りする無駄をなくそう。と言うものです。実験3.3の画像において最初はユニキャストだった通信が途中からマルチキャストになっていました。イメージとしては「最初は新入りに代表者が話を聞きに行き、聞いた話を全員に紹介する」といった感じでしょうか。代表者が変わりに紹介してくれることで新入りは全員と自己紹介をし合う必要がなくなります。現実世界だと一人ひとり自己紹介したいものですが...。ネットワークの世界では情報（パケット）を限られたリソース（回線）を用いて伝えなければならないので集約できるところは集約しよう、という考えですね。

　OSPFには2つのマルチキャストアドレスが用意されています。DR/BDRへの連絡用である「224.0.0.6」と、DRからの情報やその他に用いられる「224.0.0.5」です。下の画像を例に見ていきましょう。下はR1に新たにPCを接続したときのパケットです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2179899/74e38309-a7da-6f52-f8c9-1b57a6ca577d.png)
R1のNWに変更があったため、DRへ連絡するための「224.0.0.6」に向かってLSUを送出します。DRはLSUを受け自身のLSDBを更新し、次のパケットで一般用の「224.0.0.5」を用いてDROtherにLSDBの変更を通達し、BDRは「.5」へDROtherは「.6」へAckを返しています。ルーターが4台だとそこまで簡略化されている感じがしませんがこれがルーター100台などのネットワークをイメージすると「1台が公布して他が受信確認」という形がとても効率的なのが見えてくるのではないかと思います。

#まとめ
　今回はRIPについでOSPFの学習と実機演習を行いました。
　最大ホップ数の関係で規模が限定されているRIPとは異なり、大規模なネットワーク上で運用されることを目的として開発されたプロトコルなだけあって経路情報の簡略化や集約方法の部分で帯域を圧迫せず信頼性、耐障害性を高めるための機能が多く実装されていることを学びました。ダイクストラ法を用いたSPFツリーはコストの概念を取り入れ、より現実の利用環境で求められる「速度」の部分も考慮に入れより最適なルーティングやロードバランシングが実装されています。経路情報（LSDB）の更新には差分アップデートやDR/BDRが用いられより障害の検知、迂回ルートの選定、迂回ルートの公布といった一連の動作が高速化され、ダウンタイムも10秒程度に抑えられることを学びました。
　今回は実験できませんでしたがエリアについてもっと学習して実際に実験を行えたらなと思います。
　以上です。読んでいただきありがとうございました。