← 記事一覧

ネットワークエンジニアのユニットテスト

ネットワーク自身が唯一のオラクルであるとき、トポロジーエンジンをどうテストするか

Michel Wijnberg

トポロジーエンジンのテストには厄介な性質があります。それがやることの大半について、 期待される答えを書き下すことができないのです。

自分ででっち上げたグラフに対して Dijkstra の実装をユニットテストすることはできます。それ で証明できるのは、あなたの Dijkstra が Dijkstra であることだけです。実際の LSDB から構築 したグラフが、ルーターが本当に使っているグラフなのかについては何も言っていません。そして それこそが唯一重要なことであり、面白い形で間違いうる唯一のものです。

そこで問いはこうなります。オラクルは何か。


ルーターがリファレンス実装です

私が落ち着いた答えは、これを 2 つに分けます。RFC 2328 は仕様です。プロトコルが何をするべ きかを述べています。ラボのルーターは振る舞いのオラクルです。実装が実際に問われたときに何 をするかを述べます。Osprey は両方を満たさなければならず、両者が食い違うところでは、その食 い違い自体が発見です。ありがたいのは、そのオラクルがすぐそこにいて、いつでも尋ねられるこ とです。

これで検証はパイプラインになります。

64 台の実機ルーター
      ↓  show ip route ospf  /  show ip ospf database summary
正解データ:各ルーター自身がインストールしているテーブル

Osprey の再構成、同じ瞬間、同じスコープ

4,032 の順序付きペアすべてを 4 つの独立したアサーションで比較

これはその比較の再構成側です。あるルーター自身のテーブルを、Osprey が保持している姿です。

lax1-gw1 のルーティングテーブル:種別バッジ、メトリック、ECMP ネクストホップのペアを伴う 428 経路
lax1-gw1 のルーティングテーブル:種別バッジ、メトリック、ECMP ネクストホップのペアを伴う 428 経路

428 経路が種別ごとに分かれています(C 直結、O エリア内、O IA エリア間、E2 外部)。 それぞれにメトリック、広告元ルーター、そしてこの後の話にとって重要なネクストホップの完全 な集合が付いています。ですから 172.16.2.31, 172.16.2.32 は、ソート順で先に来たほうでは なく、実際そうであるとおりの 2 経路 ECMP として現れます。

件数よりも 4 つのアサーションのほうが重要です。

アサーションなぜ別立てなのか
メトリックが厳密一致たまたま長さが合っているだけの誤った経路を捕まえる
経路種別が厳密一致(intra / inter / external誤ったルールでたどり着いた正しいコストを捕まえる
ECMP ネクストホップの完全な集合が同一有効なメンバーを 1 つ選んで答えと称する行為を捕まえる
終了状態 = 要求した宛先で delivered途中で止まってもっともらしく見える探索を捕まえる

このうちどの 3 つが通っても、モデルが間違っていることはありえます。これは仮定の話ではありま せん。前回の記事のバグが生んだ経路は、端点は正しく実際より安いコストでした。もっと怠惰な比較なら、まさにそれを素通りさせたはずです。

現在、4 つすべてが 4,032 ペア中 4,032 で通ります。私が気にしている数字は 4,032 ではありませ ん。4 です。失敗できる独立した経路を、私がいくつ用意したかという数です。


オラクルがないなら、ファジングする

正解データはネットワークに尋ねられるときには機能します。問題のもう半分には機能しません。機器 が不正な形式の、切り詰められた、あるいは単に奇妙なものを送ってきたときにどうなるか、です。

Osprey にはプロトコルパーサーに関する絶対のルールがひとつあり、それはコード品質の努力目標では なく製品上の制約です。**異常はログに残して続行する。決してクラッシュしない。**不正な LSA で死 ぬ監視システムは、まさに何か面白いことが起きているその瞬間に、あなたの可視性を奪います。

ベンダーがどう驚かせてくるかを列挙することはできません。だからファジングします。

make fuzz                          # every target, 10s each
make fuzz FUZZTIME=60s             # longer
make fuzz FUZZPKG=./internal/isis/ # one package

このリポジトリでの現在の数は次のとおりです。

ファズターゲット110
テストファイル419
ベンチマーク98

110 のファズターゲットは見栄えのための指標ではありません。攻撃者やバグのあるエージェントがバイ トを支配するパース境界ごとに、おおむね 1 つという数です。OSPFv2 と OSPFv3 のパケットとすべての LSA タイプ、IS-IS の PDU と TLV、BGP のメッセージとパス属性、BMP のヘッダー、SNMP の varbind デ コード。そのどれもが、「この機器は私に何を送ってくるのか」という問いへの正直な答えが「まったく 分かりません」である場所です。

ベンチマークが存在するのは、それと関連した理由からです。プロトコルパーサーはホットパス上にあり、 バッファに sync.Pool を使ってパケットあたりゼロアロケーションで書かれています。そして b.ReportAllocs() 付きのベンチマークだけが、次に誰かが便利な fmt.Sprintf を足したときにそれが 黙って退行するのを止めてくれます。


本物のデータベースを必要とするテスト

第 3 のカテゴリは、そのどちらの手法も受け付けません。Osprey の難しいクエリは、集約と複数結合を伴 う CTE です。「アクティブなのに一度もポーリングされていない機器はどれか」「分断されているエリアは どれか」「時刻 T 時点のグラフを再構成せよ」。それをテストするためにデータベースをモックしても、証 明できるのはモックが自分の期待と一致することだけです。

そこでそれらは testcontainers を通じて本物の PostgreSQL に対して走ります。プロジェクトのルールは明 示的です。CTE / 集約 / 複数結合のクエリには本物の DB テストが必須であり、空集合、NULL、境界条 件、そしていちばん多くのバグを捕まえるもの、すなわち相互排他性を網羅します。あるクエリが機器を カテゴリに振り分けるなら、カテゴリの合計は総数と一致しなければなりません。それが一致しないことがど れほど多いか、そして、どの数字も単体ではもっともらしく見えるダッシュボード上でそれがどれほど見えな いかは、驚くほどです。


ベンダーは RFC を読み聞かせてはくれません

最後のカテゴリは、どれだけ内部でテストしても見つからないものであり、ラボがその働きぶりで元を取る場 所です。実機は、あなたが読んだ標準を実装していません。それに隣接する何かを実装しています。

このラボからいくつか。どれも実際に時間を食いました。

**存在しない MIB。**ラボの EVPN サービスポッドにある vEOS のリーフは、IS-IS ではなく OSPF で発見せ ざるをえませんでした。まったく華のない理由で、vEOS は ISIS-MIB のツリーをどちらも実装していないので す。部分的に、ではありません。まったくです。正しい SNMP コードをいくら書いても直りません。唯一正し い対応は、機器が実際にサポートしているプロトコルで発見し、その理由を文書に残すことです。

標準以前の方言。MPLS L2VPN の疑似ワイヤーには標準 MIB があり、RFC 5601 です。実機の IOS はその代 わりに標準以前の Cisco 方言を積んでいます。そこでポーラーは両方を実装し、自動でフォールバックします。 そして「両方に対応しています」はまさに腐りやすい種類の主張なので、2 つのドライバーはパリティゲート に縛られ、標準 MIB のパスが Cisco のパスから黙って乖離できないようにしてあります。

**時代に忘れられた暗号。**ここのルーターは 2 つの IOL イメージで動いています(124 台が IOS 15.2(4)S7、 残り 68 台が 15.4(2)T4)。そしてそのすべてが、SHA-1 の鍵交換と ssh-rsa のホスト鍵しか提供しません。 15.2 の一群はさらに、暗号方式が CBC 止まりです。素の現代的な OpenSSH クライアントは鍵交換の時点で拒否 するので、接続は認証を試みる前に死にます。Osprey の SSH クライアントはレガシーのフォールバックを明示的 に抱えています。そうしない場合の代替が、「ベンダーのスライドでは動くが、顧客の実際の設備では動かない」 ターミナル機能だからです。

**一度も起動されていなかったサーバー。**このラボの以前の 64 ルーター構成では、どこにも ip ssh version 2 が設定されていながら RSA 鍵が一度も生成されておらず、SSH サーバーは単に動いていませ んでした。全ノードで、しかも見えない形で。show ip sshDisabled と表示し、設定は完成しているよう に見えていました。

どれも仕様を読んで見つかるものではありません。自分のコードを実機に向け、それが失敗するのを見ることで見 つかるものです。


トポロジーエンジンとは本当は何なのか

検証ハーネスを作っている途中のどこかで、この対象の形が私にははっきり見えてきました。

入力:   雑然として、部分的で、矛盾したネットワーク状態
出力:   決定論的なモデル
オラクル:ルーターそのもの

それはほとんどコンパイラです。そう考えることの有用な帰結は、コンパイラがもっともらしさではなく 適合性で判断されるということです。「生成されたコードはだいたい正しそうに見えます」を受け入れる人は いません。

推測を拒む製品についてシリーズを書けるのは、私がとりわけ高潔だからではありません。求めればいつでも私に 反論してくれる機械が 64 台あり、それらすべてに一度に尋ねるハーネスがあるからです。

それがなければ、「Osprey はパスを正しく計算する」は意見です。それがあれば、4 つのアサーションについて 4,032 分の 4,032 であり、火曜日の午後に再現できます。

違いはそれがすべてです。


これがシリーズ 2 の最終回です。シリーズ 1 の 3 つの IGP、1 枚の地図ゼロフットプリントホップバイホップの真実Osprey が推測を拒むこと は、今回テストにかけた原則そのものを扱って います。

Osprey は自社運用型のネットワーク可視化・エンジニアリング基盤です。32 台まで無料でお試しいただけます。他の記事を読むこともできます。