TCP bad checksum 問題

現象

Mona 上で起動した httpd (uIP) に外からブラウザでアクセスすると「リクエストがリセットされました」と出ることがある。頻度は数回に1回。
uIP のログには TCP bad checksum と出ている。

調査

  • パケットの同定をする必要があるので、uIP に手を入れて IP identifier を合わせて出力するように変更
  • IP identifier を手がかりに Wireshark でパケットをいくつか見る。
  • 全て HTTP GET で発生している。Mona がパケットを受信するとき。
  • ブラウザから送られる TCP/IP パケットが壊れていることは可能性が低いので Mona 側が悪いのだろう。
  • TCP checksum の計算方法を調査。
  • checksum のソースとなるもので怪しいのは、ペイロード(データそのもの)か。
  • bad checksum 時にパケットダンプするようにした。
  • 結果を Wireshark と比較。
  • パケット長が 14 byte 違う。そのほかにも HTTP のデータ部が違う。
  • 長さが疑わしいので virtio-net driver で長さを取り出す部分でログ出力。
  • Ether frame が522 byte あるはずなのに、54 byte と計算されている。これだ。
  • 54 byte 以降は、以前のパケットのゴミが入っていて何となくそれっぽい値になっているのだろうと推測。
  • パケットを眺めてみると 54 byte 境界で値がおかしくなっていることが確定。
  • 54 byte ってなんだろう? Wireshark 眺める。 TCP の ACK だ。

結論

virtio-net driver でパケット長を取得する部分でパケットのずれが生じている。
要修正。