トポロジーに嘘をつかれた日
自社製品に対するエンジニアリングのポストモーテムと、それを捕まえたラボ
Michel Wijnberg
ネットワークについて本当のことを教えてもらうために、私は Osprey を作りました。そしてそれ が私に嘘をついていたと知りました。自信たっぷりに、文字で、人にデモして回っていたキャンバ スの上で。
何が起きたのか、どうやって気づいたのか、何を変えたのかを書きます。このシリーズでいちばん 役に立つ回です。誠実さについて私が書いてきたことはすべて、監査対象が自分自身の仕事になる までは安っぽいからです。
私が信じていたこと
Osprey のパスエンジンは、ほとんどのパスツールがやっていることをやっていました。送信元と宛 先を与えると、OSPF トポロジー上で送信元からエリアを意識した Dijkstra を走らせ、いちばん安 い経路を描く。
信用するだけの理由はありました。私が気にしていた RFC 2328 のルールは尊重していました。エリ ア内をエリア間より優先し、エリア間はバックボーンを経由し、E1 を E2 より先に、ECMP はまとめ ずに列挙する。テストもありました。ラボについての私のメンタルモデルとも合っていました。ルー ターを 2 つクリックすれば、それらしいパスが光りました。
同時にそれは、エリア間クエリ 8 回に 1 回、どのパケットも決して通らない経路を描いていました。
どうやって気づいたか
バグ報告からではありません。雑用からです。
まったく別のもののために検証ハーネスを作っていて、それを突き合わせる正解データセットが欲し
かったのです。ラボには AS 200 に 64 台のルーターがあり、すべて SSH で届き、すべて自分のルー
ティングテーブルを喜んで印字してくれます。そこで愚直で明白なことをしました。64 台すべてにロ
グインし、全台から show ip route ospf をダンプしたのです。
そのうえで、目視で眺める代わりに、各ルーターの実際のテーブルを、Osprey のパスエンジンがパス だと主張する内容と、4,032 の順序付き送信元/宛先ペアすべてについて比較しました。
そのうち 360 が食い違いました。
「コストが少しずれている」ではありません。描かれたパスに、パケットが証明可能に一度も訪れない ルーターが含まれていたのです。
代表的なケース
ひとつ挙げます。各行はモデル化ではなく実機で計測したものです。
| ルーター | 宛先についての言い分 | 転送先 |
|---|---|---|
dfw1-gw2 | metric 20031, type inter area | dfw1-cr1 |
dfw1-cr1 | metric 30001, type intra area | ord1-cr1 ← dfw2-cr1 ではない |
ord1-cr1 | metric 20001, type intra area | jfk1-cr1 |
jfk1-cr1 | metric 10001, type intra area | lhr1-cr1 |
lhr1-cr1 | metric 1, connected | 到達 |
Osprey はこう描きました。
dfw1-gw2 → dfw1-cr1 → dfw2-cr1 → iad2-cr1 → ams1-cr1 → lhr1-cr1
パケットは dfw2-cr1 に決して届きません。Osprey のパスはより安いものでした。ただ、どの
ルーターも組み立てない経路だったというだけです。
RFC 2328 の独立した 2 つのルールが dfw1-cr1 にその安い回廊を拒ませます。そして私は、個々の
中間ルーターのレベルでは、そのどちらも実装していませんでした。
§16 ステップ (3) / §16.2 第 1 段落:バックボーンのゲート。複数のエリアに接続するルーター
は、バックボーンの summary-LSA だけを検査します。dfw2-cr1 のコスト 20011 という安いほ
うの summary は、確かに dfw1-cr1 のエリア 4.6.23.0 のデータベースに存在します(自分でも信じ
られなかったので show ip ospf database summary で確認しました)。しかしそれは候補ではあり
ません。dfw1-cr1 が ABR であり、その summary がエリア 0 経由で届いたものではないからです。
RFC 3509 §2.1/§2.2、つまりこれらの実機で実際に動いている Cisco の ABR 挙動は、これをアクティ
ブなバックボーン接続があることに条件づけており、dfw1-cr1 はそれを持っています。
§16.2 ステップ (6):エリア内がエリア間に勝つ、以上。 “If the paths present in the table
are intra-area paths, do nothing with the LSA.” dfw1-cr1 はすでにメトリック 30001 のエリア
内経路を持っています。20011 の summary はそれに負けます。メトリックは比較にすら入りません。
これは経路の種別についてのルールです。
どちらか一方のルールだけでもこの回廊は死にます。私のエンジンはそのどちらも見られませんでした。
dfw1-cr1 に何ひとつ尋ねなかったからです。送信元ルーターの世界観を尋ね、そのうえで他の
8 台のルーターを貫く線を、まるでそれを共有しているかのように引いたのです。
間違いの形
具体的な OSPF の詳細より、それが属するカテゴリのほうが面白いので、正確に名前を付けておく価値 があります。
私はひとつのパスをモデル化していました。ネットワークが実装しているのは独立した判断の 連なりです。この 2 つは、道中のすべてのルーターが同じ入力集合に対して同じ判断ルールを使う かぎり、ぴったり一致します。単一の OSPF エリア内ではそれが成り立ちます(同じ LSDB、同じアル ゴリズム、同じ結果)。だからこそエリア内ペアの欠陥数はこうなりました。
1,193 中 0。
ABR が絡んだ瞬間、入力集合は共有されなくなります。ABR は周囲のルーターとは異なる LSA の 集合を、意図的に見るからです。私のモデルにはその事実を置く場所がありませんでした。私のモデル にはグラフ 1 枚と Dijkstra 1 回があるだけで、それぞれに意見を持つ 64 台のルーターはなかったの です。
| ペア数 | どのルーターも通らないホップを含むもの | |
|---|---|---|
| エリア内 | 1,193 | 0 |
| エリア間 | 2,839 | 360(12.68%) |
| 全体 | 4,032 | 360(8.93%) |
直し方と、それが効いたと分かる理由
エンジンは今、チェーンをたどります。各ホップで、そのルーター自身の LSDB、エリア所属、ABR 状 態、アドミニストレーティブディスタンスの組み合わせを使って、そのルーター自身が宛先アドレスに 向けてインストールしている経路を評価し、そのルーターが実際に選んだネクストホップをたどり、こ れを繰り返します。
そして同じ 4,032 ペアを、同じ正解に対してもう一度走らせました。
| チェック | 結果 |
|---|---|
| ルーター自身のメトリックを正確に再現 | 4,032 / 4,032 |
| 経路種別(エリア内 / エリア間 / 外部)が完全一致 | 4,032 / 4,032 |
| インストール済み ECMP ネクストホップの集合全体が同一 | 4,032 / 4,032 |
要求した宛先でチェーンが delivered で終了 | 4,032 / 4,032 |
「改善した」ではありません。すべてのペアで同一であり、任意に選んだ 1 メンバーではなく等コスト ネクストホップの完全な集合を含めて同一です。
これは、かつてホップをでっち上げていたのと同じクエリです。いまは実際に判断を下すすべてのルータ
ー、判断が行われたエリア、そして両側の物理ポートを表示しています。合計の 30061 は送信元自身が
インストールしているメトリックであり、文字どおり lax1-gw1 で show ip route が印字する数字で
す。
そしてチェーンが計算できない場合(OSPFv3、IS-IS、EIGRP、部分的なスコープ、仮想リンクを持つ
エリア)、エンジンは黙って古い絵に戻ったりしません。理由を名指しする model_note を添えて送信
元を根とするビューを返し、それ自体を説明ステップとして描画します。その拒否は
第 4 回の主題であり、このバグがあったからこそ存在します。
バランスのために、もっと小さいものを
自傷がすべてアルゴリズムとは限りません。私に午後を 1 つ失わせた、2 行のものをご紹介します。
Osprey の GRE レコーダーは本物の OSPF 隣接を張るので、Router-LSA を生成しなければなりません。 初期のころ、それはトンネルの内側サブネットをスタブネットワークとして広告していました。正しそう に見え、RFC 上も適法で、まったく理にかなっています。
するとエリア内のすべてのルーターがトンネルのプレフィックス宛の経路をインストールしました。その 経路は、GRE トンネル自身が乗っていたアンダーレイ経路を上書きしました。外側のトランスポートが壊 れました。隣接が落ちました。レコーダーは再接続し、LSA を再生成し、また同じことをしました。
修正は今ではコードコメントに書いてあります。誰かがうっかり消さないようにです。
// Only the P2P link is advertised. NO stub network for the tunnel
// inner subnet. Advertising the tunnel subnet (even at max cost) causes SPF
// on other routers to install a route for the tunnel prefix, which can
// disrupt the GRE outer path and kill the adjacency.
監視しているものを自分で落としてしまう監視ツールというのは、特別な種類のばつの悪さであり、そし て図面の上では見つけられなかったはずのものです。
ラボの本当の役割
私はかつてラボを「Osprey をデモする場所」と説明していました。それは職務記述として間違っていて、 そこを正したことで作り方が変わりました。
ラボは Osprey をよく見せるためにあるのではありません。Osprey が間違っていることを証明するため にあります。
つまりラボは、私に反論できる度合いにおいてのみ価値があります。だから意図的に扱いにくく作ってあ ります。プロトコルを何ひとつ共有しない 3 つのキャリア。3 つのほうがデモ映えするのに 15 ある OSPF エリア。level-1 エリアが 17 ある IS-IS ドメイン。リンクステートデータベースをそもそも持たず、 OSPF のコードが置いている前提をことごとく壊す EIGRP。そして 124 本すべてで v4 と v6 のコストが 10 倍違うデュアルスタックリンク。
どれもスクリーンショットを美しくはしません。どれも何かを捕まえてきました。
360 本の架空の回廊は、注意深く読んで見つけたのでも、事前に書けるほど私が賢かったテストで見つけた のでもありません。実際に何を考えているか尋ねられる本物のルーターが 64 台あり、抜き取りで確認した 2、3 台を信じる代わりに、ようやく全台に一度に尋ねたから見つかったのです。
そこから当然の問いが出てきます。それが次回の主題です。モデルが正しいかどうかを教えてくれるのがネ ットワークだけだとしたら、それをどうやってテストスイートに変えるのか。