Dev Study
← ネットワークの仕組み
レッスン 5 / 13·約 13 分·第2期 ネットワークの仕組み

ルーティング表 — 複数の行が当てはまったら、どれを選ぶのか

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択今ここ
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理
  7. DB保存

リクエストがアプリケーションに届くまでには、いくつもの装置を通ります。今回はそのうち「ルータが次の行き先を決める」部分だけを扱います。DNSで宛先IPが分かった後、そのIPへどう向かうかを決める段階です。

まず結論

ルータは、宛先に当てはまる行の中から「最も細かく指定している行」を選びます。これを最長一致(longest prefix match)といいます。

表の上から順に見て最初に当たった行、ではありません。ここを取り違えると、通信が想定と違う経路へ流れた理由が永久に分かりません。

? 読む前に予測

あるサーバのルーティング表に、次の3行が入っています。宛先 192.168.1.130 宛てのパケットは、どの行に従って送られるでしょうか。 ① default (=0.0.0.0/0) ② 192.168.1.0/24 ③ 192.168.1.128/25

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

ルータが持っているのは「宛先の範囲 → 出口」の対応表

ルータやサーバは、パケットを受け取ると、その宛先IPアドレスを見て「どこへ流すか」を決めます。このとき参照するのがルーティング表です。ひとことで言えば「この範囲の宛先なら、この出口へ」という対応表です。

ここで最初の引っかかりどころが出てきます。表の各行は、1つのアドレスではなく範囲を指しています。範囲である以上、ある宛先アドレスが複数の行の範囲に同時に入ることが起こります。むしろそれが普通です。

1つの宛先が、3つの範囲すべてに入っている
宛先 192.168.1.130
この宛先を含む範囲は?
0.0.0.0/0全アドレス
192.168.1.0/24.0 〜 .255
192.168.1.128/25.128 〜 .255
  • ・3つとも「当てはまっている」。どれか1つだけが正しいのではない
  • ・だからこそ、この中から1つを選ぶ規則が必要になる

したがってルータには、当てはまった複数の行から1つを選ぶ規則が必要です。その規則が最長一致です。

具体実物

実際のルーティング表を見る

Linuxで ip route show と打つと、そのマシンのルーティング表が出てきます。次は、192.168.1.0/24 のネットワークに繋がった、Dockerも動いているサーバの実際の出力です。

$ ip route showコマンド出力
default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.50 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.50

1行目の default が「他のどれにも当てはまらなかったとき」の行、いわゆるデフォルトゲートウェイです。3行目が自分のいるネットワークを表します。/24 や /16 の数字が、範囲の細かさを表しています。

ここで大事なのは、この数字の意味です。/24 は「先頭から24ビットが一致していればこの行に当てはまる」という意味です。IPアドレスは32ビットなので、/24 なら残り8ビットが自由、つまり256個のアドレスを含む範囲になります。数字が大きいほど自由な部分が減り、範囲が狭く、指定が細かくなります。

✓ ここまでの確認

/24 と /25 では、どちらが「細かい指定」でしょうか。

抽象原理

なぜ「細かい方」が勝つのか

最長一致という規則は、当てはまった行のうち、一致を求めるビット数が最も多い行を選ぶ、というものです。ではなぜ細かい方を選ぶのでしょうか。

「細かい方が具体的だから」と答えたくなりますが、それでは説明になっていません。細かい方が勝つと決めたから細かい方が具体的に見えるだけで、理由を言い換えているにすぎないからです。本当の理由は、経路の集約という運用上の必要から来ています。

集約された粗い広告に、細かい例外を1本だけ足す
上流ルータ10.0.0.0/8 は全部こちら
ところが 10.5.4.0/24 だけ別の場所へ向けたい
10.0.0.0/8 → A粗い広告(そのまま維持)
10.5.4.0/24 → B細かい例外(1本足すだけ)
最長一致があるので
10.5.4.9 は自動的に B へ、それ以外は A へ粗い広告を書き換えなくて済む
  • ・もし逆の規則(粗い方が勝つ)だったら、例外を作るたびに集約を解体しなければならない
  • ・つまり最長一致は「細かい方が偉い」ではなく、集約を成立させるための仕組み

インターネットの経路情報は膨大なので、上流のルータは「この大きな塊は全部こちら」という粗い案内にまとめて広告します。これが集約です。ところが、その塊の中の一部分だけを別の場所へ向けたいことがあります。このとき最長一致があれば、粗い案内はそのままに、細かい行を1本足すだけで済みます。

順序の話も押さえておきます。最長一致で複数の行が残った場合に初めて、メトリック(経路の優先度を表す数値)の比較に進みます。逆ではありません。メトリックがどれだけ良くても、範囲が粗ければ細かい行には勝てません。

具体実物

実際に照合してみる

宛先 192.168.1.130 が 192.168.1.128/25 に入るかどうかを、ビットで確かめます。/25 は4オクテット目の先頭1ビットまでを見る、という意味です。つまり4オクテット目が128以上か未満かで、範囲が上下に二分されます。

4オクテット目をビットで見る表
値 2進数 /25 の判定ビット 属する範囲
130 10000010 先頭が 1 192.168.1.128/25 (上半分)
127 01111111 先頭が 0 192.168.1.0/25 (下半分)

Linuxには、この判定を実際にカーネルに尋ねるコマンドがあります。ip route get です。man-pageには「そのパスに沿ってパケットを送るのと同等」と書かれており、表を眺めるのではなく本物の経路検索を実行します。さらに fibmatch を付けると、勝った行そのものを表示してくれます。

$ ip route get 192.168.1.130 fibmatchコマンド出力
192.168.1.128/25 via 192.168.1.254 dev eth0
✓ ここまでの確認

192.168.1.0/24(メトリック 0)と 192.168.1.128/25(メトリック 9999)の2行があるとき、宛先 192.168.1.130 はどちらの行に従いますか。

抽象原理

よくある誤解 — 上から順に見ているわけではない

ここが本レッスンで最も間違えられる点です。ルーティング表は、上から順に見て最初に当たった行を使う、という仕組みではありません。

実際、表示される順番と判定の順番は無関係です。Linuxカーネルの内部では、ルーティング表はそもそも上から順に読む一覧ではなく、LC-trie という木構造で保持されています。上から順に見るための「先頭」という概念自体がありません。表示が整列されて見えるのは、人間が読みやすいようにしているだけです。

そしてデフォルトルートも、特別扱いされた「最後の砦」ではありません。0.0.0.0/0 という、一致を求めるビット数が0本の、ごく普通の1行です。0ビットの一致でよいので全宛先に当てはまりますが、他のどんな行も1ビット以上は求めるため、必ず負けます。結果として「他に何もなければこれ」という振る舞いになるだけです。

具体実物

判定を1行ずつ追う

宛先 192.168.1.130 に対して、表の全行がどう判定されるかを並べます。上から順に打ち切るのではなく、全行を照合してから最も細かいものを選んでいることに注目してください。

宛先 192.168.1.130 の照合(全行を見てから決める)
0.0.0.0/00ビット一致× 当てはまるが最弱
172.17.0.0/16そもそも一致しない× 対象外
192.168.1.0/2424ビット一致× 当てはまる
192.168.1.128/2525ビット一致○ 最も細かい
↓
192.168.1.128/25 に従って転送(メトリックを見るのはこの後)
  • ・記述順を入れ替えても結果は変わらない
  • ・「当てはまる行が複数ある」のは異常ではなく通常の状態
⇄ 2つを見比べる
具体例 A

ルーティング表 — 細かさで選ぶ

3行とも 192.168.1.130 に当てはまりますが、選ばれるのは最も細かい /25 の行です。書かれている位置は結果に影響しません。/25 を表の一番下に書いても勝ちます。

宛先 192.168.1.130 の照合表
行 一致ビット数 当てはまる? 選ばれる?
0.0.0.0/0 0 ○ ×
192.168.1.0/24 24 ○ ×
192.168.1.128/25 25 ○ ○ ← 最も細かい
具体例 B

ファイアウォール — 順序で選ぶ

こちらは上から順に評価し、最初に当たった行で決着します。2行目の広い許可ルールが先にあるため、3行目の細かい拒否ルールには到達しません。行を入れ替えると結果が変わります。

アクセス制御ルール(上から評価)設定ファイル
1: deny from 10.0.0.5 → 当たらない
2: allow from 192.168.1.0/24 → 当たる ★ここで確定
3: deny from 192.168.1.130 → 評価されない

この2つは、どちらも「当てはまる候補が複数あるときに1つを選ぶ」仕組みです。選び方の違いは何で、なぜその違いが生まれるのでしょうか。

どちらも同じ「表」の形をしています。違うのは選び方の規則です。少し考えてから開いてください。

この章のまとめ

  • ルーティング表の各行は1つのアドレスではなく範囲を指すので、1つの宛先に複数の行が当てはまるのが普通。
  • その中から選ぶ規則が最長一致。一致を求めるビット数が最も多い(最も細かい)行が勝つ。
  • メトリックが比較されるのは最長一致で絞った後だけ。メトリックがいくら良くても粗い行は細かい行に勝てない。
  • 「上から順に最初に当たった行」ではない。それはファイアウォールの規則であって、ルーティングの規則ではない。
  • デフォルトルートは特別な最後の砦ではなく、一致ビット数0の普通の行。0ビットなので全部に当てはまり、そして必ず負ける。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 4正解: 0

ルーティング表に 10.0.0.0/8、10.5.0.0/16、10.5.4.0/24 の3行があります。宛先 10.5.4.9 はどの行に従いますか。

用語集(5語)
最長一致 (longest prefix match)
宛先に当てはまる複数の経路から、一致を求めるビット数が最も多い(最も範囲が狭い)ものを選ぶ規則。RFC 1812 が定める判定順序の2番目に位置する。
プレフィックス長 (/24 などの数字)
アドレスの先頭から何ビットの一致を求めるか。IPv4は32ビットなので、/24 なら残り8ビットが自由となり256アドレスの範囲を表す。数字が大きいほど範囲は狭い。
デフォルトルート
0.0.0.0/0。一致ビット数が0なので全宛先に当てはまるが、他に当てはまる行があれば必ず負ける。結果として「他になければこれ」として働く。
メトリック
経路の優先度を表す数値。小さいほど優先される。ただし比較されるのは最長一致で絞った後、同じ細かさの行が複数残ったときだけ。
経路集約 (CIDR)
複数の小さな範囲を1つの大きな範囲にまとめて広告すること。最長一致があるおかげで、集約した粗い経路を維持したまま、一部だけを細かい経路で上書きできる。