組込み

【ZynqMP】3. 2. PL EthernetでTCP/IP【調査編後半】

1.記事一覧

記事は複数回に分けて投稿する予定です。AMD/XilinxのARM SoC(ZynqMP Kria K26 SOM)で動作する、AMD/Xilinx公式認定Ubuntuやベアメタル開発を勉強していく覚書きです。

Zynq7000(armv7)版はこちら

2.PL側Etherが動くようになるまで【後半戦】

前半戦ではPL Ethernetからパケットが出てくるようになりました。しかし、DHCPサーバ(ルータ)配下のネットワークに接続してもDHCPが失敗してしまいます。

このときのネットワーク構成は以下のような感じです。

動くまでの流れ(前半と後半に記事が分かれてます)

調査の前半戦

  • 0.環境とシステム構成
  • 1.Echo Serverサンプルが動かない
  • 2.Wiresharkでパケットを見る。絶望的
  • 3.UARTログからLwIPのソースを追いかける
  • 4.LwIPのデバッグメッセージを有効化
  • 5.CMakeスクリプトを追いかける
  • 6.原因判明、パケットが出る
  • 調査の前半戦まとめ

調査の後半戦

  • 7.DHCPでコケる(後半戦開始)
  • 8.DHCPシーケンスのおさらいとパケットの中身を見る
  • 9.Wiresharkの落とし穴
  • 10.原因判明、DHCPとEcho Server無事動く
  • まとめ

2-7. DHCPでコケる(後半戦開始)

DHCPの失敗とはKR260からDHCPサーバへブロードキャストしたDHCP DISCOVERパケットをDHCPサーバが無視して、何度もリトライするという現象です。

もちろん、ネットワーク内にDHCPサーバ(ルータ)があり、機器を接続すればIPアドレスが割り振られますし、ルータへpingも通ります。ここで、一時期お手上げ状態になりかけました。

2-8. DHCPシーケンスのおさらいとパケットの中身を見る

ここで、DHCPについて再勉強することにしました。

DHCPのシーケンスは以下になります(条件:初期DHCPリースの場合)。

シーケンスから考えられる原因を挙げてみます。

  • DISCOVERパケットの中身に異常がある
  • DISCOVERパケットが経路途中にパケロス
  • DHCPサーバの設定に何らかの原因がある
  • OFFERパケットが経路途中にパケロス

DISCOVERパケットの中身か、DHCPサーバの設定に原因がありそうです。実はDHCPサーバは家庭用ルータではなく、ジャンクノートPCをレストアしたUbuntuPCで代用しているので、何かしら設定をミスった可能性があります。まずはDISCOVERパケットの中身を調べていきます。

DISCOVERパケットの中身を調べる

DISCOVERパケットはざっくりですが、こうなっているはず…

Ethernet層Dst:FF:FF:FF:FF:FF:FF(ブロードキャスト)
Src:00:0A:35:00:01:02(KR260)
インターネット層IPv4
Dst:255.255.255.255(制限ブロードキャスト)
Src:0.0.0.0
トランスポート層UDP
DstPort:67
SrcPort:68
アプリ層DHCP DISCOVER

実際に見てみましょう。一応上の表の通りで正しかったのですが、不穏なものを見つけました。

あれれ、IPv4とUDPのチェックサムおかしくないですか??? すべて’0’はさすがにありえないよね…

RFC791 1.4章(参考:https://www2s.biglobe.ne.jp/~hig/tcpip/ip.html)でIPv4ヘッダのチェックサムが不正の場合は直ちに破棄されなければならないとあります。UDPは高速化のため、0fillするとチェックサム検証が無効になるので、UDPはセーフです。

もし、IPv4のチェックサムが不正とすると、ルータのNICかTCP/IPスタックでパケット破棄されることになります。DHCPサーバサービスまで届きません。

2-9. Wiresharkの落とし穴

チェックサム破壊されているのにそもそもWiresharkが警告出さないのは不思議と思い、調べると、私が知らなかった事実がわかりました。

パケットデータからキャプチャされた環境を推測する手がかりを探す:東陽テクニカ

現在のPCのNICではIP/TCP/UDPのチェックサム計算をハードウェアオフロードする機能があり、Wiresharkでチェックサムの不正を誤検知してしまうことから、デフォルトで警告がOFFになったようです。

つまり、

  • キャプチャPCのNICのチェックサムオフロード機能をOFF
  • Wiresharkのチェックサム警告をON

の操作をしないと、本当にKR260のパケットのチェックサムが壊れているのかが完全にYesとは言いづらいわけですね。ただし、今回はPCに受信するパケットのみしか見てないので、結果は同じな気がしますが、、、とりあえずやってみましょう。

PCのチェックサムオフロードを無効化

キャプチャPC:Windows10
コントロールパネル>ネットワークとインターネット>ネットワーク接続を開く。キャプチャするNIC上で右クリック>プロパティ

“構成”を押す。

次の項目を無効にしてOKすると、NICが再起動する

  • IPv4 チェックサムオフロード
  • TCP チェックサムオフロード(IPv4)
  • UDP チェックサムオフロード(IPv4)

Wiresharkのチェックサム警告を有効化

編集>設定>Protocolを開き、以下の項目にチェックを入れる。

  • IPv4 : Validate the IPv4 checksum if possible
  • TCP : Validate the TCP checksum if possible
  • UDP : Validate the UDP checksum if possible

設定が出来たので、再度キャプチャしてみます。やはりチェックサムは不正でした。結構禍々しい色ですね。

2-10. 原因判明、DHCPとEcho Server無事動く

DHCP DISCOVERパケットをなぜDHCPサーバが無視するのかが判明しました。チェックサムの計算をLwIPが行っていないからです。

VitisのBSP設定のLwIPの項目に、ハードウェア(EtherMAC)にチェックサムオフロードするかの設定項目があります。デフォルトはOFFで今回はOFFのままのはずでした。

ちなみにチェックサムオフロードを有効にするにはMAC側が対応していないといけません。

この設定項目はCMakeスクリプトでCのヘッダファイルに変換されるはずです。そこを探すと、以下のファイルが見つかりました。

Path=<Platform Dir>/psu_cortexr5_0/freertos_psu_cortexr5_0/bsp/libsrc/lwip220/src/lwip220.cmake

チェックサムの設定処理を探すと、L.192にありました。

CMake
(...略)
## Checksum handling should be based on the MAC_INSTANCE variable
list(LENGTH MAC_INSTANCES _len)
if (${_len} GREATER 1)
    list(GET MAC_INSTANCES 0 MAC_INSTANCES)
endif()

if (${CONFIG_AXIETHERNET})
    if (MAC_INSTANCES IN_LIST AXIETHERNET_NUM_DRIVER_INSTANCES)
        if (${lwip220_temac_tcp_ip_tx_checksum_offload})
            if (${axieth_txcsum} EQUAL 0x2)
                set(CHECKSUM_GEN_TCP " ")
                set(CHECKSUM_GEN_UDP " ")
                set(CHECKSUM_GEN_IP " ")
                set(LWIP_FULL_CSUM_OFFLOAD_TX 1)
            else()
                message(FATAL_ERROR "Wrong Tx checksum options. The selected Tx checksum does not match with the HW supported Tx csum offload option")
            endif()
        endif()
        if (${lwip220_temac_tcp_ip_rx_checksum_offload})
            if (${axieth_rxcsum} EQUAL 0x2)
                set(CHECKSUM_CHECK_TCP " ")
                set(CHECKSUM_CHECK_UDP " ")
                set(CHECKSUM_CHECK_IP " ")
                set(LWIP_FULL_CSUM_OFFLOAD_RX 1)
            else()
                message(FATAL_ERROR "Wrong Rx checksum options. The selected Rx checksum does not match with the HW supported Rx csum offload option")
            endif()
        endif()
        if (${lwip220_temac_tcp_tx_checksum_offload})
            if (${axieth_txcsum} EQUAL 0x1)
                set(CHECKSUM_GEN_TCP " ")
                set(LWIP_PARTIAL_CSUM_OFFLOAD_TX 1)
            else()
                message(FATAL_ERROR "Wrong Tx checksum options. The selected Tx checksum does not match with the HW supported Tx csum offload option")
            endif()
        endif()
(...略)

L.195でCMakeキャッシュ変数MAC_INSTANCESに”psu_ethernet_0″が代入されてPSのGEM0向けの処理が走っていました。前半戦のApplicationコンポーネント側でもCMakeキャッシュ変数MAC_INSTANCESが出てきましたが、こちらはPlatformコンポーネントでビルド単位が違うらしく、スコープをまたぐことは無いようです。つまり、どうやらこちらのMAC_INSTANCESは別物で、これにも、再設定する必要がでてきそうです。

L.197にAXI-EtherMACを再設定する記述を追加します。

CMake
set(MAC_INSTANCES "axi_ethernet_0")

再ビルドして、もう一度Echo Serverサンプルを動かしてみます。

無事、DHCPによる、IPアドレス割当が完了しました。Echo Serverも動作するようになりました。

見にくいですが、水色がDHCP、黄色がARP、薄紫がEcho Serverになります。DHCPのシーケンスが2回行われているのは、Phyのリンクアップした後に再度ネゴシエーションし直していたためです。原因は現時点で不明ですが、いずれ調べておきたいと思います。

3.まとめ

前半戦でEtherからパケットが出るようになり、後半戦でチェックサムが正しく動作するようにできて、EchoServerが無事動作するようになりました。

様々なネット上の情報の力を借りてなんとかうまく行ったので、それを作成した方たちに感謝しつつ、ネットに情報発信するのは何かしらの形で誰かの助けになるのかなと改めて感じました。

ドライバの移植や改造が必要になるテーマだろうなと予想はしつつ、長期戦やリタイアを覚悟していました。しかし、蓋を開けてみたら、99%はほぼ動く状態でしたね。

そうは言いつつ、実際にやったことを細かく書いてみると、前半と後半に分けるほどになり、だいぶボリュームが大きくなってしまいました。ここまで読んでいただけた方は本当にお疲れ様です(いや本当に)。

この調査回は謎解き日記のような構成で書いています。WikiやQiitaやZennであるような、何かしらの困りごとや課題を解決するような目的の記事ではありません。仕事や趣味どちらでも良いのですが、開発で不具合が出たときに、ベテランエンジニアの方はどのようなことを考え、そしてアプローチをしながら解決へ導くのか。そのやり方について意外と参考になる情報が少なく、この記事の様なストーリー性のあるコンテンツが読みたいと思い書いてみました。実際私もエンジニアとしては若造で、今はまだまとまりのないものをだらだら書いているだけで、あくびが出そうな内容になってしまっていますが、今後少しずつ面白くしていけたらと思います。

ABOUT ME
sh-goto
低レイヤで遊んでいます
関連記事