1.記事一覧
記事は複数回に分けて投稿する予定です。AMD/XilinxのARM SoC(ZynqMP Kria K26 SOM)で動作する、AMD/Xilinx公式認定Ubuntuやベアメタル開発を勉強していく覚書きです。
ZynqMP(APU:Cortex-A53,Arm64) 組込みLinux入門編
- 【ZynqMP】1. 認定UbuntuでPLのGPIOを使う
- 【ZynqMP】2. 認定Ubuntuのカーネルビルド
- 【ZynqMP】3. 認定UbuntuのDeviceTree変更
- 【ZynqMP】4. 認定UbuntuでOpenAMPを試す【CR5Lockstep】
- 【ZynqMP】5. UARTでAMP【コア間通信】
- 【Linux】6. crash toolでカーネルメモリを見る
ZynqMP(RPU:Cortex-R5,Arm32) RPU入門編
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にありました。
(...略)
## 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を再設定する記述を追加します。
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であるような、何かしらの困りごとや課題を解決するような目的の記事ではありません。仕事や趣味どちらでも良いのですが、開発で不具合が出たときに、ベテランエンジニアの方はどのようなことを考え、そしてアプローチをしながら解決へ導くのか。そのやり方について意外と参考になる情報が少なく、この記事の様なストーリー性のあるコンテンツが読みたいと思い書いてみました。実際私もエンジニアとしては若造で、今はまだまとまりのないものをだらだら書いているだけで、あくびが出そうな内容になってしまっていますが、今後少しずつ面白くしていけたらと思います。