SONiCがCMIS 4.0のQSFP-DDをデコードするとベンダーフィールドが文字化けする、SFFモジュールは問題なく解析できるのに
うちの資産管理ツールは全スイッチを巡回して、SONiCのCLIから直接それぞれのプラガブルのベンダー、型番、シリアルを記録しています。ほとんどの機種では問題なく動くのですが、あるロットのQSFP-DDモジュールだけは識別フィールドが化けて返ってきて、アセットデータベースがゴミだらけになります。
- スイッチ: SONiC、QSFP-DDケージ
- モジュール: QSFP-DD、CMIS 4.0、ベンダー型番 T-DP4CNH-NCI、ラベル記載のシリアル L23340629 19
- 同じシャーシの旧世代SFF系モジュールはきれいにデコードされる
$ show interface transc eeprom
Vendor Name: T-DP4CNH-NCI
Vendor PN: <unreadable>
Vendor SN: <garbled characters>
Encoding: <shifted>
Connector: <shifted>
つまり型番がベンダー名の場所に出てきて、シリアルは読めず、encodingとconnectorもずれています。確認したこと:
- モジュールを挿し直して再読み込み、結果はバイト単位で同じ
- ラベルには確かにT-DP4CNH-NCIとL23340629 19と書かれているので、これらの文字列はモジュール内に実在する
- 隣のケージのQSFP28は同じコマンドでvendor、PN、SNを正しく表示する
これはモジュールがEEPROMを間違って書き込んでいるのか、それともCLIがCMISパーツに対して違うバイトを読んでいるのか。それと、とりあえず信頼できる読み取り方はあるのか。
Comments 6
どのブランチを使っていますか。
show interfaces transceiver eepromとsfputilの間には202012でキー名が食い違うという既知の問題があり、202205で修正されています。深追いする前に、まずそれを除外しておく価値があります。同じポートで
sudo sfputil show eeprom -dの出力を貼ってください。sfputilでも同じ文字化けが出るなら、原因は共有のデコードパスにあります。逆にエラーで落ちるなら話は別で、こちらにはCannot get Module EEPROM data: Invalid argumentとだけ答えてデコードまで一切たどり着かないプラットフォームもあります。両方試しました: 同じポートで
sudo sfputil show eeprom -dとshow interfaces transceiver eeprom -dです。文字化けは同じ、フィールドも同じ、シリアルがあるべき場所のゴミも同じでした。Invalid argumentはどこにも出ず、読み取り自体は文句も言わず通ります。つまり2つのコマンドは互いに一致していて、ただ間違った答えで一致しているだけです。隣のQSFP28ポートはどちらのコマンドでもきれいなままなので、プラットフォームというよりこのCMISパーツ固有の問題に見えます。
そのパターンは、理解していないメモリマップにパーサーを当ててしまったときの典型的な兆候です。ベンダー名フィールドに型番が入り込み、シリアルは読めず、connectorとencodingがずれる。モジュールの故障やI2C読み取りの不良なら、エラーかゼロの塊が返ってくるはずで、こんなにきれいに間違った文字列にはなりません。
デコードのコードは
sonic_platform_base/sonic_sfp/sfputilbase.pyにあり、そこでは3つの識別文字列が、何が挿さっていようと関係なく、旧来のSFFマップに対してハードコードされたオフセットから取り出されています。CMIS 4.0のQSFP-DDは識別ブロックをそのアドレスに置いていません(CMIS 4.0仕様のセクション8.3にその記載があります)。つまりコードは正しいモジュールから本物のバイトを読んではいるものの、自分が読んでいると思っているものとは別の中身を読んでいて、その範囲に何が入っていようとそのまま表示しているのです。だからこそきれいに失敗することもありません。識別子バイトを見てCMISレイアウトに切り替えるようなステップがどこにもないからです。実務的な結論としては、CMISマップを理解したパーサーでない限りこれを正しく処理することはなく、それがあなたのブランチに入るまで、このパーツについてのCLI出力は資産管理に使える品質ではありません。アセットデータベース用には、CLIから拾うのではなくページを生のまま読んで自分でデコードしてください。
生データを読みたいならoptoeドライバが向いています。SFP、QSFP、CMISのEEPROMを直接読み書きできる形で公開するので、バイトを取り出して自分のスクリプトでデコードできます。今のところCMIS製品用にアセットデータベースへ流し込むならこれしか使いません。
オフセットを調べに行くなら注意点が一つあります。みんなが引用する表はSFFのもので、ベンダー名はA0h bytes 20-35、PN、rev、SNは40-59です。これはまさにCMISモジュールでゴミが出る原因になっているオフセットなので、そこでは使い回さないでください。Linuxホストをベンチツールとして使う場合も同じ注意が必要です。デコード済みのビューには
ethtool -m、生バイトにはethtool -eがSFP製品には問題ありませんが、CMISで表示されるフィールドを信用する前に、自分のビルドが実際に何を理解しているか確認してください。CMISの扱いが薄いのはEEPROMデコーダーだけではありません。InnoLightの800G QSFP-DDオプティクス、T-DP8CNH-NNOとT-DP8CNT-NNOを1トレイ分投入したところ、だいたい2回に1回の挿入でポートが死にました。datapathはDataPathDeactivatedを報告し、ログには'ConfigSuccess'のタイムアウトが記録され、そこからポートは恒久的にdownのままでした。リトライもなく、自力で復帰する仕組みも何もありません。
犯人はcmis.pyの
decommission_all_datapaths()でした。DEINIT、アプリケーションIDを0にクリア、INITという流れを、各ステップが実際に効いたか確認しないまま立て続けに実行します。うちのパーツはまさにその確認を必要とするため、datapathは中途半端に設定されたまま残り、ステートマシンはただタイマーを待つだけになります。xcvrdのインラインCMISステートマシンの中ではブロッキングできないので、本当の修正は非同期で待つ形にするしかなく、最後に確認した時点では誰もそれを実装していませんでした。バグは違えどテーマは同じです。SFF向けに書かれたコードにCMISの経路を後付けしている、という話です。話の流れに一つ訂正を入れておきます。この2つの故障モードは何度も混同されます。
Cannot get Module EEPROM data: Invalid argumentや、ドライバが直るまで電源再投入後にQSFPがsfputilから消える現象、あるいはget_transceiver_infoをそもそも実装していないプラットフォームは、プラットフォームやドライバ側の欠落であり、デコードが始まる前の段階で止まります。ここで説明されているのはその逆で、読み取り自体は完全に成功していて、その後間違ったフィールドレイアウトで解釈されているだけです。これでモジュールを交換したりドライバのバージョンを追いかけたりする必要はありません。そのモジュール内のバイトは正常で、CMISとしてデコードするツールであれば、ラベル通りのシリアルが表示されます。