Open6

ネットワーク勉強の続き - 2: FRRouting(FRR)/OSPF入門

bells17bells17

このスクラップについて

https://zenn.dev/bells17/scraps/6b957078aac955

上記のスクラップまででLinuxのNetwork Namespaceを使って基本的な?ネットワークを使って、Static Routeでルーティングを設定するというのは最低限体験した。

んでCNIの仕組みの話をしていくとBGPみたいなルーティングプロトコルなるものの話が出てくることが多いので、比較的簡単な(気がした)OSPFというのを試そうというやつ。
(Network Namespaceを使ってOSPFを試すというので良い記事を見つけたという理由も大きい)

あとはtinetというコンテナでネットワーク構成を検証するアプリケーションがあるんだけど、これのルーティングをFRRoutingというソフトウェアを使ってやっているケースが多いのだけど、こういうルーティングプロトコルを喋るアプリケーション?を動かすのも初めてなので併せてどんなものか理解できるようにしていきたい。

flannelの仕組みを理解するだけならルーティングプロトコルについては知らなくても理解できそうな気もしたけどせっかくなので試していく。

ということでFRRouting/OSPFに入門するためのベースとなる記事は下記のもの:

https://zenn.dev/takai404/articles/9633f5aa669f32

https://zenn.dev/takai404/articles/cda74f91c4a330

https://zenn.dev/takai404/articles/7f282e5d5a8200

図もあってネットワーク初心者でもどんなものを作るのかイメージしやすく、コマンドをコピペするだけで動いて動作確認したりする方法とその検証結果も書かれているのでどんな仕組みになっているのかを理解しやすくてとてもありがたい。

一方でFRRouting/OSPF自体については多分なんとなく知っている前提で書かれているので、まず先にそのあたりについて調べた情報をまとめつつ実際に記事の内容を自分で試してみたメモを書こうかなと思ってる。
FRRouting/OSPF自体について調べる過程でChatGPTに質問しまくったので、可能な範囲で自分で調べて裏取りするようにはしたつもりだけど、もしこのスクラップを参考にする人がいたら雰囲気でメモを書いてる箇所もあることに注意してもらえると。

bells17bells17

OSPFについて

OSPF(Open Shortest Path First)とは下記のようなものとのこと:

  • ルーティングプロトコルの一種
  • 内部ゲートウェイプロトコル(IGP)として広く使用されているらしい
  • OSPFは、ネットワーク上の経路情報を交換し、最適な経路を計算してデータパケットの転送を制御するために使用される

要は今回最終的に作りたい↓の図みたいな構成でr1-s1 から r4-s1に通信する場合

  • router1 → router2 → router4 とか router1 → router3 → router4 って経路で行けば r4-s1 までたどり着けて
  • r4-s1まで行くためには router1 → router2 → router4router1 → router3 → router4 のどっちの経路を優先してつかったら良いの?とか(今回の構成だと同じだと思うけど)

みたいのを計算してルーター(Linuxのルーティングテーブルとか)に経路情報を設定していい感じの経路でr1-s1 から r4-s1に通信できるように設定してくれるための仕様がOSPFだって理解した。

OSPFの仕様とバージョン

仕様はRFC2328にある(こちらに日本語訳を書かれてるがある)

OSPFにはv1-3の3つのバージョンがあるっぽくて

  • v1はもうあまり使われてないっぽい?
  • 上記RFCもv2だけど、現在だとIPv4でのOSPFというのは一般的にはv2を指してるっぽい
  • v3はIPv6用のものっぽい

ゲートウェイプロトコル

概要のところで

内部ゲートウェイプロトコル(IGP)として広く使用されているらしい

って書いたけど

  • 内部ゲートウェイプロトコル(IGP)
  • 外部ゲートウェイプロトコル(EGP)

と呼ばれる2種類に区分されるっぽい。

OSPFは内部ゲートウェイプロトコル(IGP)に区分されるもので、要は多分データセンターの内部ネットワーク構築とかで使われるやつで、OSPF以外には

  • RIP
  • IS-IS

といったプロトコルがあるらしい。

外部ゲートウェイプロトコル(EGP)はインターネット上の経路情報を交換するためのプロトコルらしく、EGPに区分される中で主に使われてるのはほぼほぼBGPというプロトコルのみであるらしい。
EGPとBGPのついてはまだ詳しく理解できてないのでそれは別途調べるのでここではこれ以上は書かない。

OSPFの概要

https://tex2e.github.io/rfc-translater/html/rfc2328.html

上記のRFCの翻訳の Abstract によるとOSPFは下記のようなものであるとのこと。

  • リンクステートルーティングプロトコルであり
  • 単一の自律システムの内部で実行されるように設計されていて
  • 各OSPFルーターは、自律システムのトポロジーを記述する同一のデータベースを維持していて
  • このデータベースから、最短経路ツリーを構築することによってルーティングテーブルが計算されるようになっている

リンクステートルーティングプロトコルがどういうものかは自分で説明をかけるほどわかってないのでスキップするけど、一番はじめに書いたような経路情報を計算~設定してくれるものであるのはあってそうだった。
リンクステートルーティングプロトコルについて知りたい方はこことかこのあたりで説明されている。

ふわっとしたOSPFの動作イメージの理解

最終的には実際のネットワーク構成を作ってOSPFを試すときにはFRRを使うのだけど、その際に設定するOSPFの設定はこんな感じになる。

router1# conf t
router1(config)# router ospf
router1(config-router)# network 10.0.0.0/8 area 0
router1(config-router)# end
router1# write
router1# exit

OSPFの設定そのものををしている箇所は network 10.0.0.0/8 area 0 の行だけになる。
network 10.0.0.0/8 の部分でOSPFで経路設定を行うルーターのCIDRを設定してるだけということになる。

areaというのはOSPFの論理的なセグメントみたいなものらしいが、今回はエリアは0しか使わない。
ちなみにエリア0はバックボーンエリアという特別なエリアとして扱われるらしい。
エリアについてもうちょい知りたい方はこの記事とかがイメージしやすいかもしれない。

ともかく、上記のOSPF設定を各ルーター上のFRRで行うだけでルーター同士がいい感じに経路交換してくれて、r1-s1 → router1 → router2 → router4 → r4-s1 といった経路を通って r1-s1 から r4-s1 の通信ができるようにしてくれる。

上記の設定をすることで各ルーターの内部では下記のような処理を行うことで経路設定を行ってくれるよう。

  • Helloパケットというのを送りあって隣接するルーター(neighbor)を探す(構成にもよるみたいだけどHelloパケットはブロードキャストなどで接続してるネットワークの各ルータに送られるよう)
  • Helloパケットを受信したルーターは、送信元とのネットワークタイプ(ブロードキャスト、ポイントツーポイント、仮想リンクなど)が一致しているかどうかを確認する
  • 一致した場合はルーター間でマスタ/スレーブの選出が行われ、ネイバーシップが確立される(マスタはDR(Designated Router)、スレーブはBDR(Backup Designated Router)と呼ばれ、ルーターIDの大きさやルーターに設定された優先度、IPアドレスの値の大きさなどに基づきDRが選出されるとのこと)
  • ネイバーシップが確立されたらリンクステート情報を交換し、ルーターごとにリンク状態データベース(LSDB)を構築する
  • LSDBを参照し、各経路に対する最短経路を計算を行う(最短経路はホップ数やインターフェイスの帯域幅、OSPFに設定した優先度などに基づいて決定されるよう)
  • 計算結果に基づいて各ルーターのルーティングテーブルを設定する(ip route add コマンドでStatic Routeを設定するみたいなのを自動でやってくれる)

Helloパケットの中身については下記の記事が参考になった。

https://www.infraexpert.com/study/ospfz5.html

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |   Version #   |       1       |         Packet length         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                          Router ID                            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                           Area ID                             |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           Checksum            |             AuType            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                       Authentication                          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                       Authentication                          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                        Network Mask                           |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |         HelloInterval         |    Options    |    Rtr Pri    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     RouterDeadInterval                        |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      Designated Router                        |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                   Backup Designated Router                    |
        
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                          Neighbor                             |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                              ...                              |

上記の図はRFCより

また、後で実際に試すFRRのOSPFで下記のような感じでネイバー情報やルーティング情報が見れるんだけど、このあたりの情報がリンク状態データベース(LSDB)に保存されてるデータってことで良いのかな?

$ ip netns exec router1 vtysh -N router1 -c 'show ip ospf neighbor'

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.24.2         1 Full/Backup     1d02h48m          34.864s 10.0.12.2       e1:10.0.12.1                         0     0     0
10.0.34.3         1 Full/Backup     1d02h46m          34.864s 10.0.13.3       e2:10.0.13.1                         0     0     0

$ ip netns exec router1 vtysh -N router1 -c 'show ip ospf route'
============ OSPF network routing table ============
N    10.0.12.0/24          [10] area: 0.0.0.0
                           directly attached to e1
N    10.0.13.0/24          [10] area: 0.0.0.0
                           directly attached to e2
N    10.0.24.0/24          [20] area: 0.0.0.0
                           via 10.0.12.2, e1
N    10.0.34.0/24          [20] area: 0.0.0.0
                           via 10.0.13.3, e2
N    10.0.91.0/24          [10] area: 0.0.0.0
                           directly attached to e0
N    10.0.92.0/24          [30] area: 0.0.0.0
                           via 10.0.12.2, e1
                           via 10.0.13.3, e2

============ OSPF router routing table =============

============ OSPF external routing table ===========

今回OSPFについて調べたのはだいたいこのあたりまでで、このあたりまで理解できてなんとなくOSPFの仕組みをふわっとイメージすることができたので納得できた。

bells17bells17

FRRouting(FRR)

FRRoutingはオープンソースのルーティングソフトウェアで、OSPFやBGPなど様々なプロトコルをサポートしているLinuxなどで動作するソフトウェアのよう。
また、FRRoutingはQuaggaというソフトウェアのforkらしい。

FRRoutingがサポートしてるプロトコルはこちらにマトリクスで紹介されているが、ネットワーク初心者の自分からすると多すぎてよくわからん。

FRRoutingのアーキテクチャ

FRRoutingのアーキテクチャは

  • 各プロトコルごとに独自のdaemonが動作して
  • カーネルにルーティングテーブルを実際に書き込んだりする仲介デーモンである zebra がいる
  • これらのdaemonの設定などを行うCLIとして vtysh がある

という仕組みになっているようで、公式ドキュメントのシステムアーキテクチャにあるように下記のようになっているらしい。

+----+  +----+  +-----+  +----+  +----+  +----+  +-----+
|bgpd|  |ripd|  |ospfd|  |ldpd|  |pbrd|  |pimd|  |.....|
+----+  +----+  +-----+  +----+  +----+  +----+  +-----+
     |       |        |       |       |       |        |
+----v-------v--------v-------v-------v-------v--------v
|                                                      |
|                         Zebra                        |
|                                                      |
+------------------------------------------------------+
       |                    |                   |
       |                    |                   |
+------v------+   +---------v--------+   +------v------+
|             |   |                  |   |             |
| *NIX Kernel |   | Remote dataplane |   | ........... |
|             |   |                  |   |             |
+-------------+   +------------------+   +-------------+

FRRの設定ファイルについてはこのページで解説されていて、Network Namespaceで動かすこともできるようになっている。

その他

このページを見るとカーネル ルーティング テーブルの操作などを行うために

  • ioctl
  • sysctl
  • proc filesystem
  • routing socket / Netlink

が利用されているとのことで、下記の記事に書いたように少し前にNetlinkとioctlを軽く触ったんだけどsysctlとproc filesystemからもネットワーク関連操作が可能なのか。

https://zenn.dev/bells17/articles/netlink-goexample

このあたりまで理解してFRRoutingがどんな感じのソフトウェアかなんとなくイメージできた。
他にもBirdなどネットワークで使うソフトウェアはいくつもありそうだけど、とりあえずFRRoutingが使えればそれなりにいろんなネットワークの検証ができそう。

bells17bells17

Network Namespaceを使ってOSPFを試す

ということでFRRoutingとOSPFについての概要がイメージできたので下記の記事を試していく。
(実際には下記の記事を試しながらChatGPTに質問したり調べたりしてたんだけど、スクラップの流れ的に先にFRRoutingとOSPFについて調べたことをまとめた)

https://zenn.dev/takai404/articles/9633f5aa669f32

https://zenn.dev/takai404/articles/cda74f91c4a330

https://zenn.dev/takai404/articles/7f282e5d5a8200

この先は上記の記事の内容を試しつつわからないことをメモしするといった内容なので、OSPFを試して動作確認などをするだけなら上記記事をそのままやっていただく方が簡単でわかりやすいと思う。

まずはネットワーク構成を作ってOSPFを設定する

上記のネットワーク構成はだいたいこんな感じ
(ネットワークインターフェイス名とかは違うので注意)


設定するIPアドレスなどを一覧で見たいので論理NW構成図は引用させていただいた

元記事に従って環境構築する

基本元記事の通りにコマンドを実行しただけなんだけど、FRRのインストールやsedの処理など、自分の環境ではうまく行かなかった部分があるので実行したコマンドを下記にまとめて書く。
(fib_multipath_hash_policyについては試してない)

# create network namespaces
ip netns add host1
ip netns add router1
ip netns add router2
ip netns add router3
ip netns add router4
ip netns add host2

# create cable(veth pairs)
ip link add eth0 netns host1 type veth peer name e0 netns router1
ip link add e1 netns router1 type veth peer name e0 netns router2
ip link add e2 netns router1 type veth peer name e0 netns router3
ip link add e1 netns router2 type veth peer name e0 netns router4
ip link add e1 netns router3 type veth peer name e1 netns router4
ip link add e2 netns router4 type veth peer name eth0 netns host2

# set IP address: host1
ip netns exec host1 ip addr add 10.0.91.100/24 dev eth0

# set IP address: router1
ip netns exec router1 sysctl -w net.ipv4.ip_forward=1
ip netns exec router1 ip addr add 10.0.91.1/24 dev e0
ip netns exec router1 ip addr add 10.0.12.1/24 dev e1
ip netns exec router1 ip addr add 10.0.13.1/24 dev e2

# set IP address: router2
ip netns exec router2 sysctl -w net.ipv4.ip_forward=1
ip netns exec router2 ip addr add 10.0.12.2/24 dev e0
ip netns exec router2 ip addr add 10.0.24.2/24 dev e1

# set IP address: router3
ip netns exec router3 sysctl -w net.ipv4.ip_forward=1
ip netns exec router3 ip addr add 10.0.13.3/24 dev e0
ip netns exec router3 ip addr add 10.0.34.3/24 dev e1

# set IP address: router4
ip netns exec router4 sysctl -w net.ipv4.ip_forward=1
ip netns exec router4 ip addr add 10.0.24.4/24 dev e0
ip netns exec router4 ip addr add 10.0.34.4/24 dev e1
ip netns exec router4 ip addr add 10.0.92.4/24 dev e2

# set IP address: host2
ip netns exec host2 ip addr add 10.0.92.100/24 dev eth0

# linkup & set routes (routes can not be set before linkup.)
ip netns exec host1 ip link set lo up
ip netns exec host1 ip link set eth0 up
ip netns exec host1 ip route add default via 10.0.91.1

ip netns exec router1 ip link set lo up
ip netns exec router1 ip link set e0 up
ip netns exec router1 ip link set e1 up
ip netns exec router1 ip link set e2 up

ip netns exec router2 ip link set lo up
ip netns exec router2 ip link set e0 up
ip netns exec router2 ip link set e1 up

ip netns exec router3 ip link set lo up
ip netns exec router3 ip link set e0 up
ip netns exec router3 ip link set e1 up

ip netns exec router4 ip link set lo up
ip netns exec router4 ip link set e0 up
ip netns exec router4 ip link set e1 up
ip netns exec router4 ip link set e2 up

ip netns exec host2 ip link set lo up
ip netns exec host2 ip link set eth0 up
ip netns exec host2 ip route add default via 10.0.92.4

# install frr
curl -s https://deb.frrouting.org/frr/keys.asc | sudo apt-key add -
echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | sudo tee -a /etc/apt/sources.list.d/frr.list
sudo apt update
sudo apt install -y frr

# setup frr
for i in `seq 1 4`
do
  if [ ! -d "/etc/frr/router${i}" ]; then
    mkdir "/etc/frr/router${i}"
  fi

  # generate config file for network namespace
  cat <<__EOF__ > /etc/frr/router${i}/vtysh.conf
no service integrated-vtysh-config
hostname router${i}
__EOF__

  sed -e 's/^ospfd=.*/ospfd=yes/' -e 's/#watchfrr_options=""/watchfrr_options="--netns"/' < /etc/frr/daemons > /etc/frr/router${i}/daemons

  chown -R frr.frr "/etc/frr/router${i}"

  # start frr
  /usr/lib/frr/frrinit.sh start "router${i}"

  # ospf setting
  ip netns exec router${i} vtysh -N router${i} -E <<__EOF__
conf t
router ospf
network 10.0.0.0/8 area 0
end
write
__EOF__

done

動作確認

動作確認も元記事と似たような感じで行う
(一部書き換えてたりする)

host1 - host2への通信

ip netns exec host1 ping -c 3 10.0.92.100
PING 10.0.92.100 (10.0.92.100) 56(84) bytes of data.
64 bytes from 10.0.92.100: icmp_seq=1 ttl=61 time=0.052 ms
64 bytes from 10.0.92.100: icmp_seq=2 ttl=61 time=0.063 ms
64 bytes from 10.0.92.100: icmp_seq=3 ttl=61 time=0.065 ms

--- 10.0.92.100 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2026ms
rtt min/avg/max/mdev = 0.052/0.060/0.065/0.005 ms

host1 - host2への通信時の経路確認

ip netns exec host1 traceroute 10.0.92.100
traceroute to 10.0.92.100 (10.0.92.100), 30 hops max, 60 byte packets
 1  10.0.91.1 (10.0.91.1)  0.037 ms  0.004 ms  0.004 ms
 2  10.0.12.2 (10.0.12.2)  0.015 ms  0.004 ms  0.004 ms
 3  10.0.24.4 (10.0.24.4)  0.018 ms  0.006 ms  0.005 ms
 4  10.0.92.100 (10.0.92.100)  0.017 ms  0.007 ms  0.007 ms

ちなみに↓と同様に通信経路が分散されているのが確認できた

https://zenn.dev/takai404/articles/cda74f91c4a330#traceroute

リンクダウンによる経路切り替え

リンクダウンによる経路切り替えはそのまま試して無くて、単に片方のリンクをダウンさせたらその状態が反映されてもう片方のルートだけが使わるようになったのを確認しただけ。

# show ip routeすると10.0.92.0/24の経路が10.0.12.2と10.0.13.3の2つあるのが確認できる
ip netns exec router1 vtysh -N router1 -c 'show ip route'
Codes: K - kernel route, C - connected, 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,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

O   10.0.12.0/24 [110/10] is directly connected, e1, weight 1, 1d04h14m
C>* 10.0.12.0/24 is directly connected, e1, 1d04h16m
O   10.0.13.0/24 [110/10] is directly connected, e2, weight 1, 1d04h14m
C>* 10.0.13.0/24 is directly connected, e2, 1d04h16m
O>* 10.0.24.0/24 [110/20] via 10.0.12.2, e1, weight 1, 1d02h37m
O>* 10.0.34.0/24 [110/20] via 10.0.13.3, e2, weight 1, 1d04h09m
O   10.0.91.0/24 [110/10] is directly connected, e0, weight 1, 1d04h14m
C>* 10.0.91.0/24 is directly connected, e0, 1d04h16m
O>* 10.0.92.0/24 [110/30] via 10.0.12.2, e1, weight 1, 1d02h37m
  *                       via 10.0.13.3, e2, weight 1, 1d02h37m

# 片方の経路をリンクダウンすると、ダウンした経路がshow ip routeの10.0.92.0/24から消える
ip netns exec router2 ip link set e1 down
ip netns exec router1 vtysh -N router1 -c 'show ip route'
Codes: K - kernel route, C - connected, 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,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

O   10.0.12.0/24 [110/10] is directly connected, e1, weight 1, 1d04h15m
C>* 10.0.12.0/24 is directly connected, e1, 1d04h16m
O   10.0.13.0/24 [110/10] is directly connected, e2, weight 1, 1d04h15m
C>* 10.0.13.0/24 is directly connected, e2, 1d04h16m
O>* 10.0.34.0/24 [110/20] via 10.0.13.3, e2, weight 1, 1d04h09m
O   10.0.91.0/24 [110/10] is directly connected, e0, weight 1, 1d04h15m
C>* 10.0.91.0/24 is directly connected, e0, 1d04h16m
O>* 10.0.92.0/24 [110/30] via 10.0.13.3, e2, weight 1, 00:00:05

# host1 - host2への通信は成功してtracerouteするとrouter3経路としてが使われているのがわかる
ip netns exec host1 ping -c 3 10.0.92.100
PING 10.0.92.100 (10.0.92.100) 56(84) bytes of data.
64 bytes from 10.0.92.100: icmp_seq=1 ttl=61 time=0.063 ms
64 bytes from 10.0.92.100: icmp_seq=2 ttl=61 time=0.075 ms
64 bytes from 10.0.92.100: icmp_seq=3 ttl=61 time=0.072 ms

--- 10.0.92.100 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2042ms
rtt min/avg/max/mdev = 0.063/0.070/0.075/0.005 ms

ip netns exec host1 traceroute 10.0.92.100
traceroute to 10.0.92.100 (10.0.92.100), 30 hops max, 60 byte packets
 1  10.0.91.1 (10.0.91.1)  0.032 ms  0.004 ms  0.003 ms
 2  10.0.13.3 (10.0.13.3)  0.016 ms  0.004 ms  0.004 ms
 3  10.0.34.4 (10.0.34.4)  0.019 ms  0.006 ms  0.006 ms
 4  10.0.92.100 (10.0.92.100)  0.022 ms  0.010 ms  0.010 ms

# ダウンしたリンクをアップしてから少し待って確認するとrouter2の経路が復活してるのがわかる
ip netns exec router2 ip link set e1 up
# ちょっと待つ
ip netns exec router1 vtysh -N router1 -c 'show ip route'
Codes: K - kernel route, C - connected, 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,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

O   10.0.12.0/24 [110/10] is directly connected, e1, weight 1, 1d04h17m
C>* 10.0.12.0/24 is directly connected, e1, 1d04h19m
O   10.0.13.0/24 [110/10] is directly connected, e2, weight 1, 1d04h17m
C>* 10.0.13.0/24 is directly connected, e2, 1d04h19m
O>* 10.0.24.0/24 [110/20] via 10.0.12.2, e1, weight 1, 00:01:04
O>* 10.0.34.0/24 [110/20] via 10.0.13.3, e2, weight 1, 1d04h11m
O   10.0.91.0/24 [110/10] is directly connected, e0, weight 1, 1d04h17m
C>* 10.0.91.0/24 is directly connected, e0, 1d04h19m
O>* 10.0.92.0/24 [110/30] via 10.0.12.2, e1, weight 1, 00:00:15
  *                       via 10.0.13.3, e2, weight 1, 00:00:15

ルーターに設定されたネイバーシップ情報の確認

ip netns exec router1 vtysh -N router1 -c 'show ip ospf neighbor'

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.24.2         1 Full/Backup     1d07h14m          30.285s 10.0.12.2       e1:10.0.12.1                         0     0     0
10.0.34.3         1 Full/Backup     1d07h13m          30.285s 10.0.13.3       e2:10.0.13.1                         0     0     0

ip netns exec router2 vtysh -N router2 -c 'show ip ospf neighbor'

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.91.1         1 Full/DR         1d07h14m          33.913s 10.0.12.1       e0:10.0.12.2                         0     0     0
10.0.92.4         1 Full/DR         3h02m33s          37.030s 10.0.24.4       e1:10.0.24.2                         0     0     0

ip netns exec router3 vtysh -N router3 -c 'show ip ospf neighbor'

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.91.1         1 Full/DR         1d07h14m          34.318s 10.0.13.1       e0:10.0.13.3                         0     0     0
10.0.92.4         1 Full/Backup     1d07h13m          32.143s 10.0.34.4       e1:10.0.34.3                         0     0     0

ip netns exec router4 vtysh -N router4 -c 'show ip ospf neighbor'

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.34.3         1 Full/DR         1d07h13m          32.577s 10.0.34.3       e1:10.0.34.4                         0     0     0
10.0.24.2         1 Full/Backup     3h03m04s          35.694s 10.0.24.2       e0:10.0.24.4                         0     0     0

ルーティングテーブルの確認

OSPFとLinuxのルーティングテーブルを見比べるとだいたい対応してるっぽい

ip netns exec router1 vtysh -N router1 -c 'show ip route'
Codes: K - kernel route, C - connected, 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,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

O   10.0.12.0/24 [110/10] is directly connected, e1, weight 1, 1d07h24m
C>* 10.0.12.0/24 is directly connected, e1, 1d07h26m
O   10.0.13.0/24 [110/10] is directly connected, e2, weight 1, 1d07h24m
C>* 10.0.13.0/24 is directly connected, e2, 1d07h26m
O>* 10.0.24.0/24 [110/20] via 10.0.12.2, e1, weight 1, 03:08:15
O>* 10.0.34.0/24 [110/20] via 10.0.13.3, e2, weight 1, 1d07h18m
O   10.0.91.0/24 [110/10] is directly connected, e0, weight 1, 1d07h24m
C>* 10.0.91.0/24 is directly connected, e0, 1d07h26m
O>* 10.0.92.0/24 [110/30] via 10.0.12.2, e1, weight 1, 03:07:26
  *                       via 10.0.13.3, e2, weight 1, 03:07:26

ip netns exec router1 ip route
10.0.12.0/24 dev e1 proto kernel scope link src 10.0.12.1
10.0.13.0/24 dev e2 proto kernel scope link src 10.0.13.1
10.0.24.0/24 via 10.0.12.2 dev e1 proto ospf metric 20
10.0.34.0/24 via 10.0.13.3 dev e2 proto ospf metric 20
10.0.91.0/24 dev e0 proto kernel scope link src 10.0.91.1
10.0.92.0/24 proto ospf metric 20
	nexthop via 10.0.12.2 dev e1 weight 1
	nexthop via 10.0.13.3 dev e2 weight 1

あと↓の部分を見るとrouter2とrouter3のweightはどちらも1なので基本的には50:50で経路になるよう。
weightは使用する経路の優先度で値が大きいほど優先度が高くなる設定のよう。

10.0.92.0/24 proto ospf metric 20
	nexthop via 10.0.12.2 dev e1 weight 1
	nexthop via 10.0.13.3 dev e2 weight 1

自分で追加で調べたこと

一部はFRRoutingやOSPF自体のページにも書いてあるけど書ききれなかったやつ

vtyshの show ip ospf neighbor のフィールドの意味

ip netns exec router1 vtysh -N router1 -c 'show ip ospf neighbor'

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
10.0.24.2         1 Full/Backup     1d02h48m          34.864s 10.0.12.2       e1:10.0.12.1                         0     0     0
10.0.34.3         1 Full/Backup     1d02h46m          34.864s 10.0.13.3       e2:10.0.13.1                         0     0     0
Field Description
Neighbor ID 隣接しているルーターのユニークなID
Pri 隣接ルーターが設定した優先度(Priority)
State 隣接ルーターの状態(Exstart、Exchange、Fullなど)
Dead Time 隣接ルーターが不活性と判断されるまでの残り時間
Address 隣接ルーターのIPアドレス
Interface 隣接しているインターフェース

CISCOの資料とかで確認できた
https://www.cisco.com/c/ja_jp/support/docs/ip/open-shortest-path-first-ospf/13688-16.html

FRRのOSPCが設定するLinuxのルーティングテーブルは手動でも設定できるの?

結論から言うと問題無くできるっぽい。

例えばrouter1だとOSPFによって下記のような設定になっている。

ip netns exec router1 ip route
10.0.12.0/24 dev e1 proto kernel scope link src 10.0.12.1
10.0.13.0/24 dev e2 proto kernel scope link src 10.0.13.1
10.0.24.0/24 via 10.0.12.2 dev e1 proto ospf metric 20
10.0.34.0/24 via 10.0.13.3 dev e2 proto ospf metric 20
10.0.91.0/24 dev e0 proto kernel scope link src 10.0.91.1
10.0.92.0/24 proto ospf metric 20
	nexthop via 10.0.12.2 dev e1 weight 1
	nexthop via 10.0.13.3 dev e2 weight 1

それを手動で設定するのであれば下記のような感じでやれば設定可能のよう。

sudo ip netns exec router1 ip route add 10.0.24.0/24 via 10.0.12.2 dev e1
sudo ip netns exec router1 ip route add 10.0.34.0/24 via 10.0.13.3 dev e2
sudo ip netns exec router1 ip route add 10.0.92.0/24 nexthop via 10.0.12.2 dev e1
sudo ip netns exec router1 ip route add 10.0.92.0/24 nexthop via 10.0.13.3 dev e2

ちなみに proto ospfproto <value> の部分は任意の値を設定できるらしく、下記のようにすれば任意の値を proto に設定できるラベルのようなものとのことだった。

sudo ip route add 10.0.0.0/24 via 192.168.1.1 proto XYZ

結局各ルーターはなんで経路設定をいい感じにできたの?

各ルーターに設定した設定は全部同じで

conf t
router ospf
network 10.0.0.0/8 area 0
end
write

という設定をしただけだった。

んで network 10.0.0.0/8 という設定があると思うんだけど、これがはじめに↓でOSCPについて書いたところにも書いたけど、この設定によってそれぞれのルーターは 10.0.0.0/8 のレンジ内にHelloパケットなるものをブロードキャストしてOSCPのルーター?がいることを広告してる。

https://zenn.dev/bells17/scraps/238c522e2f7c9b

このHelloパケットを受け取ると、お互いにネイバーシップを確立し合うという処理を行うので、結果的に隣接するルーター同士がお互いにネイバーシップを確立することで、通信し合うことが可能な経路設定が自動で行われるということだと理解してる。

vtyshで show ip ospf route コマンドを叩くと↓みたいな感じの出力になるんだけど、これを見ると隣接したルーターの情報以外も情報が入っているので、こういった情報を元に自身のルーティングテーブルをいい感じに設定してるのかな?と想像してる。

ip netns exec router1 vtysh -N router1 -c 'show ip ospf route'
============ OSPF network routing table ============
N    10.0.12.0/24          [10] area: 0.0.0.0
                           directly attached to e1
N    10.0.13.0/24          [10] area: 0.0.0.0
                           directly attached to e2
N    10.0.24.0/24          [20] area: 0.0.0.0
                           via 10.0.12.2, e1
N    10.0.34.0/24          [20] area: 0.0.0.0
                           via 10.0.13.3, e2
N    10.0.91.0/24          [10] area: 0.0.0.0
                           directly attached to e0
N    10.0.92.0/24          [30] area: 0.0.0.0
                           via 10.0.12.2, e1
                           via 10.0.13.3, e2

============ OSPF router routing table =============

============ OSPF external routing table ===========

FRRoutingの設定は何をしてたの?

このあたりはだいたい元記事に書いてあると思うけどとりあえずまとめておく

/etc/frr/router${i} を作ってた理由は?

FRRoutingはNetwork Namespaceをサポートしていて、/etc/frr/<namespace>/のディレクトリを作ることで各Network Namespaceごとに設定をすることができるから

/etc/frr/router${i}/daemons ファイルって何?

FRRoutingの概要をまとめたところでも書いたけど、FRRoutingはプロトコルなどでプロセスが別れていてこの daemons ファイルで起動するdaemonを設定してあげたりする必要があった。
また、watchfrr_optionsに動作するNetwork Namespaceも指定してあげる必要がある。
なので、デフォルトのNetwork Namespaceの設定ファイルである /etc/frr/daemons をsedで書き換えたものを /etc/frr/router${i}/daemons に設置してた。

/etc/frr/router${i}/vtysh.conf ファイルって何?

名前の通り vtysh の設定ファイル。
各Network Namespace用に下記のような設定ファイルを作ってた。

no service integrated-vtysh-config
hostname router${i}

今回はOSPFの設定を行ったが、デフォルトではそれらの設定は frr.conf というファイルに設定が書き込まれるが、下記でその設定を無効にしてたよう

no service integrated-vtysh-config

https://docs.frrouting.org/en/latest/vtysh.html?highlight=vtysh.conf#clicmd-service-integrated-vtysh-config

元記事では下記のような理由で無効化していたとのこと。

frrはospfdだけではなくbgpdやripdなど他のダイナミックルーティングプロトコルデーモンを動作させることができます。通常は各デーモンごとにospfd.conf, bgpd.conf, ripd.confと別々のファイルにコンフィグが保存されます。
service integrated-vtysh-configを設定するとfrr.confというファイルにすべて保存してくれて便利… となるはずなのですが、network namespace環境で使おうとするからなのか、うまく動作しないのでnoをつけて無効化しています。

hostname router${i}

はまんまhostnameを設定してるよう

お掃除

for i in `seq 1 4`
do
  /usr/lib/frr/frrinit.sh stop "router${i}"

  # delete frr namespace files
  if [ -d "/etc/frr/router${i}" ]; then
    rm -r "/etc/frr/router${i}"
  fi
done

ip netns del host1
ip netns del router1
ip netns del router2
ip netns del router3
ip netns del router4
ip netns del host2
bells17bells17

まとめ

  • はじめにも書いた通りFRRoutingとOSPFの基礎の基礎くらいをNetwork Namespaceを使って学ぶことができた
  • ついでに復数のルーターを経由する構成を初めて試したので勉強になった
  • いちいちStatic Routeを設定しなくても良いので楽だなというのもちょっと実感できた
  • vtyshのCISCO風?のコンソールにいまいち慣れない
  • ChatGPTに質問しまくりながら検証したり調べるのはかなり有効だと思った
  • 次はflannelか、tinetのCloseネットワークの例でBGPの勉強をしたいなと思った