ふと、
昔こんなことやってたなあ
という話を思い出したので書きます。細かいところはあまり覚えてないですけど。
スイッチングハブの基本構造
当時売っていたものはネットワーク機器、そしてそこに搭載するASICを開発していました。具体的なプロダクトとしてはスイッチングハブ(スイッチ)です。
単純な「ハブ」は、あるポートからパケットが来たら、来たポート以外の全ポートにそのパケットをばら撒くということをしますが、それだと全体としてのトラフィックは増大して効率悪いので、そのパケットを送る必要があるポートのみに送ろう、というのがスイッチです。
当時いた会社は、米国シリコンバレーにもオフィスがあって、20〜30人くらいのASIC開発部隊がいました。そこでは、下記のようなシステムを構成するチップセットを開発していました。
ここで内部バスに相当するところは独自仕様で、ルーティング用のチップと複数のMACチップが繋がります。本当は他のチップも繋がってたけど省略。イーサネットポートと書いたところは、本当は物理層チップが繋がり、これら矢印の部分は MII(media independent interface)といわれる切り口になります。また、各MACチップにはパケットを保管するためのメモリがあったと思いますがこれも省略。
イーサネットポートから来たパケットの宛先アドレスを読み取り、ルーティングチップにお伺いをたてて、送り先ポートを教えてもらい、そのポートにパケットを転送する。あわせて、パケットの送信元アドレスと受信ポートの情報は、ルーティングチップで保持されて、その後のルーティングに仕様される。
というのが基本の動きです。まあ、極めてストレートです。
ここで重要なのは、ルーティングチップのほうで、パケット宛先アドレスをもとに送り先ポートを探す作業に時間がかかりすぎるとまずい、ということです。
CAMって値段が高い
図でいうと、ルーティングチップにつながるメモリと書いている箇所に、連想メモリ(CAM:Content Addressable Memory)というデバイスが使用されていました。今どきはどうなのか知りませんが。
このデバイスのメリットは検索が早いということです。
一方で、当時の問題は、このデバイスがすごく値段が高いので、製品全体で見たときのコストが高くなってしまう、というものでした。
コストダウンのための施策
そこで、ルーティングテーブル用のメモリとしてCAM以外でうまくできないか、という話になりました。たとえばシンプルはSRAMでできないか?
パケットの宛先アドレスや送り元アドレスで使われる、いわゆるMACアドレスは48ビット、これを単純に検索用のメモリアドレスと考えると、とんでもないサイズのメモリになります。
そこで考えられたのは、
・48ビット情報をもとにメモリとして妥当なサイズのアドレスを作りだし、それで検索する
というものでした。これをハッシュと呼んでいました。13ビットと書いたのは、このくらいだった気がするというもので、ちょっとずれがあるかもしれません。
このハッシュで使用している関数としては、パケットのエラーチェックなどでよく使うCRC32のロジックを流用しました。
ただこの場合、複数の異なる48ビットアドレスが同じ13ビットに集約されてしまう、という可能性が当然あるわけですね。だから、もし同じ13ビットになったとしても、1つだけでなく4つまでエントリーできるようにしました。これは、アドレス的には、下位に2ビット追加することで実現できますね。
ハッシュで48ビットが13ビットになったあと、
・13ビット+’b00
・13ビット+’b01
・13ビット+’b10
・13ビット+’b11
という感じで、同じ13ビットに属する4エントリーを検索できます。かかる時間(サイクル数)も、この範囲であればOKであることが分かりました。
ルーティングチップでの検索としては、
・宛先アドレス48ビットをもらったら、ハッシュで13ビットにする
・その13ビットアドレスに属するエントリ4つを検索して、有効な宛先ポート情報があるか確認して
・存在すればそのポート情報を返す、なければ(到着ポート以外の)全ポートつまりブロードキャスティングだという判断の情報を返す
という動きになります。
送り元アドレス情報は永遠に有効か?
ルーティングチップで管理する、アドレスと所属ポートのリストには、他の情報も必要になります。
まず、実用上の問題として、
ポートを差し替える可能性
があります。つまり、スイッチのポート1に繋がっていたパソコンを、なにかの理由でポート7に差し替えるかも、ということです。そうなると、ルーティングチップで管理している、[送信元アドレス – ポート] 情報が無意味になります。貯めた情報の期限は有限であると考えるべきです。
そのため、エントリーそのものが有効なものであるかどうか示す、Enableに相当するフラグbitが必要です。
古めの情報を随時無効化していく、という仕組みをつくるために、別途、Agingフラグbitを設置しました。具体的には:
1)新しいパケットが来たとき、その送信元アドレスと到着ポートをもとに新しいエントリを入れます。このとき [ enable, aging ] = [ 1, 1 ] です。
2)一定時間ごとにメモリを上から順にアクセスしてエントリを確認するロジックを作っておいて、
[ enable, aging ] = [ 1, 1 ] だったら、[ enable, aging ] = [ 1, 0 ] に変更する。
[ enable, aging ] = [ 1, 0 ] だったら、[ enable, aging ] = [ 0, 0 ] に変更する。
[ enable, aging ] = [ 0, 0 ] だったら、そのまま。
こんな感じの処理をすると、いずれ古いデータは disable になります。宛先検索する場合は、enable=0 のエントリは Hit の対象になりません。
もちろん、この aging 処理用のアクセスは、通常の検索処理が行われていない、メモリアクセスが暇なときに行われます。
最終製品のコストダウンは ASIC化 の重要な要素
当時の私は、製品のコストダウンのための努力っていうのはなんだかあまりカッコよくないイメージを持っていたというのが正直なところです。でも、製品分野を問わず、世の中に売り出す製品の、製品化においての努力の大半はこういうことなのでしょうね。
このプロジェクトにおいては、既存のチップセットのデザインがあり、MACチップはそのまま流用、ルーティングチップだけ改版するという形でした。その中で私は、上記のハッシュ含めた新しい仕組みの導入、検索および登録用のメモリアクセス関連のロジックを RTL 書いて検証していました。自分で書いたロジックを自分で検証するというのは、イマイチですが、設計と検証を分けるほどのリソースがなかったというのが現実ですね。