igb(4)を理解する為にデータシートを読む(RSSハッシュキーの取り出し)

まずはこのフローを見てもらうと分かりやすいのだけれど、FreeBSDのイーサーネットドライバでは割り込みハンドラ(em_irq_fast)からtaskqueue_enqueueを呼んでカーネルスレッドを起こして、このスレッドが実際にパケットを取り出しに行く(em_irq_fast)。

フロー図ではem(4)の関数名を使っているが、ここではigb(4)を見ていくのでem_irq_fast→igb_irq_fast、em_rxeof→igb_rxeofと読み替えて欲しい。

ソースコードこの辺りを参照

igb_rxeofが行っている事は、大雑把に言うと以下の通りである;

  • for (i = rxr->next_to_check; count != 0;)というループでRing上のパケットを一つづつ見に行く
  • mbufとして取り出す
  • 何パケットか繋ぐ
  • チェックサムオフロードの為にigb_rx_checksumを呼ぶ
  • igb_rx_inputへ渡す
    • TCPパケットならtcp_lro_rxを呼んでLRO処理を行う・その他のパケットなら(*ifp->if_input)(ifp, m)に渡す
      • 同一フローのパケットを一つのパケットにマージ
      • (*ifp->if_input)(ifp, m)に渡す

この流れの詳細はここでは省略する。

ここでは、どうやったらNICで計算したRSSハッシュ値が受け取れるのか知りたいので、mbufとして取り出す手前で

union e1000_adv_rx_desc *cur = &rxr->rx_base[i];

として取り出されているAdvanced Receive Descriptorの内容を見てみる。

igb(4)が対応するイーサネットコントローラの一つである82576EBのデータシートをダウンロードして見てみよう。

7.1.5章にAdvanced Receive Descriptorの構造が書いてある。
igb_rxeofで参照しているのはcur->wbとなっているし内容的にも7.1.5.2のWriteback formatの方だろう。
(Read formatがどこで使われているかはよくわからなかったので後で確認してみようと思う)

0-3bitのRSS TypeはどのRSS hash functionでhashしたかを示す値。
ドライバでは使われていないが(!)、取り出すとしたら

u16 pkt = le16toh(cur->wb.lower.lo_dword.hs_rss.pkt_info);
u8 rsstype = (u8)(pkt & E1000_RXDAVD_RSSTYPE_MASK);

といった所だろう。

32-63bitはRSS Hash Value/Fragment Checksum and IP identificationと書いてあるが、RSS有効の時はハッシュ値で無効の時はIP Identification/fragment checksumに使うらしい。
これもドライバで使われていないが、

u32 rss = le32toh(cur->wb.lower.hi_dword.rss);

で取り出せる。

RSSから脱線するけど、4-16bitのPacket Typeが面白くて、IPv4IPv6か、TCPUDPかだけでなくてNFSかどうかまでわかるらしい。